Fix removal of shared drawers between clocks and notes

* lisp/org.el (org-log-note-marker): Remove variable.
(org-log-note-buffer): New variable.
(org-add-log-setup): Remove one argument.  Also use new variable.
(org-refile):
(org-todo):
(org-auto-repeat-maybe):
(org-deadline):
(org-schedule):
(org-add-note): Apply argument removal.
(org-store-log-note): Use new variable.  Compute the insertion's location
at the time the note is really inserted in the buffer.

* lisp/org-clock.el (org-clock-out): Apply argument removal.  Remove hack
  around shared drawers.

Reported-by: Olli P <kotkis@gmail.com>
<http://permalink.gmane.org/gmane.emacs.orgmode/103958>
This commit is contained in:
Nicolas Goaziou 2016-01-06 15:16:35 +01:00
parent c6ec704dce
commit aab46486f7
2 changed files with 110 additions and 135 deletions

View File

@ -1598,8 +1598,9 @@ to, overriding the existing value of `org-clock-out-switch-to-state'."
(move-marker org-clock-marker nil)
(move-marker org-clock-hd-marker nil)
(when org-log-note-clock-out
(org-add-log-setup 'clock-out nil nil nil nil
(concat "# Task: " (org-get-heading t) "\n\n")))
(org-add-log-setup
'clock-out nil nil nil
(concat "# Task: " (org-get-heading t) "\n\n")))
(when org-clock-mode-line-timer
(cancel-timer org-clock-mode-line-timer)
(setq org-clock-mode-line-timer nil))
@ -1629,18 +1630,7 @@ to, overriding the existing value of `org-clock-out-switch-to-state'."
(message (concat "Clock stopped at %s after "
(org-minutes-to-clocksum-string (+ (* 60 h) m)) "%s")
te (if remove " => LINE REMOVED" ""))
(let ((h org-clock-out-hook)
(clock-drawer (org-clock-into-drawer)))
;; If a closing note needs to be stored in the drawer
;; where clocks are stored, let's temporarily disable
;; `org-clock-remove-empty-clock-drawer'.
(if (and clock-drawer
(not (stringp clock-drawer))
(org-log-into-drawer)
(eq org-log-done 'note)
org-clock-out-when-done)
(setq h (delq 'org-clock-remove-empty-clock-drawer h)))
(mapc #'funcall h))
(run-hooks 'org-clock-out-hook)
(unless (org-clocking-p)
(setq org-clock-current-task nil)))))))

View File

@ -11935,7 +11935,7 @@ prefix argument (`C-u C-u C-u C-c C-w')."
(unless (bolp) (newline))
(org-paste-subtree level nil nil t)
(when org-log-refile
(org-add-log-setup 'refile nil nil 'findpos org-log-refile)
(org-add-log-setup 'refile nil nil org-log-refile)
(unless (eq org-log-refile 'note)
(save-excursion (org-add-log-note))))
(and org-auto-align-tags
@ -12651,10 +12651,10 @@ When called through ELisp, arg is also interpreted in the following way:
;; It is now done, and it was not done before
(org-add-planning-info 'closed (org-current-effective-time))
(when (and (not dolog) (eq 'note org-log-done))
(org-add-log-setup 'done org-state this 'findpos 'note)))
(org-add-log-setup 'done org-state this 'note)))
(when (and org-state dolog)
;; This is a non-nil state, and we need to log it
(org-add-log-setup 'state org-state this 'findpos dolog)))
(org-add-log-setup 'state org-state this dolog)))
;; Fixup tag positioning
(org-todo-trigger-tag-changes org-state)
(and org-auto-align-tags (not org-setting-tags) (org-set-tags nil t))
@ -13195,9 +13195,10 @@ This function is run automatically after each state change to a DONE state."
;; make sure we take a note, not only a time stamp
(setq org-log-note-how 'note))
;; Set up for taking a record
(org-add-log-setup 'state (or done-word (car org-done-keywords))
(org-add-log-setup 'state
(or done-word (car org-done-keywords))
org-last-state
'findpos org-log-repeat)))
org-log-repeat)))
(org-back-to-heading t)
(org-add-planning-info nil nil 'closed)
(setq re (concat "\\(" org-scheduled-time-regexp "\\)\\|\\("
@ -13298,8 +13299,7 @@ can either be an Org date like \"2011-07-24\" or a delta like \"+2d\"."
(cond
((equal arg '(4))
(when (and old-date org-log-redeadline)
(org-add-log-setup 'deldeadline nil old-date 'findpos
org-log-redeadline))
(org-add-log-setup 'deldeadline nil old-date org-log-redeadline))
(org-remove-timestamp-with-keyword org-deadline-string)
(message "Item no longer has a deadline."))
((equal arg '(16))
@ -13327,8 +13327,7 @@ can either be an Org date like \"2011-07-24\" or a delta like \"+2d\"."
org-log-redeadline
(not (equal old-date org-last-inserted-timestamp)))
(org-add-log-setup
'redeadline org-last-inserted-timestamp old-date 'findpos
org-log-redeadline))
'redeadline org-last-inserted-timestamp old-date org-log-redeadline))
(when repeater
(save-excursion
(org-back-to-heading t)
@ -13370,8 +13369,7 @@ either be an Org date like \"2011-07-24\" or a delta like \"+2d\"."
((equal arg '(4))
(progn
(when (and old-date org-log-reschedule)
(org-add-log-setup 'delschedule nil old-date 'findpos
org-log-reschedule))
(org-add-log-setup 'delschedule nil old-date org-log-reschedule))
(org-remove-timestamp-with-keyword org-scheduled-string)
(message "Item is no longer scheduled.")))
((equal arg '(16))
@ -13399,8 +13397,7 @@ either be an Org date like \"2011-07-24\" or a delta like \"+2d\"."
org-log-reschedule
(not (equal old-date org-last-inserted-timestamp)))
(org-add-log-setup
'reschedule org-last-inserted-timestamp old-date 'findpos
org-log-reschedule))
'reschedule org-last-inserted-timestamp old-date org-log-reschedule))
(when repeater
(save-excursion
(org-back-to-heading t)
@ -13564,7 +13561,7 @@ WHAT entry will also be removed."
(unless (eolp) (insert " "))
ts))))))
(defvar org-log-note-marker (make-marker))
(defvar org-log-note-buffer nil)
(defvar org-log-note-purpose nil)
(defvar org-log-note-state nil)
(defvar org-log-note-previous-state nil)
@ -13584,7 +13581,7 @@ The auto-repeater uses this.")
"Add a note to the current entry.
This is done in the same way as adding a state change note."
(interactive)
(org-add-log-setup 'note nil nil 'findpos nil))
(org-add-log-setup 'note))
(defun org-log-beginning (&optional create)
"Return expected start of log notes in current entry.
@ -13623,31 +13620,19 @@ narrowing."
(forward-line)))))
(if (bolp) (point) (line-beginning-position 2))))
(defun org-add-log-setup (&optional purpose state prev-state findpos how extra)
(defun org-add-log-setup (&optional purpose state prev-state how extra)
"Set up the post command hook to take a note.
If this is about to TODO state change, the new state is expected in STATE.
When FINDPOS is non-nil, find the correct position for the note in
the current entry. If not, assume that it can be inserted at point.
HOW is an indicator what kind of note should be created.
EXTRA is additional text that will be inserted into the notes buffer."
(org-with-wide-buffer
(when findpos
(goto-char (org-log-beginning t))
(unless org-log-states-order-reversed
(org-skip-over-state-notes)
(skip-chars-backward " \t\n\r")
(forward-line)))
(move-marker org-log-note-marker (point))
;; Preserve position even if a property drawer is inserted in the
;; process.
(set-marker-insertion-type org-log-note-marker t)
(setq org-log-note-purpose purpose
org-log-note-state state
org-log-note-previous-state prev-state
org-log-note-how how
org-log-note-extra extra
org-log-note-effective-time (org-current-effective-time))
(add-hook 'post-command-hook 'org-add-log-note 'append)))
(setq org-log-note-buffer (current-buffer)
org-log-note-purpose purpose
org-log-note-state state
org-log-note-previous-state prev-state
org-log-note-how how
org-log-note-extra extra
org-log-note-effective-time (org-current-effective-time))
(add-hook 'post-command-hook 'org-add-log-note 'append))
(defun org-skip-over-state-notes ()
"Skip past the list of State notes in an entry."
@ -13673,13 +13658,12 @@ EXTRA is additional text that will be inserted into the notes buffer."
(org-list-get-item-end (point) struct)))))))
(defun org-add-log-note (&optional purpose)
"Pop up a window for taking a note, and add this note later at point."
"Pop up a window for taking a note, and add this note later."
(remove-hook 'post-command-hook 'org-add-log-note)
(setq org-log-note-window-configuration (current-window-configuration))
(delete-other-windows)
(move-marker org-log-note-return-to (point))
(org-pop-to-buffer-same-window (marker-buffer org-log-note-marker))
(goto-char org-log-note-marker)
(org-pop-to-buffer-same-window org-log-note-buffer)
(org-switch-to-buffer-other-window "*Org Note*")
(erase-buffer)
(if (memq org-log-note-how '(time state))
@ -13714,93 +13698,94 @@ EXTRA is additional text that will be inserted into the notes buffer."
(defvar org-note-abort nil) ; dynamically scoped
(defun org-store-log-note ()
"Finish taking a log note, and insert it to where it belongs."
(let ((txt (buffer-string)))
(kill-buffer (current-buffer))
(let ((note (cdr (assq org-log-note-purpose org-log-note-headings))) lines)
(while (string-match "\\`# .*\n[ \t\n]*" txt)
(setq txt (replace-match "" t t txt)))
(when (string-match "\\s-+\\'" txt)
(setq txt (replace-match "" t t txt)))
(setq lines (org-split-string txt "\n"))
(when (and note (string-match "\\S-" note))
(setq note
(org-replace-escapes
note
(list (cons "%u" (user-login-name))
(cons "%U" user-full-name)
(cons "%t" (format-time-string
(org-time-stamp-format 'long 'inactive)
org-log-note-effective-time))
(cons "%T" (format-time-string
(org-time-stamp-format 'long nil)
org-log-note-effective-time))
(cons "%d" (format-time-string
(org-time-stamp-format nil 'inactive)
org-log-note-effective-time))
(cons "%D" (format-time-string
(org-time-stamp-format nil nil)
org-log-note-effective-time))
(cons "%s" (cond
((not org-log-note-state) "")
((org-string-match-p org-ts-regexp
org-log-note-state)
(format "\"[%s]\""
(substring org-log-note-state 1 -1)))
(t (format "\"%s\"" org-log-note-state))))
(cons "%S"
(cond
((not org-log-note-previous-state) "")
((org-string-match-p org-ts-regexp
org-log-note-previous-state)
(format "\"[%s]\""
(substring
org-log-note-previous-state 1 -1)))
(t (format "\"%s\""
org-log-note-previous-state)))))))
(when lines (setq note (concat note " \\\\")))
(push note lines))
(when (or current-prefix-arg org-note-abort)
(when (org-log-into-drawer)
(org-remove-empty-drawer-at org-log-note-marker))
(setq lines nil))
(when lines
(with-current-buffer (marker-buffer org-log-note-marker)
(org-with-wide-buffer
(goto-char org-log-note-marker)
(move-marker org-log-note-marker nil)
;; 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"))))
;; In an existing list, add a new item at the top level.
;; Otherwise, indent line like a regular one.
(let ((itemp (org-in-item-p)))
(if itemp
(org-indent-line-to
(let ((struct (save-excursion
(goto-char itemp) (org-list-struct))))
(org-list-get-ind (org-list-get-top-point struct) struct)))
(org-indent-line)))
(insert (org-list-bullet-string "-") (pop lines))
(let ((ind (org-list-item-body-column (line-beginning-position))))
(dolist (line lines)
(insert "\n")
(org-indent-line-to ind)
(insert line)))
(message "Note stored")
(org-back-to-heading t)
(org-cycle-hide-drawers 'children))
;; Fix `buffer-undo-list' when `org-store-log-note' is called
;; from within `org-add-log-note' because `buffer-undo-list'
;; is then modified outside of `org-with-remote-undo'.
(when (eq this-command 'org-agenda-todo)
(setcdr buffer-undo-list (cddr buffer-undo-list)))))))
;; Don't add undo information when called from `org-agenda-todo'
(let ((txt (prog1 (buffer-string)
(kill-buffer)))
(note (cdr (assq org-log-note-purpose org-log-note-headings)))
lines)
(while (string-match "\\`# .*\n[ \t\n]*" txt)
(setq txt (replace-match "" t t txt)))
(when (string-match "\\s-+\\'" txt)
(setq txt (replace-match "" t t txt)))
(setq lines (org-split-string txt "\n"))
(when (org-string-nw-p note)
(setq note
(org-replace-escapes
note
(list (cons "%u" (user-login-name))
(cons "%U" user-full-name)
(cons "%t" (format-time-string
(org-time-stamp-format 'long 'inactive)
org-log-note-effective-time))
(cons "%T" (format-time-string
(org-time-stamp-format 'long nil)
org-log-note-effective-time))
(cons "%d" (format-time-string
(org-time-stamp-format nil 'inactive)
org-log-note-effective-time))
(cons "%D" (format-time-string
(org-time-stamp-format nil nil)
org-log-note-effective-time))
(cons "%s" (cond
((not org-log-note-state) "")
((org-string-match-p org-ts-regexp
org-log-note-state)
(format "\"[%s]\""
(substring org-log-note-state 1 -1)))
(t (format "\"%s\"" org-log-note-state))))
(cons "%S"
(cond
((not org-log-note-previous-state) "")
((org-string-match-p org-ts-regexp
org-log-note-previous-state)
(format "\"[%s]\""
(substring
org-log-note-previous-state 1 -1)))
(t (format "\"%s\""
org-log-note-previous-state)))))))
(when lines (setq note (concat note " \\\\")))
(push note lines))
(when (and lines (not (or current-prefix-arg org-note-abort)))
(with-current-buffer org-log-note-buffer
(org-with-wide-buffer
;; Find location for the new note.
(goto-char (org-log-beginning t))
(unless org-log-states-order-reversed
(org-skip-over-state-notes)
(skip-chars-backward " \t\n\r")
(forward-line))
;; 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"))))
;; In an existing list, add a new item at the top level.
;; Otherwise, indent line like a regular one.
(let ((itemp (org-in-item-p)))
(if itemp
(org-indent-line-to
(let ((struct (save-excursion
(goto-char itemp) (org-list-struct))))
(org-list-get-ind (org-list-get-top-point struct) struct)))
(org-indent-line)))
(insert (org-list-bullet-string "-") (pop lines))
(let ((ind (org-list-item-body-column (line-beginning-position))))
(dolist (line lines)
(insert "\n")
(org-indent-line-to ind)
(insert line)))
(message "Note stored")
(org-back-to-heading t)
(org-cycle-hide-drawers 'children))
;; Fix `buffer-undo-list' when `org-store-log-note' is called
;; from within `org-add-log-note' because `buffer-undo-list'
;; is then modified outside of `org-with-remote-undo'.
(when (eq this-command 'org-agenda-todo)
(setcdr buffer-undo-list (cddr buffer-undo-list))))))
;; Don't add undo information when called from `org-agenda-todo'.
(let ((buffer-undo-list (eq this-command 'org-agenda-todo)))
(set-window-configuration org-log-note-window-configuration)
(with-current-buffer (marker-buffer org-log-note-return-to)
(goto-char org-log-note-return-to))
(move-marker org-log-note-return-to nil)
(and org-log-post-message (message "%s" org-log-post-message))))
(when org-log-post-message (message "%s" org-log-post-message))))
(defun org-remove-empty-drawer-at (pos)
"Remove an empty drawer at position POS.