[erlang-patches] [PATCH] Make the Emacs Erlang mode TRAMP-aware when compiling

Tomas Abrahamsson <>
Wed Aug 21 22:35:28 CEST 2013

In Emacs it is possible to remotely edit a file, by opening for
example /ssh:somehost.com:/path/to/file.erl.  In Emacs, the feature
that makes this possible, is called TRAMP.  When compiling such a file,
by typing C-c C-k, an inferior Erlang shell is opened on the remote
host, but the compilation expression that was evaluated in the remote
Erlang shell was:

   c("/ssh:somehost.com:/path/to/file", [...]).

which resulted in a "no such file or directory" error.
This commit changes the compilation expression into:

   c("/path/to/file", [...]).

for files opened remotely via TRAMP.  The file name is adjusted
similarly when compiling .yrl and .xrl files.

In a buffer opened remotely, the Elisp function buffer-file-name
returns the full path with TRAMP syntax.  In this example it would
be "/ssh:somehost.com:/path/to/file.erl".  A new function,
erlang-local-buffer-file-name, has been introduced, which peels off
the TRAMP syntax on remotely opened files, while for locally opened
files, it just calls buffer-file-name.
 lib/tools/emacs/erlang.el | 44 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 37 insertions(+), 7 deletions(-)

diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index b5da9e7..6589047 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -5286,7 +5286,7 @@ There exists two workarounds for this bug:
   (let* ((dir (inferior-erlang-compile-outdir))
 ;;; (file (file-name-nondirectory (buffer-file-name)))
-	 (noext (substring (buffer-file-name) 0 -4))
+	 (noext (substring (erlang-local-buffer-file-name) 0 -4))
 	 (opts (append (list (cons 'outdir dir))
 		       (if current-prefix-arg
 			   (list 'debug_info 'export_all))
@@ -5324,7 +5324,7 @@ unless the optional NO-DISPLAY is non-nil."
 (defun inferior-erlang-compile-outdir ()
   "Return the directory to compile the current buffer into."
   (let* ((buffer-dir (directory-file-name
-		      (file-name-directory (buffer-file-name))))
+		      (file-name-directory (erlang-local-buffer-file-name))))
 	 (parent-dir (directory-file-name
 		      (file-name-directory buffer-dir)))
          (ebin-dir (concat (file-name-as-directory parent-dir) "ebin"))
@@ -5342,11 +5342,11 @@ unless the optional NO-DISPLAY is non-nil."
 	(res (inferior-erlang-compute-erl-compile-command module-name opts))
-    (if (not (null (buffer-file-name)))
+    (if (not (null (erlang-local-buffer-file-name)))
 	(while (and (not done) (not (null ccfn)))
 	  (setq ccfn-entry (car ccfn))
 	  (setq ccfn (cdr ccfn))
-	  (if (string-match (car ccfn-entry) (buffer-file-name))
+	  (if (string-match (car ccfn-entry) (erlang-local-buffer-file-name))
 	      (let ((c-fn (cdr ccfn-entry)))
 		(setq done t)
 		(if (not (null c-fn))
@@ -5378,7 +5378,7 @@ unless the optional NO-DISPLAY is non-nil."
 	 tmpvar tmpvar tmpvar2)))))
 (defun inferior-erlang-compute-leex-compile-command (module-name opts)
-  (let ((file-name        (buffer-file-name))
+  (let ((file-name        (erlang-local-buffer-file-name))
 	(erl-compile-expr (inferior-erlang-remove-any-trailing-dot
 			    module-name opts))))
@@ -5397,7 +5397,7 @@ unless the optional NO-DISPLAY is non-nil."
 (defun inferior-erlang-compute-yecc-compile-command (module-name opts)
-  (let ((file-name        (buffer-file-name))
+  (let ((file-name        (erlang-local-buffer-file-name))
 	(erl-compile-expr (inferior-erlang-remove-any-trailing-dot
 			    module-name opts))))
@@ -5448,6 +5448,36 @@ unless the optional NO-DISPLAY is non-nil."
       (setq strs (cdr strs)))
+(defun erlang-local-buffer-file-name ()
+  ;; When editing a file remotely via tramp,
+  ;; the buffer's file name may be for example
+  ;; "/ssh:host.example.com:/some/path/x.erl"
+  ;;
+  ;; If I try to compile such a file using C-c C-k, an
+  ;; erlang shell on the remote host is automatically
+  ;; started if needed, but for it to successfully compile
+  ;; the file, the c(...)  command that is sent must contain
+  ;; the file name "/some/path/x.erl" without the
+  ;; tramp-prefix "/ssh:host.example.com:".
+  (cond ((null (buffer-file-name))
+	 nil)
+	((erlang-tramp-remote-file-p)
+	 (erlang-tramp-get-localname))
+	(t
+	 (buffer-file-name))))
+(defun erlang-tramp-remote-file-p ()
+  (and (fboundp 'tramp-tramp-file-p)
+       (tramp-tramp-file-p (buffer-file-name))))
+(defun erlang-tramp-get-localname ()
+  (let ((tramp-info (tramp-dissect-file-name (buffer-file-name))))
+    (if (fboundp 'tramp-file-name-localname)
+	(tramp-file-name-localname tramp-info)
+      ;; In old versions of tramp, it was `tramp-file-name-path'
+      ;; instead of the newer `tramp-file-name-localname'
+      (tramp-file-name-path tramp-info))))
 ;; `next-error' only accepts buffers with major mode `compilation-mode'
 ;; or with the minor mode `compilation-minor-mode' activated.
 ;; (To activate the minor mode is out of the question, since it will
@@ -5482,7 +5512,7 @@ Capable of finding error messages in an inferior Erlang buffer."
   "Make the inferior Erlang change directory.
 The default is to go to the directory of the current buffer."
-  (or dir (setq dir (file-name-directory (buffer-file-name))))
+  (or dir (setq dir (file-name-directory (erlang-local-buffer-file-name))))
   (or (inferior-erlang-running-p)
       (error "No inferior Erlang is running"))

More information about the erlang-patches mailing list