>From c00c911f06ba059b61d8246f25e679f06a8f8491 Mon Sep 17 00:00:00 2001 From: Leo Vivier Date: Thu, 21 Feb 2019 00:16:27 +0100 Subject: [PATCH] Fix narrowed 1-line subtrees (squashed) * 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. (org-log-beginning): Ensure insertion in current restriction. (org-store-log-note): Ensure insertion in current restriction. * lisp/org-clock.el (org-clock-find-position): Ensure clock-drawer insertion in current restriction. (org-clock-in): Ensure 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 ----------------------------------------------------------------------- org-log-beginning: Fix drawer creation * lisp/org.el This commit ensures that the log-drawer for state-changes and notes is created within the current restriction. org-store-log-note: Fix drawer-less logging * lisp/org.el (org-log-beginning): --- lisp/org-clock.el | 14 ++++++++------ lisp/org.el | 27 +++++++++++++++------------ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/lisp/org-clock.el b/lisp/org-clock.el index b20158df6..5c9b0a1cf 100644 --- a/lisp/org-clock.el +++ b/lisp/org-clock.el @@ -1292,6 +1292,7 @@ the default behavior." (org-todo org-clock-in-switch-to-state))) (setq org-clock-heading (org-clock--mode-line-heading)) (org-clock-find-position org-clock-in-resume) + (forward-char -1) (cond ((and org-clock-in-resume (looking-at @@ -1315,8 +1316,8 @@ the default behavior." (sit-for 2) (throw 'abort nil)) (t - (insert-before-markers "\n") - (backward-char 1) + (insert "\n") + (org-indent-line) (org-indent-line) (when (and (save-excursion (end-of-line 0) @@ -1508,12 +1509,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 b8e378e73..27cd2bbd7 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) @@ -12950,7 +12950,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 @@ -13047,8 +13048,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 @@ -13117,12 +13118,13 @@ narrowing." ;; No drawer found. Create one, if permitted. (when create (unless (bolp) (insert "\n")) - (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)) - (end-of-line -1))))) + (line-end-position 0) (point) t 'org-hide-drawer)) + (end-of-line 0))))) (t (org-end-of-meta-data org-log-state-notes-insert-after-drawers) (skip-chars-forward " \t\n") @@ -13261,7 +13263,7 @@ EXTRA is additional text that will be inserted into the notes buffer." ;; Note associated to a clock is to be located right after ;; the clock. Do not move point. (unless (eq org-log-note-purpose 'clock-out) - (goto-char (org-log-beginning t))) + (goto-char (1- (org-log-beginning t)))) ;; Make sure point is at the beginning of an empty line. (cond ((not (bolp)) (let ((inhibit-read-only t)) (insert "\n"))) ((looking-at "[ \t]*\\S-") (save-excursion (insert "\n")))) @@ -13307,8 +13309,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) @@ -15223,7 +15225,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