Compiling from within Emacs based on an Emakefile
I tried some script by Alexey Lebedeff recently discussed on the Erlang mailing list, but at first try I did not manage to adapt the script to fit my needs. The situation got worse when I started to use non-Erlang source files such as templates and lexer / parser grammars which all get compiled to beam files and need to be reloaded when compilation was successful. After digging a bit into Emacs Lisp I came up with the following approach:
By pressing a function key (F13 in my case) emacs invokes via RPC at the Erlang application a custom compile command which in case of an Erlang source file switches to the directory of the Emakefile, runs a make:all([load]). and switches back to the original directory of the currently edited file. If the source file is a non-Erlang, than custom code gets called to perform all the necessary steps until beam file reloading.
There are two implications which need to be considered before adapting this approach:
- An application must contain specific code which can be called by emacs and that code must be able to determine the location of the Emakefile.
- The approach can't be used for initial compilation, because emacs calls a function from an application module, which must be compiled already.
(defun my-erlang-compile ()
(interactive)
(save-some-buffers (not compilation-ask-about-save) nil)
(save-excursion
(let ((thisdir default-directory))
(setq src-file-name buffer-file-name)
(with-current-buffer (get-buffer-create "*erl-output*")
(setq default-directory thisdir)
(erase-buffer)
(compilation-mode)
(toggle-read-only nil)
(setq compilation-current-error nil)
(display-buffer (current-buffer))
(erl-spawn
(erl-send-rpc (erl-target-node)
'distel
'eval_expression
(list (format "myapp_make:all(%S)." src-file-name)))
(erl-receive ()
((['rex ['ok string]]
(insert string))
(['rex ['error reason]]
(insert reason))
(other
(message "Unexpected: %S" other)))))))))
(add-hook 'erlang-mode-hook 'my-erlang-mode-hook)
(defun my-erlang-mode-hook ()
;; when starting an Erlang shell in Emacs, default in the node name
(setq inferior-erlang-machine-options '("-sname" "emacs"))
(define-key erlang-mode-map [f13]
(lambda () (interactive)
(progn
(my-erlang-compile))))
)
;; just to illustrate how to use custom erlang compilation
;; from within other modes
(add-hook 'foo-helper-mode-hook
(lambda ()
(define-key foo-helper-mode-map [f13]
(lambda () (interactive)
(progn
(my-erlang-compile))))))
With the elisp snippet from above, the corresponding Erlang application must contain a module myapp_make which implements the function all/1 :
all(Path) ->
case filename:extension(Path) of
".erl" ->
{ok, OldDir} = file:get_cwd(),
ok = file:set_cwd(my_find_emakefile_dir()),
make:all([load]),
ok = file:set_cwd(OldDir);
Ext ->
maybe_my_custom_stuff
end.
No comments:
Post a Comment