From mboxrd@z Thu Jan 1 00:00:00 1970 From: Nicolas Goaziou Subject: Re: How do I create a drawer? Date: Wed, 25 Jan 2012 17:33:22 +0100 Message-ID: <87vcnzeo8d.fsf@gmail.com> References: <30687.1327452372@alphaville> <8739b4p30t.fsf@gnu.org> <874nvjgbbn.fsf@gmail.com> <87zkdbeuji.fsf@gmail.com> <878vkvg8m5.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Return-path: Received: from eggs.gnu.org ([140.186.70.92]:38357) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rq5ow-0001sb-NE for emacs-orgmode@gnu.org; Wed, 25 Jan 2012 11:35:43 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Rq5om-0000Dm-Bk for emacs-orgmode@gnu.org; Wed, 25 Jan 2012 11:35:38 -0500 Received: from mail-bk0-f41.google.com ([209.85.214.41]:64043) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rq5om-0000DH-1x for emacs-orgmode@gnu.org; Wed, 25 Jan 2012 11:35:28 -0500 Received: by bkbzx1 with SMTP id zx1so5168712bkb.0 for ; Wed, 25 Jan 2012 08:35:27 -0800 (PST) In-Reply-To: <878vkvg8m5.fsf@gnu.org> (Bastien's message of "Wed, 25 Jan 2012 15:27:46 +0100") List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org To: Bastien Cc: nicholas.dokos@hp.com, emacs-orgmode@gnu.org, Carsten Dominik --=-=-= Content-Type: text/plain Hello, Bastien 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 --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Make-org-insert-drawer-more-user-oriented.patch Content-Description: insert drawer patch >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 --=-=-=--