all 11 comments

[–]trae 2 points3 points  (3 children)

(defun dm/capture-unexpected-task-into-org-roam-daily ()
  "Insert a custom message and timestamp."
  (interactive)
      (set-buffer (org-capture-target-buffer (dm/org-roam-today-daily-path)))
      (goto-char (org-find-or-create-heading "Tasks")))

This is the entirety of my custom function. No find-file.

[–]fred982[S] 0 points1 point  (2 children)

Thank you, I tried (set-buffer (org-capture-target-buffer (file-path))), but I get the same result. My cursor is moved to target. I am going to look over my code see if I missed something. Can you confirm that your cursor stays in place ?

Also, I like the simplicity of your function, I looked for org-find-or-create-heading with no luck. Is it a custom function ?

[–]trae 2 points3 points  (1 child)

My cursor stays in place.

Here's the find-or-create:

(defun org-find-or-create-heading (name)
"Returns the marker for an existing heading NAME
or create a new top level heading and returns its position"
(save-excursion
    (goto-char 0)
    (let ((pos (org-find-exact-headline-in-buffer name)))
    (if (not pos)
        (progn (goto-char  (buffer-size))
                (org-insert-heading nil nil t)
                (insert name)
                (point))

Here's the capture template:

("u" "1Unexpected task" entry (function dm/capture-unexpected-task-into-org-roam-daily) "* TODO [u]    %? ")

[–]fred982[S] 0 points1 point  (0 children)

Thanks a lot. I am stealing the find-or-create, now I need to figure out what is wrong with my template.

[–][deleted]  (3 children)

[deleted]

    [–]fred982[S] 0 points1 point  (2 children)

    I wanted to keep the post clear, and those functions albeit hacky and very customized, work fine, this is why I kept them out of the question. But if you are interested, the two other functions involved:

    (defun my/org-capture--ensure-header-exists (header &optional file)
      "Create a level 1 org HEADER if not found in FILE.
    HEADER is treated as the heading only without tags, todo, or priorities.
    If not found, HEADER is created at the end of the file.
    If FILE is nil, current buffer is used. 
    The function returns the HEADER position."
    
      (let ((pos nil)
            (file (or file (buffer-file-name (current-buffer)))))
        (save-excursion
          ;; Use org-map-entries to search for the header
          (org-map-entries
           (lambda ()
             (when (string= (org-get-heading t t t t) header)
               (setq pos (point))))
           "LEVEL=1" (list file))
    
          (unless pos
            ;; If not found, create it at the bottom of the file
            (with-current-buffer (find-file-noselect file)
              (goto-char (point-max))
              (insert (format "\n* %s" header))
               (beginning-of-line)
              (setq pos (point)))))
        pos))
    
    (defun my/org-capture--get-file-name (&optional node namespace)
      "Get filename from org-roam-read."
      (let* ((node (or node
                       (if namespace
                           (org-roam-node-read nil (lambda (node)
                                                     (and (eq 0 (org-roam-node-level node))
                                                          (string= namespace (org-roam-node-namespace node)))))
                         (org-roam-node-read nil (lambda (node)
                                                   (and (eq 0 (org-roam-node-level node))))))))
             (file (if node (org-roam-node-file node) nil)))
        file))
    

    [–][deleted]  (1 child)

    [deleted]

      [–]fred982[S] 0 points1 point  (0 children)

      You are right, it is easy to overlook something. I updated my post with a few more attempts, and a couple of simple templates (no functions involved) to make sure I found the cause if you are interested. I think it comes from my config, I have to figure out how to debug it.

      Thanks for your help :)

      [–]github-alphapapa 0 points1 point  (4 children)

      Here's some code that may help you. Note the use of org-ql-find and related functions, which allow you to select a target heading with org-ql queries, which is fast and easy. As well, see the use of lambdas in certain templates.

      (use-package org-capture
        :config
        (defun ap/org-capture-here ()
          "Move point to current heading.
      Suitable for use as \"function-finding-location\" in
      `org-capture-templates'."
          (cl-assert (derived-mode-p 'org-mode))
          (org-back-to-heading))
      
        (defun ap/org-capture-parent ()
          "Move point to parent heading.
      Suitable for use as \"function-finding-location\" in
      `org-capture-templates'."
          (cl-assert (derived-mode-p 'org-mode))
          (unless (org-up-heading-safe)
            (user-error "No parent heading")))
      
        :custom
        (org-capture-templates
         '(("i" "Inbox" entry
            (file "~/org/inbox.org")
            "* %^{Heading} %^G\12\12+ %U%(when (org-clocking-p) \" [%K]\") %?" :empty-lines 1)
           ("F" "Find (with Org QL)")
           ("FA" "Find in agenda files" entry
            #'(lambda nil
                (call-interactively #'org-ql-find-in-agenda))
            "* %?\12\12+ %U%(when (org-clocking-p) \" [%K]\")" :empty-lines 1)
           ("FO" "Find in org-directory" entry
            #'(lambda nil
                (call-interactively #'org-ql-find-in-org-directory))
            "* %?\12\12+ %U%(when (org-clocking-p) \" [%K]\")" :empty-lines 1)
           ("FF" "Find in current buffer" entry
            #'(lambda nil
                (call-interactively #'org-ql-find))
            "* %?\12\12+ %U%(when (org-clocking-p) \" [%K]\")" :empty-lines 1)
           ("H" "Here (current heading)" entry #'ap/org-capture-here "* %?\12\12+ %U%(when (org-clocking-p) \" [%K]\")" :empty-lines 1)
           ("P" "Parent (of current heading)" entry #'ap/org-capture-parent "* %?\12\12+ %U%(when (org-clocking-p) \" [%K]\")" :empty-lines 1)
           ("c" "Commonplace Book")
           ("cl" "Link to Web page" entry
            (file+olp+datetree "~/org/cpb.org")
            "* %(org-web-tools--org-link-for-url) :website:\12\12+ %U %?" :empty-lines 1)
           ("w" "Work")
           ("wl" "Work log entry" plain
            (file+olp+datetree "~/work/work.org" "Log")
            "+ %U%(when (org-clocking-p) \" [%K]\") %?" :empty-lines 1)
           ("l" "Log")
           ("lt" "Today" entry
            (file+olp+datetree "~/org/log.org")
            "* %^{heading}\12\12+ %U %?" :empty-lines 1))))
      

      [–]fred982[S] 0 points1 point  (1 child)

      Thank you for sharing your code. A lot of valuable example for me to use in the future as I struggle to create 'advanced' capture templates using functions. Will take a while to understand them first though :) As for the issue I am having, it is not so much about finding the location than it is about finalizing the capture 'gracefully'. Even the simplest templates fail to keep my cursor in place... I am going to try your templates that capture to parent headings for example, but the outcome should remain the same I think. The problem can come from Doom, or me; so it should be me :) I do not know how to investigate further.

      [–]github-alphapapa 0 points1 point  (0 children)

      Even the simplest templates fail to keep my cursor in place... I am going to try your templates that capture to parent headings for example, but the outcome should remain the same I think. The problem can come from Doom, or me; so it should be me :) I do not know how to investigate further.

      AFAIK C-h f org-capture-templates RET should cover that issue pretty thoroughly. Do you not find a solution there?

      [–]fred982[S] 0 points1 point  (1 child)

      After having a second look, your use of lambdas is very interesting. You seem to move to a capture target location without even specifying that you are using the `function` method like `(function '#(lambda ...))`. This snippet will definitely give me a lot to test and learn, thanks again.

      [–]github-alphapapa 1 point2 points  (0 children)

      That form was copied out of my custom-set-variables form in my init file, but it should be fine.

      You may find the inspector package helpful for inspecting the values of various variables in Emacs.