Browse Source

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.
Bastien Guerry 14 years ago
parent
commit
471ddbd14e
2 changed files with 113 additions and 58 deletions
  1. 13 3
      doc/org.texi
  2. 100 55
      lisp/org.el

+ 13 - 3
doc/org.texi

@@ -1768,6 +1768,8 @@ numerically, alphabetically, by time, or by custom function.
 @cindex visibility cycling, drawers
 @cindex visibility cycling, drawers
 
 
 @vindex org-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
 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}.
 normally don't want to see it.  For this, Org mode has @emph{drawers}.
 Drawers need to be configured with the variable
 Drawers need to be configured with the variable
@@ -1784,6 +1786,13 @@ look like this:
    After the drawer.
    After the drawer.
 @end example
 @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
 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
 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
 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}
 @orgcmd{C-c C-x p,org-set-property}
 Set a property.  This prompts for a property name and a value.  If
 Set a property.  This prompts for a property name and a value.  If
 necessary, the property drawer is created as well.
 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
 Insert a property drawer into the current entry.  The drawer will be
 inserted early in the entry, but after the lines with planning
 inserted early in the entry, but after the lines with planning
 information like deadlines.
 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.
 `special' or `standard', only get that subclass.
 @end defun
 @end defun
 @vindex org-use-property-inheritance
 @vindex org-use-property-inheritance
+@findex org-insert-property-drawer
 @defun org-entry-get pom property &optional inherit
 @defun org-entry-get pom property &optional inherit
 Get value of PROPERTY for entry at point-or-marker POM.  By default,
 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
 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
 @end defun
 
 
 @defun org-insert-property-drawer
 @defun org-insert-property-drawer
-Insert a property drawer at point.
+Insert a property drawer for the current entry.  Also
 @end defun
 @end defun
 
 
 @defun org-entry-put-multivalued-property pom property &rest values
 @defun org-entry-put-multivalued-property pom property &rest values

+ 100 - 55
lisp/org.el

@@ -14398,62 +14398,106 @@ formats in the current buffer."
 
 
 (defun org-insert-property-drawer ()
 (defun org-insert-property-drawer ()
   "Insert a property drawer into the current entry."
   "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
 (defvar org-property-set-functions-alist nil
   "Property set function alist.
   "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$"    '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-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-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-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-xA" 'org-archive-to-archive-sibling)
 (org-defkey org-mode-map "\C-c\C-xb" 'org-tree-to-indirect-buffer)
 (org-defkey org-mode-map "\C-c\C-xb" 'org-tree-to-indirect-buffer)