(stackeffect )
2013-10-12: kanban-fill: a generalized version of kanban-zero and kanban-todo stackeffect kanban-fill: a generalized version of kanban-zero and kanban-todo
diff --git a/kanban.el b/kanban.el
--- a/kanban.el
+++ b/kanban.el
@@ -170,6 +170,30 @@ Gets the ROW and COLUMN via TBLFM ($# an
""
elem)))
+(defun kanban--normalize-whitespace (elem)
+"Return ELEM with sequences of spaces reduced to 1 space"
+(replace-regexp-in-string "\\W\\W+" " " elem))
+
+(defun kanban--member-of-table (elem &optional skipcol)
+"Check if ELEM is in some table field
+ignoring all elements of column SKIPCOL.
+
+If SKIPCOL is not set column 1 will be ignored."
+(if (org-at-table-p)
+ (let ((row 2)
+ (skipcol (or skipcol 1))
+ col result field)
+ (while (and (not result) (<= row (length org-table-dlines)))
+ (setq col (if (= 1 skipcol) 2 1))
+ (while (and (not result) (<= col org-table-current-ncol))
+ (setq field (org-table-get row col))
+ (if (and field elem)
+ (setq result (or result (equal (kanban--normalize-whitespace elem) (kanban--normalize-whitespace field)))))
+ (setq col (1+ col))
+ (if (= col skipcol) (setq col (1+ col))))
+ (setq row (1+ row)))
+ result)))
+
; Fill the first column with TODO items, except if they exist in other cels
;;;###autoload
(defun kanban-todo (row cels &optional match scope)
@@ -216,6 +240,51 @@ Gets the ROW and all other CELS via TBLF
elem))) ; otherwise use the element.
+(defun kanban-fill (&optional match scope)
+ "Kanban TODO item grabber. Fills the current row of the kanban
+table with org-mode TODO entries, if they are not in another cell
+of the table. This allows you to set the state manually and just
+use org-mode to supply new TODO entries.
+
+Can get a string as MATCH to select only entries with a matching tag, as well as a list of org-mode files as the SCOPE to search for tasks.
+
+Only not already present TODO states will be filled into empty
+fields starting from the current field. All fields above the current
+one are left untouched."
+ (let* ((ofc (org-table-get nil nil)) ; remember old field content
+ (row (org-table-current-dline))
+ (startrow row)
+ (col (org-table-current-column)) ; and current column
+ (srcfile (buffer-file-name))
+ (todo (kanban--get-todo-of-current-col))
+ (maxrow (length (delete nil org-table-dlines)))
+ (elems (delete nil (org-map-entries
+ '(kanban--todo-links-function srcfile)
+ ; select the TODO state via the matcher: just match the TODO.
+ (if match
+ (concat match "+TODO=\"" todo "\"")
+ (concat "+TODO=\"" todo "\""))
+ ; read all agenda files
+ (if scope
+ scope
+ 'agenda))))
+ (elem t))
+ (save-excursion
+ (while (and elem (<= row maxrow))
+ (setq elem (pop elems))
+ (while (and elem (kanban--member-of-table elem 0))
+ (setq elem (pop elems)))
+ (while (and elem (<= row maxrow) (not (equal "" (org-table-get row col))))
+ (if (= row maxrow)
+ (setq elem nil) ; stop search
+ (setq row (1+ row)))) ; skip non empty rows
+ (when (and elem (equal "" (org-table-get row col)))
+ (if (= row startrow) (setq ofc elem))
+ (save-excursion
+ (if (org-table-goto-line row)
+ (org-table-get-field col elem))))))
+ (org-table-goto-column col)
+ ofc))
;; An example for auto-updating kanban tables from duply.han
;; I use the double-dash to mark this as "private" function