I want to create a file with org-open-at-point from a template if that file does not exist. If it exists, I want to open it in an external app.

In org-mode, file-links are created by [[file:path-to-file.ext]]. Enter or C-c C-o opens that file. This behavior is defined by org-file-apps depending on the file extension. According to the docs, org-file-apps can take functions as argument:

Possible values for the command are:
 string        A command to be executed by a shell; %s will be replaced
               by the path to the file.
 function      A Lisp function, which will be called with two arguments:
               the file path and the original link string, without the
               "file:" prefix.

(add-to-list 'org-file-apps '("\\.svg\\'" . "inkscape %s")) opens that file in inkscape.

I wrote a function to create the file beforhand if it does not exist:

    (defun inkscape-open (path &optional link)
      "Open the path in inkscape. Copy template if path does not exist."
      (unless (file-exists-p path)
          (shell-command (format "cp /home/jolla/Dropbox/org/sketches/default.svg %s" path)))
      (shell-command (format "inkscape %s" path))

and set it for svg-files:

 (add-to-list 'org-file-apps '("\\.svg\\'" . inkscape-open))

1.) This does not work: emacs tells me that the file does not exist. If it exists, emacs opens the file.

2.) I would like to modify my function so that it only creates the file if a specific directory (like Dropbox/org/sketches) is in path. What would I have to do?

3.) How can I switch focus to inkscape after org-open-at-point?

PS: if I create a new link-parameter like [[svg:path-to-file.ext]] like this:

 :follow (lambda (path)
           (let ((actions '(("find-file" . find-file)
                            ("edit in inkscape" . inkscape-open))))
         (funcall (cdr (assoc (completing-read "Action: " actions) actions)) path))))

I can chose inkscape-open and the function works as expected. This is also described here. However, I don't want to create a new link type because this would prevent org-mode from showing inline images.


OK, this appears to be quite complicated. I found two solutions, both of which require a good deal of lisp knowledge.

  1. org-open-at-point pipes the file link to org-open-file. This function checks if the file exists first, before handling org-file-apps. This behavior is hardcoded in org.el. So I would have to change the function to skip the file exists check.
  2. I could alternatively add svg-images to the images displayed in org-buffers. This behavior is also hardcoded in org.el in org-display-inline-images, I think this is the code I would need to change:
    (format "\\[\\[\\(?:file%s:\\|attachment:\\|[./~]\\)\\|\\]\\[\\(<?file:\\)"
            (if (not link-abbrevs) ""
              (concat "\\|" (regexp-opt link-abbrevs)))))

I am not literate enough in emacs-lisp to accomplish this.

As a workaround, I wrote a script for autokey, which espands on [ink and asks for a file-name, copies my template, inserts the link and opens inkscape. Here is the code:

import shutil

retCode, new_file = dialog.input_dialog(title='file name', message='Enter a file name') 
path = "/home/jolla/Dropbox/org/sketches/"

# copy template
shutil.copyfile(path + "default.svg",
                path + new_file + ".svg")

# write link
output = "[[{}{}.svg]]".format(path, new_file)

# open inkscape
ret = system.exec_command('inkscape {}{}.svg &'.format(path, new_file), getOutput=False)

What you are asking to do sounded a lot like what Binnema did in mu4e to open attachments at a point in mu4e specifically in the mu4e-view section of his package, like so:

(defun mu4e-view-open-attachment-with (msg attachnum &optional cmd)
  "Open MSG's attachment ATTACHNUM with CMD.
If CMD is nil, ask user for it."
  (let* ((att (mu4e~view-get-attach msg attachnum))
         (ext (file-name-extension (plist-get att :name)))
         (cmd (or cmd
                   (mu4e-format "Shell command to open it with: ")
                   (assoc-default ext mu4e-view-attachment-assoc)
         (index (plist-get att :index)))
     (mu4e-message-field msg :docid) index 'open-with cmd)))

I suspect that you are working on getting the same thing Dirk-Jan gets from the attatchment link. It seems like it is difficult to organize them in a way to produce images inline effectively in every case, but this works to open the attachments in their native applications, just not in an embedded fashion. I suspect it is better in some cases for you as there is native support for the existing files (like in your svg example) that you don't want to miss out on. You stated that the native support would have to be added to emacs itself, but I think you can add that to an org-mode extension instead of working directly on the built-in application like Binnema does with org-mu4e.

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.