diff options
author | Nicolas Goaziou <n.goaziou@gmail.com> | 2010-12-19 22:04:12 +0100 |
---|---|---|
committer | Nicolas Goaziou <n.goaziou@gmail.com> | 2011-02-18 12:45:07 +0100 |
commit | 8a3a81c08eec031d8636737024d652a4178cf317 (patch) | |
tree | 9f0b291141c0159b4cd2467129780f1b3d392c0c | |
parent | 7e57111524884effcde424446c22ef58dfb2de6b (diff) | |
download | org-mode-8a3a81c08eec031d8636737024d652a4178cf317.tar.gz |
org-list: fix checkboxes directly from list structures
* lisp/org-list.el (org-list-struct-fix-checkboxes): new function
(org-checkbox-blocked-p): removed function
-rw-r--r-- | lisp/org-list.el | 93 |
1 files changed, 66 insertions, 27 deletions
diff --git a/lisp/org-list.el b/lisp/org-list.el index 3d0514c..6a2f3ac 100644 --- a/lisp/org-list.el +++ b/lisp/org-list.el @@ -834,28 +834,6 @@ TOP is the position of list's top-item." "Is point at a line starting a plain-list item with a checklet?" (org-list-at-regexp-after-bullet-p "\\(\\[[- X]\\]\\)[ \t]+")) -(defun org-checkbox-blocked-p () - "Is the current checkbox blocked from for being checked now? -A checkbox is blocked if all of the following conditions are fulfilled: - -1. The checkbox is not checked already. -2. The current entry has the ORDERED property set. -3. There is an unchecked checkbox in this entry before the current line." - (catch 'exit - (save-match-data - (save-excursion - (unless (org-at-item-checkbox-p) (throw 'exit nil)) - (when (equal (match-string 1) "[X]") - ;; the box is already checked! - (throw 'exit nil)) - (let ((end (point-at-bol))) - (condition-case nil (org-back-to-heading t) - (error (throw 'exit nil))) - (unless (org-entry-get nil "ORDERED") (throw 'exit nil)) - (when (org-search-forward-unenclosed - "^[ \t]*[-+*0-9.)]+[ \t]+\\(\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[[- ]\\]" end t) - (org-current-line))))))) - ;;; Navigate ;; Every interactive navigation function is derived from a @@ -1336,15 +1314,13 @@ This function modifies STRUCT." ((string-match "[0-9]+" bullet) (replace-match "1" nil nil bullet)) (t bullet))))) - (set-bul (lambda (item bullet) - (setcdr item (list (nth 1 item) bullet (nth 3 item))))) (get-bul (lambda (item bullet) (let* ((counter (nth 3 item))) (if (and counter (string-match "[0-9]+" bullet)) (replace-match counter nil nil bullet) bullet)))) (fix-bul - (lambda (item) struct + (lambda (item) (let* ((parent (cdr (assq (car item) origins))) (orig-ref (assq parent acc))) (if orig-ref @@ -1382,11 +1358,70 @@ This function modifies STRUCT." (org-list-set-ind item struct top-ind)))))) (mapc new-ind (mapcar 'car (cdr struct))))) +(defun org-list-struct-fix-checkboxes (struct origins &optional ordered) + "Verify and correct checkboxes for every association in STRUCT. +ORIGINS is the alist of parents. See `org-list-struct-origins'. + +If ORDERED is non-nil, a checkbox can only be checked when every +checkbox before it is checked too. If there was an attempt to +break this rule, the function will return the blocking item. In +all others cases, the return value will be `nil'. + +To act reliably, this function requires the full structure of the +list, and not a part of it. It will modify STRUCT." + (let ((struct (cdr struct)) + (set-parent-box + (function + (lambda (item) + (let* ((box-list (mapcar (lambda (child) + (org-list-get-checkbox child struct)) + (org-list-get-all-children item origins)))) + (org-list-set-checkbox + item struct + (cond + ((and (member "[ ]" box-list) (member "[X]" box-list)) "[-]") + ((member "[-]" box-list) "[-]") + ((member "[X]" box-list) "[X]") + ((member "[ ]" box-list) "[ ]") + ;; parent has no boxed child: leave box as-is + (t (org-list-get-checkbox item struct)))))))) + parent-list) + ;; Start: get all parents with a checkbox + (mapc + (lambda (elt) + (let* ((parent (cdr elt)) + (parent-box-p (org-list-get-checkbox parent struct))) + (when (and parent-box-p (not (memq parent parent-list))) + (setq parent-list (cons parent parent-list))))) + origins) + ;; sort those parents by decreasing indentation + (setq parent-list (sort parent-list + (lambda (e1 e2) + (> (org-list-get-ind e1 struct) + (org-list-get-ind e2 struct))))) + ;; for each parent, get all children's checkboxes to determine and + ;; set its checkbox accordingly + (mapc set-parent-box parent-list) + ;; if ORDERED is set, see if we need to uncheck some boxes + (when ordered + (let* ((all-items (mapcar 'car struct)) + (box-list + (mapcar (lambda (e) (org-list-get-checkbox e struct)) all-items)) + (after-unchecked (member "[ ]" box-list))) + ;; there are boxes checked after an unchecked one: fix that + (when (member "[X]" after-unchecked) + (let ((index (- (length struct) (length after-unchecked)))) + (mapc (lambda (e) (org-list-set-checkbox e struct "[ ]")) + (nthcdr index all-items)) + ;; Verify once again the structure, without ORDERED + (org-list-struct-fix-checkboxes struct origins nil) + ;; return blocking item + (nth index all-items))))))) + (defun org-list-struct-fix-struct (struct origins) "Return STRUCT with correct bullets and indentation. ORIGINS is the alist of parents. See `org-list-struct-origins'. - -Only elements of STRUCT that have changed are returned." +\nOnly elements of STRUCT that have changed are returned." (let ((old (copy-alist struct))) (org-list-struct-fix-bul struct origins) (org-list-struct-fix-ind struct origins) @@ -1516,6 +1551,10 @@ Initial position is restored after the changes." (replace-match new-bul nil nil nil 1)) ;; 3. Replace checkbox (cond + ((and new-box + (save-match-data (org-at-item-description-p)) + (cdr (assq 'checkbox org-list-automatic-rules))) + (message "Cannot add a checkbox to a description list item")) ((equal (match-string 3) new-box)) ((and (match-string 3) new-box) (replace-match new-box nil nil nil 3)) |