emacs-orgmode
[Top][All Lists]
Advanced

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

[O] [PATCH 1/2] Fix narrowing for 1-line subtrees


From: Leo Vivier
Subject: [O] [PATCH 1/2] Fix narrowing for 1-line subtrees
Date: Mon, 18 Feb 2019 01:25:46 +0100

* lisp/org.el (org-narrow-to-subtree): Ensure newline at end of
  subtree.
  (org-tree-to-indirect-buffer): Ensure newline at end of
  subtree.
  (org-widen): Create wrapper for `widen' to handle end newline.

* lisp/org-capture.el (org-capture-finalize): Replace `widen' with
  `org-widen'.
  (org-capture-narrow): Ensure newline at end of subtree.

* lisp/org-keys.el (org-remap): Remap `widen' to `org-widen'.

There was a problem with narrowed 1-line subtrees which caused
clocking and scheduling commands to print their modifications outside
of the current narrowing, e.g. `org-clock-in'. This also prevented
some commands from working as expected,
e.g. `org-clock-out-when-done', since the clock-drawer isn't visible.

Previous commits have addressed this problem by patching those
commands to act on a widened buffer within a `save-restriction'
environment (cf. 8fc22d464, 503ede74b, and 6872088c7) but this does
not address the original problem, namely the modifications not being
visible in the narrowed buffer.

The problem is inherent to Emacs's narrowing.  In org-mode, the
narrowing commands use `org-end-of-subtree' to retrieve the
end-position of the region to be narrowed.  However, with a 1-line
subtree, `org-end-of-subtree' moves the point to the end of the line
which is before the position where clocking and scheduling commands
print their modifications, i.e. right below the headline.

To address the problem, we need to change the way we narrow and widen
buffers in org-mode:
- We patch the narrowing commands in org-mode to always add a newline
  at the end of subtrees (not only the 1-line subtrees).  This ensures
  that clocking and scheduling commands print their modifications
  within the narrowed buffer.
- We create a wrapper for `widen' within org-mode (called `org-widen')
  which deletes the newline added when we narrowed the buffer to the
  subtree.

However, for this solution to be complete, we need to ensure that the
newlines added by the narrowing commands cannot be deleted by the
user.
---
This is an implementation of the solution I've discussed in 'Bug:
org-clock commands spawn drawer outside of narrowing' on Fri, 15 Feb
2019 09:48:00 +0100.

I've tried it with `emacs -q' and with different numbers of
blank-lines between headings, and  I haven't encountered any problem so
far.  The code doesn't make any assumption about how many lines you
should have between your headings, which means that it shouldn't
interfere with `org-blank-before-new-entry'.

If there are more idiomatic ways to write some of the functions,
please let me know.

Thank you.

 lisp/org-capture.el | 12 +++++++++---
 lisp/org-keys.el    |  1 +
 lisp/org.el         | 26 +++++++++++++++++++++-----
 3 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/lisp/org-capture.el b/lisp/org-capture.el
index debf1808c..ff3134fb4 100644
--- a/lisp/org-capture.el
+++ b/lisp/org-capture.el
@@ -746,7 +746,7 @@ captured item after finalizing."
   (let ((abort-note nil))
     ;; Store the size of the capture buffer
     (org-capture-put :captured-entry-size (- (point-max) (point-min)))
-    (widen)
+    (org-widen)
     ;; Store the insertion point in the target buffer
     (org-capture-put :insertion-point (point))
 
@@ -1416,8 +1416,14 @@ Of course, if exact position has been required, just put 
it there."
 (defun org-capture-narrow (beg end)
   "Narrow, unless configuration says not to narrow."
   (unless (org-capture-get :unnarrowed)
-    (narrow-to-region beg end)
-    (goto-char beg)))
+    (goto-char beg)
+    (narrow-to-region
+     beg
+     (progn (org-end-of-subtree t t)
+            (when (and (org-at-heading-p) (not (eobp)))
+              (backward-char 1)
+              (insert "\n"))
+            (point)))))
 
 (defun org-capture-empty-lines-before (&optional n)
   "Set the correct number of empty lines before the insertion point.
diff --git a/lisp/org-keys.el b/lisp/org-keys.el
index d103957a9..90e8139b0 100644
--- a/lisp/org-keys.el
+++ b/lisp/org-keys.el
@@ -532,6 +532,7 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command 
names."
           'delete-char            'org-delete-char
           'delete-backward-char   'org-delete-backward-char
           'kill-line              'org-kill-line
+          'widen                  'org-widen
           'open-line              'org-open-line
           'yank                   'org-yank
           'comment-dwim           'org-comment-dwim
diff --git a/lisp/org.el b/lisp/org.el
index ebec2befa..3110f14ba 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -7391,7 +7391,9 @@ frame is not changed."
       (setq beg (point)
            heading (org-get-heading 'no-tags))
       (org-end-of-subtree t t)
-      (when (org-at-heading-p) (backward-char 1))
+      (when (and (org-at-heading-p) (not (eobp)))
+              (backward-char 1)
+              (insert "\n"))
       (setq end (point)))
     (when (and (buffer-live-p org-last-indirect-buffer)
               (not (eq org-indirect-buffer-display 'new-frame))
@@ -8381,16 +8383,21 @@ If yes, remember the marker and the distance to BEG."
     (move-marker (car x) (+ beg (cdr x))))
   (setq org-markers-to-move nil))
 
-(defun org-narrow-to-subtree ()
-  "Narrow buffer to the current subtree."
-  (interactive)
+(defun org-narrow-to-subtree (&optional newline)
+  "Narrow buffer to the current subtree.
+
+When called interactively, ensures that there’s a newline at the
+end of the narrowed tree."
+  (interactive "p")
   (save-excursion
     (save-match-data
       (org-with-limited-levels
        (narrow-to-region
        (progn (org-back-to-heading t) (point))
        (progn (org-end-of-subtree t t)
-              (when (and (org-at-heading-p) (not (eobp))) (backward-char 1))
+              (when (and (org-at-heading-p) (not (eobp)))
+                 (backward-char 1)
+                 (when newline (insert "\n")))
               (point)))))))
 
 (defun org-toggle-narrow-to-subtree ()
@@ -8410,6 +8417,15 @@ If yes, remember the marker and the distance to BEG."
        (narrow-to-region (car blockp) (cdr blockp))
       (user-error "Not in a block"))))
 
+(defun org-widen ()
+  "Widen buffer."
+  (interactive)
+  (save-excursion
+    (goto-char (point-max))
+    (when (string-match-p "^\\s-*$" (thing-at-point 'line))
+      (delete-char -1)))
+  (widen))
+
 (defun org-clone-subtree-with-time-shift (n &optional shift)
   "Clone the task (subtree) at point N times.
 The clones will be inserted as siblings.
-- 
2.20.1




reply via email to

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