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)
| improve this answer | |

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.