1 Getting started with Elisp
This post will describe my first steps with Emacs Lisp and how to use it to communicate with an external process.
The little 'script' I implemented will:
- use the
inotifywaittools on Linux to monitor filesystem changes1.
- call a function to react to them.
As for all things Emacs, the Emacs documentation is incredibly detailed and very, very good and all informations in this post can be found (with a lot more information) in the documentation.
This post is simply a little write up of the most basic steps to get started.
It will cover the following steps:
- How to start a external program from Emacs.
- How to react to output generated from the started process.
2 Starting a process in Emacs
When deciding to start an external program there are two possibilities: either start a synchronous process or an asynchronous one.
As I want
inotifywait to keep running in the background, while
reacting to the output I have to start an external process using the
start-process function provided by emacs:
(start-process "some-name" ;; A name for the process "*buffer-to-write-output-into*" ;; A buffer the process can write to "inotifywait" ;; The command to run ;; Following are any arguments that are required by the command: "-m" "-e" "create" "<file_to_watch>")
It is important that the command-line arguments are passed as
variadic arguments, so if you want to apply this command to a list
of arguments you already have stored in a list you can simply use
(process (apply 'start-process "some-name" "*buffer-to-write-output-into*" "inotifywait" argument-list))
That is all there is to starting an asynchronous process in Emacs.
3 Reacting to output from the process
Reacting to output generated by the process is done using classic callbacks.
To register the callback-function with a process, you have to store
the return value of the
start-process call and register a callback
(defun callback-func (process msg) "Callback function need to accept two arguments: - the process that created the output. - the message containing the currently produced output." (message msg)) (let* ((arguments (list "-m" "-e" "create" "<filepath>")) (process (apply 'start-process "NOTIFYWAIT" "*notifywait*" "inotifywait" arguments))) (set-process-filter process 'callback-func))
Now all output generated by the
inotifywait-command will be send
callback and can be processed in whatever fashion required.
I wrote a little callback that will run all
nosetests for a
Python-project for example, as soon as a file under the
source-directory changes. You can find the source-code on Github.
If you are using Emacs ≥ 24.4 then cross-platform
inotify-functionality is included in Emacs. As both Debian and
OpenSUSE both still provide Emacs 24.3 however, I worked around this
with this small script.
If you know Python then you can think of
apply as being the
same as calling a function with