From f3c76eb772d1d8e0fa9fc53f10ed8985334c75bf Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Wed, 25 Jan 2012 16:48:21 +0100 Subject: [PATCH] Make org-insert-drawer more user oriented * lisp/org.el (org-insert-property-drawer): Do not rely on `org-insert-drawer' since properties drawers are not meant for user's consumption. (org-insert-drawer): Insert drawer at point. If a region is provided, wrap the drawer around it instead. When offering completion, ignore internal drawers. Provide an error message when region contains an headline. --- lisp/org.el | 143 +++++++++++++++++++++++++++++++++++++--------------------- 1 files changed, 91 insertions(+), 52 deletions(-) diff --git a/lisp/org.el b/lisp/org.el index 1fa7259..cada815 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -14399,61 +14399,100 @@ formats in the current buffer." (defun org-insert-property-drawer () "Insert a property drawer into the current entry." (interactive) - (org-insert-drawer "PROPERTIES")) + (org-back-to-heading t) + (looking-at org-outline-regexp) + (let ((indent (if org-adapt-indentation + (- (match-end 0) (match-beginning 0)) + 0)) + (beg (point)) + (re (concat "^[ \t]*" org-keyword-time-regexp)) + end hiddenp) + (outline-next-heading) + (setq end (point)) + (goto-char beg) + (while (re-search-forward re end t)) + (setq hiddenp (outline-invisible-p)) + (end-of-line 1) + (and (equal (char-after) ?\n) (forward-char 1)) + (while (looking-at "^[ \t]*\\(:CLOCK:\\|:LOGBOOK:\\|CLOCK:\\|:END:\\)") + (if (member (match-string 1) '("CLOCK:" ":END:")) + ;; just skip this line + (beginning-of-line 2) + ;; Drawer start, find the end + (re-search-forward "^\\*+ \\|^[ \t]*:END:" nil t) + (beginning-of-line 1))) + (org-skip-over-state-notes) + (skip-chars-backward " \t\n\r") + (if (eq (char-before) ?*) (forward-char 1)) + (let ((inhibit-read-only t)) (insert "\n:PROPERTIES:\n:END:")) + (beginning-of-line 0) + (org-indent-to-column indent) + (beginning-of-line 2) + (org-indent-to-column indent) + (beginning-of-line 0) + (if hiddenp + (save-excursion + (org-back-to-heading t) + (hide-entry)) + (org-flag-drawer t)))) (defun org-insert-drawer (&optional drawer) - "Insert a drawer into the current entry." + "Insert a drawer at point. + +Optional argument DRAWER, when non-nil, is a string representing +drawer's name. Otherwise, the user is prompted for a name. + +If a region is active, insert the drawer around that region +instead. + +Point is left between drawer's boundaries." (interactive) - (if (org-region-active-p) - (let ((rbeg (region-beginning)) - (rend (region-end)) - (drawer (or drawer (completing-read "Drawer: " org-drawers)))) - (goto-char rbeg) - (insert ":" drawer ":\n") - (move-beginning-of-line 1) - (indent-for-tab-command) - (goto-char rend) - (move-end-of-line 1) - (insert "\n:END:") - (move-beginning-of-line 1) - (indent-for-tab-command)) - (org-back-to-heading t) - (looking-at org-outline-regexp) - (let ((indent (if org-adapt-indentation - (- (match-end 0) (match-beginning 0)) - 0)) - (beg (point)) - (re (concat "^[ \t]*" org-keyword-time-regexp)) - (drawer (or drawer (completing-read "Drawer: " org-drawers))) - end hiddenp) - (outline-next-heading) - (setq end (point)) - (goto-char beg) - (while (re-search-forward re end t)) - (setq hiddenp (outline-invisible-p)) - (end-of-line 1) - (and (equal (char-after) ?\n) (forward-char 1)) - (while (looking-at "^[ \t]*\\(:CLOCK:\\|:LOGBOOK:\\|CLOCK:\\|:END:\\)") - (if (member (match-string 1) '("CLOCK:" ":END:")) - ;; just skip this line - (beginning-of-line 2) - ;; Drawer start, find the end - (re-search-forward "^\\*+ \\|^[ \t]*:END:" nil t) - (beginning-of-line 1))) - (org-skip-over-state-notes) - (skip-chars-backward " \t\n\r") - (if (eq (char-before) ?*) (forward-char 1)) - (let ((inhibit-read-only t)) (insert "\n:" drawer ":\n:END:")) - (beginning-of-line 0) - (org-indent-to-column indent) - (beginning-of-line 2) - (org-indent-to-column indent) - (beginning-of-line 0) - (if hiddenp - (save-excursion - (org-back-to-heading t) - (hide-entry)) - (org-flag-drawer t))))) + (let* ((logbook (if (stringp org-log-into-drawer) org-log-into-drawer + "LOGBOOK")) + ;; SYSTEM-DRAWERS is a list of drawer names that are used + ;; internally by Org. They are meant to be inserted + ;; automatically. + (system-drawers `("CLOCK" ,logbook "PROPERTIES")) + ;; Remove system drawers from list. Note: For some reason, + ;; `org-completing-read' ignores the predicate while + ;; `completing-read' handles it fine. + (drawer (or drawer + (completing-read + "Drawer: " org-drawers + (lambda (d) (not (member d system-drawers))))))) + (if (not (org-region-active-p)) + ;; Insert a drawer at point. + (progn + (unless (bolp) (insert "\n")) + (insert (format ":%s:\n\n:END:\n" drawer)) + (forward-line -2)) + (let ((rbeg (region-beginning)) + (rend (copy-marker (region-end)))) + (unwind-protect + (progn + (goto-char rbeg) + (beginning-of-line) + (when (save-excursion + (re-search-forward org-outline-regexp-bol rend t)) + (error "Drawers cannot contain headlines")) + ;; Position point at the beginning of the first + ;; non-blank line in region. Insert drawer's opening + ;; there, then indent it. + (org-skip-whitespace) + (beginning-of-line) + (insert ":" drawer ":\n") + (forward-line -1) + (indent-for-tab-command) + ;; Move point to the beginning of the first blank line + ;; after the last non-blank line in region. Insert + ;; drawer's closing, then indent it. + (goto-char rend) + (skip-chars-backward " \r\t\n") + (insert "\n:END:") + (indent-for-tab-command) + (unless (eolp) (insert "\n"))) + ;; Clear marker, whatever the outcome of insertion is. + (set-marker rend nil)))))) (defvar org-property-set-functions-alist nil "Property set function alist. -- 1.7.8.4