emacs-orgmode
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [O] How do I create a drawer?


From: Nicolas Goaziou
Subject: Re: [O] How do I create a drawer?
Date: Wed, 25 Jan 2012 17:33:22 +0100

Hello,

Bastien <address@hidden> writes:

> The version I just pushed does not handle this kind of problem.
> If you think it's worth the trouble, can you have a look at it?

I've checked the code, and the `org-insert-drawer' is actually not what
I had in mind.

To me, there are really two types of drawers: system drawers and user's
drawers (which I'll simply call "drawers" from now).  System drawers
usually go just below the current headline (which is mandatory) and are
inserted automatically by some Org mechanism. Drawers can go anywhere,
even before the first headline, and are usually inserted manually.

Being interactive, `org-insert-drawer' is clearly user-oriented. An user
calling this function will probably want to insert a drawer at point (if
not around region), much less likely to insert a system drawer manually.

Thus, that function shouldn't be used for `org-insert-property-drawer'
internals, which needs to move point back to the headline.

Therefore, I suggest the following draft of a patch, that mostly reverts
commit splitting `org-insert-property-drawer' and makes
`org-insert-drawer' more user friendly. It provides the following
facilities:

  - headline inclusion check,
  - drawer insertion without requiring an headline above,
  - skip trailing blank lines (i.e. to wrap buffer around a just marked
    paragraph),
  - Ignore system drawer's names in completion list.

What do you think?


Regards,

-- 
Nicolas Goaziou
>From f3c76eb772d1d8e0fa9fc53f10ed8985334c75bf Mon Sep 17 00:00:00 2001
From: Nicolas Goaziou <address@hidden>
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


reply via email to

[Prev in Thread] Current Thread [Next in Thread]