From mboxrd@z Thu Jan 1 00:00:00 1970 From: Cody Goodman Subject: Re: org-capture with :prepend t breaks :clock-resume functionality in 9.1.9 Date: Fri, 25 Oct 2019 19:01:22 -0500 Message-ID: References: Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="00000000000031cf000595c4f8d5" Return-path: Received: from eggs.gnu.org ([2001:470:142:3::10]:52344) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iO9WT-00029B-HB for emacs-orgmode@gnu.org; Fri, 25 Oct 2019 20:01:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iO9WR-0006FG-3y for emacs-orgmode@gnu.org; Fri, 25 Oct 2019 20:01:37 -0400 Received: from mail-qt1-x82f.google.com ([2607:f8b0:4864:20::82f]:45396) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iO9WQ-0006F8-Uu for emacs-orgmode@gnu.org; Fri, 25 Oct 2019 20:01:35 -0400 Received: by mail-qt1-x82f.google.com with SMTP id c21so5819656qtj.12 for ; Fri, 25 Oct 2019 17:01:34 -0700 (PDT) In-Reply-To: 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" To: emacs-orgmode@gnu.org --00000000000031cf000595c4f8d5 Content-Type: text/plain; charset="UTF-8" A little different solution that takes advantage of the fact that adding a newline preserves the clock in the narrowed buffer. Maybe the right thing to do is to widen/re-narrow buffer to include the clock within org-clock-in though if it detects it's in an org capture buffer? Here is my working solution for now with use-package and advice: (use-package org :straight org-plus-contrib :init (defun my/org-capture-place-entry () "Place the template as a new Org entry." (let ((template (org-capture-get :template)) (reversed? (org-capture-get :prepend)) (exact-position (org-capture-get :exact-position)) (insert-here? (org-capture-get :insert-here)) (level 1)) (org-capture-verify-tree template) (when exact-position (goto-char exact-position)) (cond ;; Force insertion at point. ((org-capture-get :insert-here) nil) ;; Insert as a child of the current entry. ((org-capture-get :target-entry-p) (setq level (org-get-valid-level (if (org-at-heading-p) (org-outline-level) 1) 1)) (if reversed? (outline-next-heading) (org-end-of-subtree t t))) ;; Insert as a top-level entry at the beginning of the file. (reversed? (goto-char (point-min)) (unless (org-at-heading-p) (outline-next-heading))) ;; Otherwise, insert as a top-level entry at the end of the file. (t (goto-char (point-max)))) (let ((origin (point))) (unless (bolp) (insert "\n")) (org-capture-empty-lines-before) (let ((beg (point))) (save-restriction (when insert-here? (narrow-to-region beg beg)) (org-paste-subtree level template 'for-yank)) (org-capture-position-for-last-stored beg) (let ((end (point))) (org-capture-empty-lines-after) (unless (org-at-heading-p) (outline-next-heading)) (org-capture-mark-kill-region origin (point)) ;; CHANGE: insert a newline so clock is included (if (org-capture-get :clock-in) (insert "\n")) (org-capture-narrow beg end) (when (or (search-backward "%?" beg t) (search-forward "%?" end t)) (replace-match ""))))))) (defun my/org-capture (&optional goto keys) "Capture something. \\ This will let you select a template from `org-capture-templates', and then file the newly captured information. The text is immediately inserted at the target location, and an indirect buffer is shown where you can edit it. Pressing `\\[org-capture-finalize]' brings you back to the \ previous state of Emacs, so that you can continue your work. When called interactively with a `\\[universal-argument]' prefix argument \ GOTO, don't capture anything, just go to the file/headline where the selected template stores its notes. With a `\\[universal-argument] \\[universal-argument]' prefix argument, go to \ the last note stored. When called with a `C-0' (zero) prefix, insert a template at point. When called with a `C-1' (one) prefix, force prompting for a date when a datetree entry is made. ELisp programs can set KEYS to a string associated with a template in `org-capture-templates'. In this case, interactive selection will be bypassed. If `org-capture-use-agenda-date' is non-nil, capturing from the agenda will use the date at point as the default date. Then, a `C-1' prefix will tell the capture process to use the HH:MM time of the day at point (if any) or the current HH:MM time." (interactive "P") (when (and org-capture-use-agenda-date (eq major-mode 'org-agenda-mode)) (setq org-overriding-default-time (org-get-cursor-date (equal goto 1)))) (cond ((equal goto '(4)) (org-capture-goto-target)) ((equal goto '(16)) (org-capture-goto-last-stored)) (t (let* ((orig-buf (current-buffer)) (annotation (if (and (boundp 'org-capture-link-is-already-stored) org-capture-link-is-already-stored) (plist-get org-store-link-plist :annotation) (ignore-errors (org-store-link nil)))) (entry (or org-capture-entry (org-capture-select-template keys))) initial) (setq initial (or org-capture-initial (and (org-region-active-p) (buffer-substring (point) (mark))))) (when (stringp initial) (remove-text-properties 0 (length initial) '(read-only t) initial)) (when (stringp annotation) (remove-text-properties 0 (length annotation) '(read-only t) annotation)) (cond ((equal entry "C") (customize-variable 'org-capture-templates)) ((equal entry "q") (user-error "Abort")) (t (org-capture-set-plist entry) (org-capture-get-template) (org-capture-put :original-buffer orig-buf :original-file (or (buffer-file-name orig-buf) (and (featurep 'dired) (car (rassq orig-buf dired-buffers)))) :original-file-nondirectory (and (buffer-file-name orig-buf) (file-name-nondirectory (buffer-file-name orig-buf))) :annotation annotation :initial initial :return-to-wconf (current-window-configuration) :default-time (or org-overriding-default-time (org-current-time))) (org-capture-set-target-location (and (equal goto 0) 'here)) (condition-case error (org-capture-put :template (org-capture-fill-template)) ((error quit) (if (get-buffer "*Capture*") (kill-buffer "*Capture*")) (error "Capture abort: %s" (error-message-string error)))) (setq org-capture-clock-keep (org-capture-get :clock-keep)) (condition-case error (org-capture-place-template (eq (car (org-capture-get :target)) 'function)) ((error quit) (when (and (buffer-base-buffer (current-buffer)) (string-prefix-p "CAPTURE-" (buffer-name))) (kill-buffer (current-buffer))) (set-window-configuration (org-capture-get :return-to-wconf)) (error "Capture template `%s': %s" (org-capture-get :key) (error-message-string error)))) (when (and (derived-mode-p 'org-mode) (org-capture-get :clock-in)) (condition-case nil (progn (when (org-clock-is-active) (org-capture-put :interrupted-clock (copy-marker org-clock-marker))) (org-clock-in) ;; CHANGE: remove inserted newline now that clock is in narrowed buffer (save-excursion (if (org-capture-get :clock-in) (progn (goto-char (point-max)) (join-line)))) (setq-local org-capture-clock-was-started t)) (error "Could not start the clock in this capture buffer"))) (when (org-capture-get :immediate-finish) (org-capture-finalize)))))))) (advice-add 'org-capture-place-entry :override #'my/org-capture-place-entry) (advice-add 'org-capture :override #'my/org-capture) ) --00000000000031cf000595c4f8d5 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
A little different solution that takes advantage of the fact that adding a newline=20 preserves the clock in the narrowed buffer. Maybe the right thing to do=20 is to widen/re-narrow buffer to include the clock within org-clock-in=20 though if it detects it's in an org capture buffer? Here is my working= =20 solution for now with use-package and advice:


=
(use-package org
=C2=A0 :straight org-plus-contrib
=C2=A0 = :init
=C2=A0 (defun my/org-capture-place-entry ()
=C2=A0 =C2=A0 "= ;Place the template as a new Org entry."
=C2=A0 =C2=A0 (let ((templ= ate (org-capture-get :template))
=C2=A0(reversed? (org-capture-get :pr= epend))
=C2=A0(exact-position (org-capture-get :exact-position))
= =C2=A0(insert-here? (org-capture-get :insert-here))
=C2=A0(level 1))=C2=A0 =C2=A0 =C2=A0 (org-capture-verify-tree template)
=C2=A0 =C2=A0 = =C2=A0 (when exact-position (goto-char exact-position))
=C2=A0 =C2=A0 = =C2=A0 (cond
=C2=A0 =C2=A0 =C2=A0 =C2=A0;; Force insertion at point.
= =C2=A0 =C2=A0 =C2=A0 =C2=A0((org-capture-get :insert-here) nil)
=C2=A0 = =C2=A0 =C2=A0 =C2=A0;; Insert as a child of the current entry.
=C2=A0 = =C2=A0 =C2=A0 =C2=A0((org-capture-get :target-entry-p)
(setq level (org= -get-valid-level
=C2=A0 =C2=A0 (if (org-at-heading-p) (org-outline-le= vel) 1)
=C2=A0 =C2=A0 1))
(if reversed? (outline-next-heading) (o= rg-end-of-subtree t t)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0;; Insert as a top-l= evel entry at the beginning of the file.
=C2=A0 =C2=A0 =C2=A0 =C2=A0(rev= ersed?
(goto-char (point-min))
(unless (org-at-heading-p) (outline-= next-heading)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0;; Otherwise, insert as a top= -level entry at the end of the file.
=C2=A0 =C2=A0 =C2=A0 =C2=A0(t (goto= -char (point-max))))
=C2=A0 =C2=A0 =C2=A0 (let ((origin (point)))
(u= nless (bolp) (insert "\n"))
(org-capture-empty-lines-before)<= br> (let ((beg (point)))
=C2=A0(save-restriction
=C2=A0 =C2=A0(when insert-here? (narrow-to-region beg beg))
= =C2=A0 =C2=A0(org-paste-subtree level template 'for-yank))
=C2=A0(= org-capture-position-for-last-stored beg)
=C2=A0(let ((end (poi= nt)))
=C2=A0 =C2=A0(org-capture-empty-lines-a= fter)
=C2=A0 =C2=A0(unless (org-at-heading-p) (outline-next-heading))<= br> =C2=A0 =C2=A0(org-capture-mark-kill-region origin (point))
= =C2=A0 =C2=A0;; CHANGE: insert a newline so clock is included
=C2=A0 = =C2=A0(if (org-capture-get :clock-in) (insert "\n"))
=C2=A0 = =C2=A0(org-capture-narrow beg end)
=C2=A0 =C2=A0(when (or (search-back= ward "%?" beg t)
=C2=A0 =C2=A0 =C2=A0(search-forward "= %?" end t))
=C2=A0 =C2=A0 =C2=A0(replace-match ""))))))= )

=C2=A0 (defun my/org-capture (&optional goto keys)
=C2=A0 = =C2=A0 "Capture something.
=C2=A0 \\<org-capture-mode-map>=C2=A0 This will let you select a template from `org-capture-templates'= ;, and
=C2=A0 then file the newly captured information.=C2=A0 The text i= s immediately
=C2=A0 inserted at the target location, and an indirect bu= ffer is shown where
=C2=A0 you can edit it.=C2=A0 Pressing `\\[org-captu= re-finalize]' brings you back to the \
=C2=A0 previous
=C2=A0 sta= te of Emacs, so that you can continue your work.

=C2=A0 When called = interactively with a `\\[universal-argument]' prefix argument \
=C2= =A0 GOTO, don't
=C2=A0 capture anything, just go to the file/headlin= e where the selected
=C2=A0 template stores its notes.

=C2=A0 Wit= h a `\\[universal-argument] \\[universal-argument]' prefix argument, go= to \
=C2=A0 the last note stored.

=C2=A0 When called with a `C-0= ' (zero) prefix, insert a template at point.

=C2=A0 When called = with a `C-1' (one) prefix, force prompting for a date when
=C2=A0 a = datetree entry is made.

=C2=A0 ELisp programs can set KEYS to a stri= ng associated with a template
=C2=A0 in `org-capture-templates'.=C2= =A0 In this case, interactive selection
=C2=A0 will be bypassed.

= =C2=A0 If `org-capture-use-agenda-date' is non-nil, capturing from the<= br>=C2=A0 agenda will use the date at point as the default date.=C2=A0 Then= , a
=C2=A0 `C-1' prefix will tell the capture process to use the HH:= MM time
=C2=A0 of the day at point (if any) or the current HH:MM time.&q= uot;
=C2=A0 =C2=A0 (interactive "P")
=C2=A0 =C2=A0 (when (a= nd org-capture-use-agenda-date
=C2=A0 =C2=A0 =C2=A0 (eq major-mode = 9;org-agenda-mode))
=C2=A0 =C2=A0 =C2=A0 (setq org-overriding-default-ti= me
=C2=A0 =C2=A0(org-get-cursor-date (equal goto 1))))
=C2=A0 =C2= =A0 (cond
=C2=A0 =C2=A0 =C2=A0((equal goto '(4)) (org-capture-goto-t= arget))
=C2=A0 =C2=A0 =C2=A0((equal goto '(16)) (org-capture-goto-la= st-stored))
=C2=A0 =C2=A0 =C2=A0(t
=C2=A0 =C2=A0 =C2=A0 (let* ((orig-= buf (current-buffer))
=C2=A0 =C2=A0 (annotation (if (and (boundp '= org-capture-link-is-already-stored)
=C2=A0org-capture-link-is-alrea= dy-stored)
=C2=A0 =C2=A0 (plist-get org-store-link-plist :annotation= )
=C2=A0 (ignore-errors (org-store-link nil))))
=C2=A0 =C2=A0 (= entry (or org-capture-entry (org-capture-select-template keys)))
=C2= =A0 =C2=A0 initial)
(setq initial (or org-capture-initial
=C2=A0= (and (org-region-active-p)
=C2=A0 =C2=A0 =C2=A0 (buffer-substring (p= oint) (mark)))))
(when (stringp initial)
=C2=A0(remove-text-proper= ties 0 (length initial) '(read-only t) initial))
(when (stringp ann= otation)
=C2=A0(remove-text-properties 0 (length annotation)
= =C2=A0'(read-only t) annotation))
(cond
((equal entry "C&= quot;)
=C2=A0(customize-variable 'org-capture-templates))
((e= qual entry "q")
=C2=A0(user-error "Abort"))
(= t
=C2=A0(org-capture-set-plist entry)
=C2=A0(org-capture-get-temp= late)
=C2=A0(org-capture-put :original-buffer orig-buf
=C2=A0 := original-file (or (buffer-file-name orig-buf)
=C2=A0 =C2=A0 =C2=A0= (and (featurep 'dired)
=C2=A0 (car (rassq orig-buf
= =C2=A0 =C2=A0 =C2=A0 dired-buffers))))
=C2=A0 :original-file-nondir= ectory
=C2=A0 (and (buffer-file-name orig-buf)
(file-name-non= directory
(buffer-file-name orig-buf)))
=C2=A0 :annotation a= nnotation
=C2=A0 :initial initial
=C2=A0 :return-to-wconf (cu= rrent-window-configuration)
=C2=A0 :default-time (or org-overriding-= default-time
=C2=A0 =C2=A0 (org-current-time)))
=C2=A0(org-ca= pture-set-target-location (and (equal goto 0) 'here))
=C2=A0(condi= tion-case error
=C2=A0 =C2=A0 =C2=A0(org-capture-put :template (org-ca= pture-fill-template))
=C2=A0 =C2=A0((error quit)
=C2=A0 =C2=A0 (i= f (get-buffer "*Capture*") (kill-buffer "*Capture*")) =C2=A0 =C2=A0 (error "Capture abort: %s" (error-message-strin= g error))))

=C2=A0(setq org-capture-clock-keep (org-capture-get :c= lock-keep))
=C2=A0(condition-case error
=C2=A0 =C2=A0 =C2=A0(org-= capture-place-template
=C2=A0 =C2=A0 =C2=A0 (eq (car (org-capture-get = :target)) 'function))
=C2=A0 =C2=A0((error quit)
=C2=A0 =C2= =A0 (when (and (buffer-base-buffer (current-buffer))
(string-prefix-p= "CAPTURE-" (buffer-name)))
=C2=A0 =C2=A0 =C2=A0 (kill-buffe= r (current-buffer)))
=C2=A0 =C2=A0 (set-window-configuration (org-capt= ure-get :return-to-wconf))
=C2=A0 =C2=A0 (error "Capture template= `%s': %s"
=C2=A0 =C2=A0(org-capture-get :key)
=C2=A0 = =C2=A0(error-message-string error))))
=C2=A0(when (and (derived-mode-p= 'org-mode) (org-capture-get :clock-in))
=C2=A0 =C2=A0(condition-c= ase nil
(progn
=C2=A0(when (org-clock-is-active)
=C2=A0 = =C2=A0(org-capture-put :interrupted-clock
=C2=A0 =C2=A0 (copy-marke= r org-clock-marker)))
=C2=A0(org-clock-in)

=C2=A0;; CHANGE:= remove inserted newline now that clock is in narrowed buffer
=C2=A0(= save-excursion (if (org-capture-get :clock-in)
=C2=A0 =C2=A0 =C2= =A0(progn (goto-char (point-max)) (join-line))))
=C2=A0(setq-local or= g-capture-clock-was-started t))
=C2=A0 =C2=A0 =C2=A0(error "Could= not start the clock in this capture buffer")))
=C2=A0(when (org-= capture-get :immediate-finish)
=C2=A0 =C2=A0(org-capture-finalize)))))= )))

=C2=A0 (advice-add 'org-capture-place-entry :override #'= my/org-capture-place-entry)
=C2=A0 (advice-add 'org-capture :overrid= e #'my/org-capture)
=C2=A0 )
--00000000000031cf000595c4f8d5--