From 471ddbd14e2bb3e7689cdca5e6a461e54b8be9d8 Mon Sep 17 00:00:00 2001 From: Bastien Guerry Date: Thu, 26 Jan 2012 09:18:10 +0100 Subject: [PATCH] Improve `org-insert-drawer' and related documentation. * org.el (org-insert-property-drawer): Not an interactive command anymore. (org-insert-drawer): With a prefix argument, insert a property drawer. Check for headline within the region before inserting the drawer. Don't include special drawers in the completion table. (org-mode-map): New keybinding `C-c C-x d' for `org-insert-drawer'. * org.texi (Drawers): How to insert/complete drawers. Thanks to Nicolas Goaziou for the discussion and the patch. --- doc/org.texi | 16 ++++-- lisp/org.el | 155 ++++++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 113 insertions(+), 58 deletions(-) diff --git a/doc/org.texi b/doc/org.texi index f216aa0b3..a285ccabb 100644 --- a/doc/org.texi +++ b/doc/org.texi @@ -1768,6 +1768,8 @@ numerically, alphabetically, by time, or by custom function. @cindex visibility cycling, drawers @vindex org-drawers +@cindex org-insert-drawer +@kindex C-c C-x d Sometimes you want to keep information associated with an entry, but you normally don't want to see it. For this, Org mode has @emph{drawers}. Drawers need to be configured with the variable @@ -1784,6 +1786,13 @@ look like this: After the drawer. @end example +You can interactively insert drawers at point by calling +@code{org-insert-drawer}, which is bound to @key{C-c C-x d}. With an active +region, this command will put the region inside the drawer. With a prefix +argument, this command calls @code{org-insert-property-drawer} and add a +property drawer right below the current headline. Completion over drawer +keywords is also possible using @key{M-TAB}. + Visibility cycling (@pxref{Visibility cycling}) on the headline will hide and show the entry, but keep the drawer collapsed to a single line. In order to look inside the drawer, you need to move the cursor to the drawer line and @@ -4894,8 +4903,8 @@ in the current file will be offered as possible completions. @orgcmd{C-c C-x p,org-set-property} Set a property. This prompts for a property name and a value. If necessary, the property drawer is created as well. -@item M-x org-insert-property-drawer -@findex org-insert-property-drawer +@item C-u M-x org-insert-drawer +@cindex org-insert-drawer Insert a property drawer into the current entry. The drawer will be inserted early in the entry, but after the lines with planning information like deadlines. @@ -15912,6 +15921,7 @@ If WHICH is nil or `all', get all properties. If WHICH is `special' or `standard', only get that subclass. @end defun @vindex org-use-property-inheritance +@findex org-insert-property-drawer @defun org-entry-get pom property &optional inherit Get value of PROPERTY for entry at point-or-marker POM. By default, this only looks at properties defined locally in the entry. If INHERIT @@ -15934,7 +15944,7 @@ Get all property keys in the current buffer. @end defun @defun org-insert-property-drawer -Insert a property drawer at point. +Insert a property drawer for the current entry. Also @end defun @defun org-entry-put-multivalued-property pom property &rest values diff --git a/lisp/org.el b/lisp/org.el index 1fa725907..94ff9f7f5 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -14398,62 +14398,106 @@ 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." - (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))))) +(defun org-insert-drawer (&optional arg drawer) + "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 "P") + (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 (if arg "PROPERTIES" + (or drawer + (completing-read + "Drawer: " org-drawers + (lambda (d) (not (member d system-drawers)))))))) + (cond + ;; With C-u, fall back on `org-insert-property-drawer' + (arg (org-insert-property-drawer)) + ;; With an active region, insert a drawer at point. + ((not (org-region-active-p)) + (progn + (unless (bolp) (insert "\n")) + (insert (format ":%s:\n\n:END:\n" drawer)) + (forward-line -2))) + ;; Otherwise, insert the drawer at point + (t + (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. @@ -17320,6 +17364,7 @@ BEG and END default to the buffer boundaries." (org-defkey org-mode-map "\C-c$" 'org-archive-subtree) (org-defkey org-mode-map "\C-c\C-x\C-s" 'org-advertized-archive-subtree) (org-defkey org-mode-map "\C-c\C-x\C-a" 'org-archive-subtree-default) +(org-defkey org-mode-map "\C-c\C-xd" 'org-insert-drawer) (org-defkey org-mode-map "\C-c\C-xa" 'org-toggle-archive-tag) (org-defkey org-mode-map "\C-c\C-xA" 'org-archive-to-archive-sibling) (org-defkey org-mode-map "\C-c\C-xb" 'org-tree-to-indirect-buffer) -- 2.11.4.GIT