2

I wrote a Python script to parse an org file that I keep my tasks in, reformat those tasks, and save them to a taskpaper file so that I can easily view and process the tasks on my phone. The script works the way I want it to, but I have to rememeber to run it every time I want my tasks to 'sync'. I have been trying to use after-save-hook to run the script whenever I save changes to my org file, but I haven't been able to get it to work. I am new to Emacs, and don't know much about lisp. This is what I have come up with based mostly on the answer to this question.

(defun sync-to-taskpaper ()
  "Sync org file to taskpaper file for mobile access"
  (when (eq buffer-file-name "~/path/to/org/file.org")
    (shell-command "python3 ~/path/to/python/script.py")))

(add-hook 'after-save-hook #'sync-to-taskpaper)

I am not getting any error messages when I save the file, it just is not running my custom function. Is it possible to do it this way, and if so, what am I missing? Thank you for your help!

elethan
  • 4,755
  • 3
  • 29
  • 56
  • Have you tried running just `(shell-command "python3 ~/path/to/python/script.py")` and does it do what you want? You can type `M-x eval-expression RET (shell-command "python3 ~/path/to/python/script.py") RET` – lawlist Jun 16 '15 at 15:39
  • Oh, good question! I just ran only that line of code from a \*scratch\* buffer using `eval-buffer` , and it did exactly what I want. The problem must be with my function then...`(when (eq buffer-file-name "~/path/to/org/file.org")` seemed to be the best thing I could come up with for "do this when the file in the buffer that I am saving is the file I want to run the script on", but I am not that confident that this is right. – elethan Jun 16 '15 at 15:44

1 Answers1

2

This is a mistake: (eq buffer-file-name "~/path/to/org/file.org").

Do not compare file names or any other strings using eq. See the Elisp manual, node Equality Predicates.

For strings, use string= or equal. For file names, use file-equal-p.

Here is another function that I also use to compare filenames, to see whether they reference the same file. It avoids accessing remote files when possible.

(defun same-file-p (file1 file2)
  "Return non-nil if FILE1 and FILE2 name the same file.
If either name is not absolute, then it is expanded relative to
`default-directory' for the test."
  (let ((remote1  (file-remote-p file1))
        (remote2  (file-remote-p file2)))
    (and (equal remote1 remote2)  (file-equal-p file1 file2))))
Drew
  • 75,699
  • 9
  • 109
  • 225
  • Thank you! I got it to work by comparing `buffer-file-name` to the org file path using `string=`. It took me a while though, because I just figured out that buffer-file-name returns the path to my file with `/home/username/` instead of `~/` ... – elethan Jun 16 '15 at 17:04
  • OK, but as my answer says, file names are specific thingies - they are not arbitrary *strings*. You are better off comparing them as file names, not just as strings. A common mistake, for example, is to manipulate them using functions such as `concat` and `substring`instead of file-name functions - see the Elisp manual, node [File-Names](http://www.gnu.org/software/emacs/manual/html_node/elisp/File-Names.html) and its children. You can compare file names (e.g. their components) or you can compare the files they point to. There are many file names that can reference the same file. – Drew Jun 16 '15 at 17:30
  • Got it. The documentation on `file-equal-p` is super brief, and my assumption was that it was comparing file objects or something like that. Lisp is so different from what I am used to in Python, at least from what I gather about it so far. Now I replaced `string=` in my function with `file-equal-p`, and it still works perfectly. Is this what you where suggesting? In other words, what I ended up with is `(file-equal-p buffer-file-name "home/username/path/to/file.org")`. When this evaluates as `t` it runs my script from the shell. – elethan Jun 16 '15 at 18:00
  • Yes, but it is for you to decide whether you want to use `file-equal-p`, which tests the referenced files to see if they are the same file, instead of, say, testing only the file names. You can test file names using the various file-name component functions, but in that case you may miss the fact that two very different file names correspond to the same file. Testing remote files, in particular, can be costly. If you can get away with a quick-&-dirty filename comparison it is cheaper. But it might not always DTRT. – Drew Jun 16 '15 at 19:49