0

I am editing a file on a remote server via Tramp, and I decide that I want to open up an ansi-term session on the remote server (as opposed to relying on shell-command). How do I do this? When I run ansi-term, it just opens up a new session on my local computer.

3
  • ansi-term is 'just' a terminal emulator, running on the local Emacs instance. Are you asking how to connect to a remote shell process (inside an ansi-term buffer) ?
    – phils
    Commented Mar 16, 2017 at 21:26
  • 3
    Possible duplicate of Honor default-directory in ansi-term
    – phils
    Commented Mar 18, 2017 at 11:49
  • You are right, phils. And what is shocking to myself: I answered there with the gnome-term solution and totally forgot about it.... so much about getting older.
    – dfeich
    Commented Mar 18, 2017 at 20:22

2 Answers 2

2

You can use the following function

(defun dfeich/ansi-terminal (&optional path name)
  "Opens an ansi terminal at PATH. If no PATH is given, it uses
the value of `default-directory'. PATH may be a tramp remote path.
The ansi-term buffer is named based on `name' "
  (interactive) 
  (unless path (setq path default-directory))
  (unless name (setq name "ansi-term"))
  (ansi-term "/bin/bash" name)
  (let ((path (replace-regexp-in-string "^file:" "" path))
    (cd-str 
     "fn=%s; if test ! -d $fn; then fn=$(dirname $fn); fi; cd $fn;")
    (bufname (concat "*" name "*" )))
    (if (tramp-tramp-file-p path)
    (let ((tstruct (tramp-dissect-file-name path)))
      (cond 
       ((equal (tramp-file-name-method tstruct) "ssh")
        (process-send-string bufname (format
                      (concat  "ssh -t %s '"
                           cd-str
                           "exec bash'; exec bash; clear\n")
                      (tramp-file-name-host tstruct)
                      (tramp-file-name-localname tstruct))))
       (t (error "not implemented for method %s"
             (tramp-file-name-method tstruct)))))
      (process-send-string bufname (format (concat cd-str " exec bash;clear\n")
                       path)))))

This code is also linked this gist. I have a similar gist for opening gnome-terminals at the current path (or any given path) here.

With the ansi terminal there may just some small but non-critical problem with the remote server not knowing the 'eterm-color' type. E.g. look at this stackoverflow question.

1
  • If you were keen, you could integrate emacs.stackexchange.com/q/18672 with your solution here, in order to directly run the ssh command in the terminal, as opposed to starting a local shell and then running commands in the local shell.
    – phils
    Commented Mar 16, 2017 at 22:02
2

I have implemented @phils suggestion based on the answer provided by @dfeich. The advantage is that without the local shell indirection, the terminal management is "instant".

(defun aratiu/terminal (&optional path name)
  "Opens a terminal at PATH. If no PATH is given, it uses
the value of `default-directory'. PATH may be a tramp remote path.
The term buffer is named based on `name' "
  (interactive)
  (require 'term)
  (unless path (setq path default-directory))
  (unless name (setq name "term"))
  (let ((path (replace-regexp-in-string "^file:" "" path))
        (cd-str "fn=%s; if test ! -d $fn; then fn=$(dirname $fn); fi; cd $fn; exec bash")
        (start-term (lambda (termbuf)
                      (progn
                        (set-buffer termbuf)
                        (term-mode)
                        (term-char-mode)
                        (switch-to-buffer termbuf)))))
    (if (tramp-tramp-file-p path)
        (let* ((tstruct (tramp-dissect-file-name path))
               (cd-str-ssh (format cd-str (tramp-file-name-localname tstruct)))
               (user (if (tramp-file-name-user tstruct)
                         (tramp-file-name-user tstruct)
                       user-login-name))
               (switches (list "-l" user
                               "-t" (tramp-file-name-host tstruct)
                               cd-str-ssh))
               (termbuf (apply 'make-term name "ssh" nil switches)))
          (cond
           ((equal (tramp-file-name-method tstruct) "ssh")
            (funcall start-term termbuf))
           (t (error "not implemented for method %s"
                     (tramp-file-name-method tstruct)))))
      (let* ((cd-str-local (format cd-str path))
             (termbuf (apply 'make-term name "/bin/sh" nil (list "-c" cd-str-local))))
        (funcall start-term termbuf)))))
2
  • I think you'll want to add "-l" (tramp-file-name-user tstruct) to your switches. I had a stab at something similar years ago but at the time I couldn't see how to generate the command in a way that could support multi-hop tramp connections, and I think this has the same problem; but it seems to work nicely otherwise.
    – phils
    Commented Dec 17, 2021 at 4:16
  • Thanks @phils, I added user handling to my function and updated the answer. It is true it does not work for multi-hop tramp connections, that is something I do not use personally very often, but I guess this function could be generalized a bit to chain ssh commands, shouldn't be to hard I guess, just needs someone willing to do it. :)
    – gimmesudo
    Commented Dec 17, 2021 at 11:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.