11

Q: How can I get a custom org link function to insert a description automatically?

I'd like to store org links to files in a dired buffer, but would prefer that the link description be the file name sans path rather than report the full path, ie:

file:~/the/full/path/myfile.ext     ; default, but no thanks
myfile.ext                          ; what I want

Now: org-store-link hardcodes links from dired to provide the default. Instead, I've written a custom function (cribbing from the hard-coded function) and added it to org-store-link-functions:

(defun dired-store-link ()
  (when (derived-mode-p 'dired-mode)
    (let ((file (dired-get-filename nil t)))
      (setf file (if file
                     (abbreviate-file-name (expand-file-name file))
                   default-directory))
      (org-store-link-props :type        "dired"
                            :link        file
                            :description (file-name-nondirectory file))
      file)))

(add-to-list 'org-store-link-functions #'dired-store-link)

So far so good, and it works as expected, but for one thing:

  • When calling org-insert-link with the built-in, default behavior, it simply inserts the link without asking me for a description.
  • When calling org-insert-link with my custom function, it prompts me to enter a description (which it correctly populates with the file name stored in the :description property).

I'd rather not be prompted for the description each time, and want org-insert-link to use the value of :description that the custom function sets.

How can I convince org-insert-link to use the :description automatically without prompting me for it?

  • Do the optional arguments link-location or default-description in the function org-insert-link help any? If the LINK-LOCATION parameter is non-nil, this value will be used as the link location instead of reading one interactively. If the DEFAULT-DESCRIPTION parameter is non-nil, this value will be used as the default description. – lawlist Jun 11 '15 at 20:09
  • @lawlist: thanks for the suggestion, although I'm not sure how I'd set it in interactive use without wrapping it in another function. However, it made me read the docstring more closely, which got me to an answer of sorts. – Dan Jun 11 '15 at 20:53
4

Buried at the bottom of the docstring for org-insert-link is a note that:

If org-make-link-description-function is non-nil, this function will be called with the link target, and the result will be the default link description.

Apparently org throws away a lot of information in the process of storing a link, so all that's left in org-stored-links is a list of entries of the form (link description). Insofar as the earlier function has a file name for the link, it looks like the following works:

(defun org-link-describe (link desc)
  (if (file-exists-p link)
      desc
    (read-string "Description: " desc)))

(setf org-make-link-description-function #'org-link-describe)

It's kind of hacky, and I haven't tested it extensively, but it seems to work so far. Would be thrilled to see a more elegant solution, of course.

  • 2
    Now that you know this function, can't you ditch dired-store-link and just use this to create the description you want? I think that would end up a lot shorter. – Malabarba Jun 25 '15 at 14:48
  • 1
    @Malabarba: you're probably right -- this function could be rewritten to inspect the link for a file and proceed accordingly. Will try it out when I get a spare moment. – Dan Jun 25 '15 at 14:53
2

I'm using org 9.1.6, and to my dismay it seems that org-store-link-functions is now a builtin org function (rather than a hook), so the original solution no longer works. There may be a workaround using org-link-parameters, but instead I'm using the following little hack, which seems to do the trick:

(defun my//dired-store-link (orig-fun &rest args)
  (if (derived-mode-p 'dired-mode)
      (let ((file (dired-get-filename nil t)))
        (setf file (if file
                       (abbreviate-file-name (expand-file-name file))
                     default-directory))
        (let ((link (concat "file:" file))
              (desc (file-name-nondirectory file)))
          (push (list link desc) org-stored-links)
          (car org-stored-links)))
    (apply orig-fun args)))
(advice-add 'org-store-link :around #'my//dired-store-link)

As a bonus, this does not prompt for a description, since the description pushed to org-stored-links is non-nil.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.