From 2960652d664aee33de307b0fed38ac3acd237a5f Mon Sep 17 00:00:00 2001 From: Daniel Borchmann Date: Fri, 17 Jan 2025 17:54:06 +0100 Subject: [PATCH 1/2] Draft function to convert Org items to headlines This usually happens when I try to convert loose entrie in my refile file into proper headlines. Usage of Org capture functionality is inspired by Sacha Chua [1]. [1]: https://sachachua.com/blog/2020/12/org-mode-create-a-quick-timestamped-note-and-capture-a-screenshot-by-prefilling-a-capture-template-via-emacs-lisp/ --- site-lisp/db-org.el | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/site-lisp/db-org.el b/site-lisp/db-org.el index e536a56..f858cb6 100644 --- a/site-lisp/db-org.el +++ b/site-lisp/db-org.el @@ -388,6 +388,59 @@ In ~%s~: (advice-add 'org-capture-finalize :after #'db/delete-frame-if-capture) +(require 'org-capture) + +(defun db/org-convert-item-to-headline () + "Convert list item around point to headline. + +TODO: more information." + (interactive) + + (let ((element (org-element-at-point)) + last-seen-item) + + ;; Get outermost list item + (while element + (when (eq (org-element-type element) 'item) + (setq last-seen-item element)) + (setq element (org-element-parent element))) + + (unless last-seen-item + (user-error "Cannot find enclosing list item at point to convert to headline")) + + ;; Generate headline and store it somewhere + (let ((body (buffer-substring-no-properties (org-element-contents-begin last-seen-item) + (org-element-end last-seen-item)))) + + ;; Remove old entry first + (delete-region (org-element-begin last-seen-item) + (org-element-end last-seen-item)) + + ;; Set up capture buffer + (org-capture-set-plist `("" + "" + entry + (file db/org-default-refile-file) + ,(format "* TODO [#B] %s +:PROPERTIES: +:CREATED: %%U +:END: + +Via %%(with-temp-buffer (db/org-add-link-to-current-clock) (string-trim (buffer-string))). + +%s + +%%?" + (seq-take-while #'(lambda (x) (not (= x ?\n))) body) ; TODO: improve + (string-trim (seq-drop-while #'(lambda (x) (not (= x ?\n))) body))) + :empty-lines-before 1 + :empty-lines-after 1)) + (org-capture-set-target-location) + (org-capture-put :template (org-capture-fill-template (org-capture-get :template))) + (org-capture-place-template) + + (indent-region (point-min) (point-max))))) + ;;; Refiling From 6e31e4a707c062213f104991a82f1c18ed0fbb52 Mon Sep 17 00:00:00 2001 From: Daniel Borchmann Date: Fri, 17 Jan 2025 18:10:20 +0100 Subject: [PATCH 2/2] Clean up draft of Org list item conversion function The template is still fixed, should it be customizable? --- site-lisp/db-org.el | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/site-lisp/db-org.el b/site-lisp/db-org.el index f858cb6..3258323 100644 --- a/site-lisp/db-org.el +++ b/site-lisp/db-org.el @@ -13,6 +13,7 @@ (require 'cl-lib) (require 'org) (require 'org-agenda) +(require 'org-capture) (require 'org-clock) (require 'hydra) (require 'db-customize) @@ -388,12 +389,23 @@ In ~%s~: (advice-add 'org-capture-finalize :after #'db/delete-frame-if-capture) -(require 'org-capture) - (defun db/org-convert-item-to-headline () "Convert list item around point to headline. -TODO: more information." +Search for the outermost list item enclosing point and convert it +to a Org headline. Use the first line of the item as actual +headline, and move the rest to the body of the headline. A +property CREATED is added with an inactive timestamp capturing +the current time. + +The converted headline will be shown in a capture buffer for +further editing. After finishing this buffer, the final headline +will be stored in `db/org-default-refilefile'. + +Note that the original list item will be deleted before the +capture buffer will open. If the buffer is aborted, the original +list item is _not_ restored. This has to be done using the undo +history of the buffer." (interactive) (let ((element (org-element-at-point)) @@ -409,19 +421,23 @@ TODO: more information." (user-error "Cannot find enclosing list item at point to convert to headline")) ;; Generate headline and store it somewhere - (let ((body (buffer-substring-no-properties (org-element-contents-begin last-seen-item) - (org-element-end last-seen-item)))) + (let* ((body (buffer-substring-no-properties (org-element-contents-begin last-seen-item) + (org-element-end last-seen-item))) + (first-line-of-body (seq-take-while #'(lambda (x) (not (= x ?\n))) body)) + (rest-of-body (string-trim (seq-drop-while #'(lambda (x) (not (= x ?\n))) body)))) ;; Remove old entry first (delete-region (org-element-begin last-seen-item) (org-element-end last-seen-item)) ;; Set up capture buffer - (org-capture-set-plist `("" - "" - entry - (file db/org-default-refile-file) - ,(format "* TODO [#B] %s + (org-capture-put :key "") + (org-capture-put :description "") + (org-capture-put :target '(file db/org-default-refile-file)) + (org-capture-put :empty-lines-before 1) + (org-capture-put :empty-lines-after 1) + (org-capture-put :template (org-capture-fill-template + (format "* TODO [#B] %s :PROPERTIES: :CREATED: %%U :END: @@ -431,12 +447,9 @@ Via %%(with-temp-buffer (db/org-add-link-to-current-clock) (string-trim (buffer- %s %%?" - (seq-take-while #'(lambda (x) (not (= x ?\n))) body) ; TODO: improve - (string-trim (seq-drop-while #'(lambda (x) (not (= x ?\n))) body))) - :empty-lines-before 1 - :empty-lines-after 1)) + first-line-of-body + rest-of-body))) (org-capture-set-target-location) - (org-capture-put :template (org-capture-fill-template (org-capture-get :template))) (org-capture-place-template) (indent-region (point-min) (point-max)))))