emacs-orgmode
[Top][All Lists]
Advanced

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

[O] [PATCH] Fix narrowed 1-line subtrees


From: Leo Vivier
Subject: [O] [PATCH] Fix narrowed 1-line subtrees
Date: Thu, 21 Feb 2019 16:38:17 +0100

* lisp/org.el (org-add-planning-info): Ensure insertion in current
  restriction.
  (org-remove-timestamp-with-keyword): Respect ambiguous newline when
  narrowed to 1-line-subtree.
  (org-remove-empty-drawer-at): Respect ambiguous newline when
  narrowed to 1-line subtree.
  (org-entry-delete): Respect ambiguous newline when narrowed to
  1-line subtree.

* lisp/org-clock.el (org-clock-find-position): Ensure clock-drawer
  insertion in current restriction.

This patch addresses multiple issues occuring when running commands on
a 1-line subtree when the buffer is narrowed to it.  A 1-line subtree
is a subtree only containing a heading and a newline at the end.

Typical problem:
-----------------------------------------------------------------------
* Tree 1
:PROPERTIES:
:TEST: t
:END:
* Tree 2
-----------------------------------------------------------------------
With point on `Tree 1', run the following:
(progn
  (org-narrow-to-subtree)
  (org-delete-property "TEST")
  (org-back-to-heading)
  (end-of-line)
  (delete-char 1)
  (widen))

Result:
-----------------------------------------------------------------------
* Tree 1* Tree 2
-----------------------------------------------------------------------

Observation:
The newline between the two headings has been removed despite the fact
that it wasn't in the buffer restriction.

The problem is due to two things:
- The way that narrowing works in Emacs, notably how restrictions are
  restored after `save-restriction'.
- The ambiguous newline between the end of a 1-line subtree and a
  following subtree.

The solution is to stop the problematic commands from interacting with
the ambiguous newline in order to preserve the narrowed region's
`point-max'.  This is done by inserting or removing newlines from
the top of a heading rather than its bottom.

Visually, instead of deleting the following bracketed region...
-----------------------------------------------------------------------
* Tree 1
{:PROPERTIES:
:TEST: t
:END:
}* Tree 2
-----------------------------------------------------------------------

We delete the following one:
-----------------------------------------------------------------------
* Tree 1{
:PROPERTIES:
:TEST: t
:END:}
* Tree 2
-----------------------------------------------------------------------
---
Please see my reply to this message for a detailed account of the
problem and the solution.

 lisp/org-clock.el |  9 +++++----
 lisp/org.el       | 16 +++++++++-------
 2 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/lisp/org-clock.el b/lisp/org-clock.el
index b20158df6..5624af32a 100644
--- a/lisp/org-clock.el
+++ b/lisp/org-clock.el
@@ -1508,12 +1508,13 @@ line and position cursor in that line."
          (when (and org-clock-into-drawer
                     (or (not (wholenump org-clock-into-drawer))
                         (< org-clock-into-drawer 2)))
-           (let ((beg (point)))
-             (insert ":" drawer ":\n:END:\n")
+           (let ((beg (1- (point))))
+             (forward-char -1)
+             (insert "\n:" drawer ":\n:END:")
              (org-indent-region beg (point))
              (org-flag-region
-              (line-end-position -1) (1- (point)) t 'org-hide-drawer)
-             (forward-line -1))))
+              (line-end-position 0) (point) t 'org-hide-drawer)
+             (beginning-of-line))))
         ;; When a clock drawer needs to be created because of the
         ;; number of clock items or simply if it is missing, collect
         ;; all clocks in the section and wrap them within the drawer.
diff --git a/lisp/org.el b/lisp/org.el
index ef6e40ca9..ae9494672 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -12937,7 +12937,7 @@ nil."
   "Remove all time stamps with KEYWORD in the current entry."
   (let ((re (concat "\\<" (regexp-quote keyword) " +<[^>\n]+>[ \t]*"))
        beg)
-    (save-excursion
+    (org-with-wide-buffer
       (org-back-to-heading t)
       (setq beg (point))
       (outline-next-heading)
@@ -12949,7 +12949,8 @@ nil."
          (when (string-match "^[ \t]*$" (buffer-substring
                                          (point-at-bol) (point-at-eol)))
            (delete-region (point-at-bol)
-                          (min (point-max) (1+ (point-at-eol))))))))))
+                          (point-at-eol)
+                          (delete-char -1))))))))
 
 (defvar org-time-was-given) ; dynamically scoped parameter
 (defvar org-end-time-was-given) ; dynamically scoped parameter
@@ -13046,8 +13047,8 @@ WHAT entry will also be removed."
                    (unless (= (skip-chars-backward " \t" p) 0)
                      (delete-region (point) (line-end-position)))))))
             ((not what) (throw 'exit nil)) ; Nothing to do.
-            (t (insert-before-markers "\n")
-               (backward-char 1)
+            (t (backward-char 1)
+               (insert "\n")
                (when org-adapt-indentation
                  (indent-to-column (1+ (org-outline-level))))))
        (when what
@@ -13306,8 +13307,8 @@ POS may also be a marker."
         (delete-region (org-element-property :begin drawer)
                        (progn (goto-char (org-element-property :end drawer))
                               (skip-chars-backward " \r\t\n")
-                              (forward-line)
-                              (point))))))))
+                              (point)))
+        (delete-char -1))))))
 
 (defvar org-ts-type nil)
 (defun org-sparse-tree (&optional arg type)
@@ -15222,7 +15223,8 @@ non-nil when a property was removed."
         ;; If drawer is empty, remove it altogether.
         (when (= begin end)
           (delete-region (line-beginning-position 0)
-                         (line-beginning-position 2)))
+                         (point-at-eol))
+          (delete-char -1))
         ;; Return non-nil if some property was removed.
         (prog1 (/= end origin) (set-marker end nil))))
       (_ nil))))
-- 
2.20.1




reply via email to

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