2

Is there a method to link files without specifying their absolute file name nor their relative file name; just the non-directory part of their file name? I remember stumbling into one when browsing the other day that was defined as a custom link type that maintains some sort of data structure that users can append to and that it is used to resolve links but the name escapes me.

so for example, to refer to a file located ../../blob.txt, all I have to do is [[LINKTYPE:blob.txt]] and this works across files. I would expect I need to add the absolute file name to some list/data structure or some other resolving mechanism.

  • In Emacs jargon we do not use "path" the way you used it; hence the edit (and rollback). See the Emacs manual Glossary - see the glossary entry for "File Name", where you see this all explained. – Drew Nov 13 at 1:39
  • @Drew I see, I wasn't aware of the different terminology. I already know how to link with just relative file name, it is described in here. What I am looking for is the "file name", or in Emacs terminology the "non-directory part of the file name". – Joann Morris Nov 13 at 2:42
  • You can set the :follow property of a customized link type with org-link-set-parameters. The :follow property is a function that takes the link as argument when you click on it. – Tobias Nov 13 at 3:36
  • The nondirectory part of an absolute file name is the relative file name. You can obtain it using function file-name-nondirectory. – Drew Nov 13 at 4:54
  • @drew I believe that is not correct. as per this, relative file name is no different than relative path. for example "../../file.org" is a relative file name, while the associated non-directory part of the file name is file.org. you are right though that file-name-nondirectory returns the non directory part of a file name. file-relative-name returns the relative file name. note that file-realtive-name takes two arguments as it is relative. – Joann Morris Nov 13 at 5:42
1

You can use org-link-set-parameters to define your own link types as demonstrated in the following Elisp snippet.

The snippet contains a function my-org-open-file which opens the file given as org file link target. If the file name is relative and if the file with that name does not exist my-org-open-file tries to find an existing file by expanding the file name successively with all entries of the path list my-org-path.

Note that you can customize my-org-path. Just call M-x customize-option RET my-org-path RET and insert the paths you need.

If my-org-open-file does not find the file at all a buffer is generated with the original file name as buffer-file-name.

(defcustom my-org-path nil
  "List of paths to try with `my-org-open-file'.
If the LINK argument for `my-org-open-file' is a relative path
and a file with that path does not exist
try successively each of the directory entries of this list
as `default-directory' for expanding the path.
The directory entries can be given relative or absolute."
  :type '(repeat directory)
  :group 'org-link-follow)

(defun my-org-open-file (link)
  "Open LINK with `org-open-file'.
If LINK is given as relative file path also try to find file
with prefixes from `my-org-path'."
  (let* ((el (car (org-element-parse-secondary-string (format "[[file:%s]]" link) '(link))))
     (option (org-element-property :search-option el))
     (path (org-element-property :path el))
     (app (org-element-property :application el))
     (org-path (org-property-or-variable-value 'my-org-path t)))
    (when (stringp org-path)
      (setq org-path (list org-path)))
    (setq path (substitute-in-file-name path))
    (unless (file-name-absolute-p path)
      (cl-dolist (path-prefix org-path)
    (let ((try-path (expand-file-name path path-prefix)))
      (when (file-exists-p try-path)
        (setq path try-path)
        (cl-return)))))
    (apply #'org-open-file
       path
       (cond ((equal app "emacs") 'emacs)
         ((equal app "sys") 'system))
       (cond ((not option) nil)
         ((string-match-p "\\`[0-9]+\\'" option)
          (list (string-to-number option)))
         (t (list nil option))))))

(org-link-set-parameters
 "myfile"
 :follow #'my-org-open-file
 :complete #'org-file-complete-link)

You can set the search path also in the properties drawer of an Org section as demonstrated in the following example:

* My Section
:PROPERTIES:
:org-search-path: ("~/tmp" "/tmp" "/temp")
:END:
  • thanks. work like a charm. – Joann Morris Nov 21 at 2:22

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.