How to insert a prefix to the description when using org-roam-node-insert?

I want to automatically insert a prefix to the description of the link whenever I insert a link using org-roam-node-insert. For eg.-
Whenever I insert a link to one of my projects, I should have proj:project1_name as the link description instead of just project1_name. Similarly after selecting project2_name in org-roam-node-insert, I should get the link description as proj:project2_name. Also, if there is some other category of things like a “plan”, I should get plan:plan1_name and so on. Of course, I would first need to define the “proj” variable for the projects and the “plan” variable for the plans. Also, if there is no such “variable” defined for some entity, the prefix should not be inserted.
Can someone guide me on how to achieve this? I looked into aliases but, I don’t think they are suitable for my use case.

Could be done trivially - depends on how you want to define the variable – would it be defined automatically based on the folder or how? The way to solve a problem is to first delineate clear steps from reaching point a to point b – unless the steps could be clarified, no algorithm could be built to automate the process - try to think in terms of steps.

I intentionally didn’t specify where I would put the “prefix” (thinking if there was a better way than mine, then, someone could help me out). What I was thinking was putting a different prefix for each file (maybe in the properties drawer at the top of the file). Maybe this could be extended to the headings with the property drawer. I don’t know how I would go about extracting that. If there is some better way/location to hold the “prefix” word, then I would be happy to hear it.

(defun 0/org-roam-node-insert (&optional filter-fn &key templates info)
  "Find an Org-roam node and insert (where the point is) an \"id:\" link to it.
FILTER-FN is a function to filter out nodes: it takes an `org-roam-node',
and when nil is returned the node will be filtered out.
The TEMPLATES, if provided, override the list of capture templates (see
`org-roam-capture-'.)
The INFO, if provided, is passed to the underlying `org-roam-capture-'."
  (interactive)
  (unwind-protect
      ;; Group functions together to avoid inconsistent state on quit
      (atomic-change-group
        (let* ((region-text (if (region-active-p)
                                (buffer-substring-no-properties (region-beginning) (region-end))))
               (node (org-roam-node-read region-text filter-fn))
               (description (or region-text
                                (org-roam-node-formatted node)))
               (id (org-roam-node-id node))
               (prefix (org-entry-get (point) "prefix"))) ;; Change "prefix" to the name of your property
          (if id
              (progn
                (when region-text
                  (delete-region (region-beginning) (region-end)))
                (insert (org-link-make-string
                         (concat "id:" id)
                         (concat prefix (when prefix ":") description)))
                (run-hook-with-args 'org-roam-post-node-insert-hook id description))
            (org-roam-capture-
             :node node
             :info info
             :templates templates
             :props (list :region (when (region-active-p)
                                     (cons (region-beginning) (region-end)))
                          :link-description description
                          :finalize 'insert-link)))))
    (deactivate-mark)))

The value of the property :prefix: will be automatically taken into consideration – let me know if you need anything else

1 Like

Hi, sorry for not replying earlier as I was understanding and trying out the code snippet shared by you. Thank you so much for the code snippet.
One issue I am facing is that the “prefix” variable is empty, even, after adding the property :prefix: project1_name. Do you know what might be causing the issue?

You should add the prefix to the headline – and then save the file before inserting it. Is it not working for that? Or are you adding the property to the file property then want the headline to just grab it?

For simplicity I have considered the case where each headline could be configured with its own prefix

I tried inserting this (with different uuids) for a heading as well as on top of a file-

:PROPERTIES:
:ID:       f896f7c2-145a-4229-ab2c-9ea6a5cb08e5
:prefix:    project1_name
:END:

After that, I call M-x 0/org-roam-node-insert from another file to insert the link. But, I still get an empty prefix value.

My mistake – I did not test it out thoroughly, we need to dynamically get the property value – I tested it in the current file only

(defun 0/org-roam-get-prefix (node)
  "Determine the prefix for an Org-roam node."
  (let ((file (org-roam-node-file node)))
    (with-current-buffer (find-file-noselect file)
      (org-with-point-at (org-roam-node-point node)
        (org-entry-get nil "prefix")))))

(defun 0/org-roam-node-insert (&optional filter-fn &key templates info)
  "Find an Org-roam node and insert (where the point is) an \"id:\" link to it.
FILTER-FN is a function to filter out nodes: it takes an `org-roam-node',
and when nil is returned the node will be filtered out.
The TEMPLATES, if provided, override the list of capture templates (see
`org-roam-capture-'.)
The INFO, if provided, is passed to the underlying `org-roam-capture-'."
  (interactive)
  (unwind-protect
      ;; Group functions together to avoid inconsistent state on quit
      (atomic-change-group
        (let* ((region-text (if (region-active-p)
                                (buffer-substring-no-properties (region-beginning) (region-end))))
               (node (org-roam-node-read region-text filter-fn))
               (description (or region-text
                                (org-roam-node-formatted node)))
               (id (org-roam-node-id node))
               (prefix (0/org-roam-get-prefix node))) ;; Get prefix dynamically
          (if id
              (progn
                (when region-text
                  (delete-region (region-beginning) (region-end)))
                (insert (org-link-make-string
                         (concat "id:" id)
                         (concat prefix (when prefix ":") description)))
                (run-hook-with-args 'org-roam-post-node-insert-hook id description))
            (org-roam-capture-
             :node node
             :info info
             :templates templates
             :props (list :region (when (region-active-p)
                                     (cons (region-beginning) (region-end)))
                          :link-description description
                          :finalize 'insert-link)))))
    (deactivate-mark)))

I have defined a helper function to get the property correctly this time, let me know if it works

1 Like

Hey, that works perfectly as I want even from another file. Thank you so much.
One question I want to ask is why the previous solution didn’t work?

1 Like

Because it was looking for the property in the file you were inserting in rather than in the file the node is defined at, I made a silly mistake.

1 Like