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.

Andrew
  • 541
  • 6
  • 17
  • `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 Mar 16 '17 at 21:26
  • 3
    Possible duplicate of [Honor default-directory in ansi-term](http://emacs.stackexchange.com/questions/20877/honor-default-directory-in-ansi-term) – phils Mar 18 '17 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 Mar 18 '17 at 20:22

2 Answers2

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.

dfeich
  • 1,844
  • 16
  • 16
  • If you were keen, you could integrate http://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 Mar 16 '17 at 22:02
1

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)))))
gimmesudo
  • 111
  • 2
  • I think you'll want to add `"-l" (tramp-file-name-user tstruct)` to your switches. I had a stab at [something similar](https://emacs.stackexchange.com/a/21533) 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 Dec 17 '21 at 04: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 Dec 17 '21 at 11:14