4

In Emacs, I don't like shell-mode/eshell-mode since they cannot take full use of zsh and they suck much.

So I hope to use xterm as the external subprocess.

(global-set-key (kbd "M-<f2>")
                (lambda () (interactive)
                  (start-process "XTerm" nil "xterm")))

And now the PWD of xterm is synced with Emacs default-directory and the term is now a full-feathered one. But there is ONE problem: I the startup time of the sub-rountine is always disappointing.

So I hope starting xterm only once and when in Emacs, if it finds there is a subprocess called XTerm running, 1) switch to it 2)set the PWD of shell running in xterm to default-directory of Emacs.

Is it possible to do so?

If neither is possible, then with tmux, can we achieve this goal?

Hongxu Chen
  • 5,240
  • 2
  • 45
  • 85

2 Answers2

2

Here's my setup:

(defvar terminal-process)
(defun terminal ()
  "Switch to terminal. Launch if nonexistant."
  (interactive)
  (if (get-buffer "*terminal*")
      (switch-to-buffer "*terminal*")
    (term "/bin/bash"))
  (setq terminal-process (get-buffer-process "*terminal*")))

(global-set-key "\C-t" 'terminal)

Could you elaborate more on the start-up time? Mine is around 0.3s.

UPD A small snippet from my dired customization

I've got this in my dired setup:

(add-hook
 'dired-mode-hook
 (lambda()
   (define-key dired-mode-map (kbd "`")
     (lambda()(interactive)
       (let ((current-dir (dired-current-directory)))
         (term-send-string
          (terminal)
          (format "cd %s\n" current-dir)))))))

where terminal is:

(defun terminal ()
  "Switch to terminal. Launch if nonexistant."
  (interactive)
  (if (get-buffer "*terminal*")
      (switch-to-buffer "*terminal*")
    (term "/bin/bash"))
  (setq terminal-process (get-buffer-process "*terminal*")))

What this does is it opens a terminal for the same directory as dired buffer, reusing the existing *terminal*, or creating a new one if it's absent.

To summarize the answer to your question:

Yes, it's possible. It's done with:

(term-send-string
 (terminal)
 (format "cd %s\n" default-directory))
Community
  • 1
  • 1
abo-abo
  • 20,038
  • 3
  • 50
  • 71
  • I have almost the same snippet in my setup file, though I don't have anything like your `terminal-process` variable. What do you use it for? – François Févotte Jul 23 '13 at 15:14
  • In this snippet: `(term-simple-send terminal-process "clear")(term-simple-send terminal-process (buffer-file-name))`. Poor man's python eval:). – abo-abo Jul 23 '13 at 15:28
  • WARNING: what follows is a shameless self-advertisement... Have you looked at [isend-mode](https://github.com/ffevotte/isend-mode.el)? Tis is my own attempt at creating a language-agnostic way to interact with the interpreter living in a terminal buffer... – François Févotte Jul 23 '13 at 17:39
  • Actually I'm using terminal less and less these days. With stuff like `rgrep`, `magit` and `org-mode`'s babel I rarely need it. – abo-abo Jul 23 '13 at 17:50
  • @abo-abo Thanks. 2 more questions: 1) Can term-mode exactly work like a real emulator? 2) What if I hope a special command in shell(such as pressing a `q`) to `bury-buffer` or add a keymap to do so(I find that using `define-key term-mode-map` here doesn't work). – Hongxu Chen Jul 24 '13 at 00:50
  • @Francesco Until now I don't have much need for it but I think I will have a try since it looks really wonderful! – Hongxu Chen Jul 24 '13 at 00:56
  • @abo-abo What I miss is in `eshell` mode I can define an alias `q` to `bury-buffer`. – Hongxu Chen Jul 24 '13 at 00:57
  • @abo-abo I figure that for the second question it seems impossible since there is an additional `` needed to be input and binding `q`/`q ` would shadow the input of `q` itself. So I am using `(define-key term-raw-map (kbd "") 'bury-buffer)` instead. – Hongxu Chen Jul 24 '13 at 01:33
  • 1
    I didn't really get into this buffer-burying thing. I use `ido-switch-buffer` instead. It only makes sense to bury the buffer if the next one is the one you want. But `ido-switch-buffer` already gives you this next one as the default *with* an option to select a different one. Bind it to some really accessible keys, as it's very useful. – abo-abo Jul 24 '13 at 05:49
  • @abo-abo I use bury-buffer a lot since I am using evil-mode, and I just remap `q` in normal state with it so I only need to press `q` to get the previous buffer. – Hongxu Chen Jul 27 '13 at 03:52
0

If xterm is not a hard requirement, only that you somehow launch zsh from emacs, then take a look at AnsiTerm, or my preference, MultiTerm. They implement a terminal emulator (like xterm) in emacs, so you can run whatever terminal application (e.g. zsh) in a buffer. I like MultiTerm because it has better defaults IMO.

Then you can change directories with

(defun term-send-cd (&optional dir)
  (interactive "DDirectory: ")
  (let ((dir (if dir (expand-file-name dir) "")))
    (term-send-raw-string (format "cd '%s'\n" dir))))
jpkotta
  • 9,237
  • 3
  • 29
  • 34
  • Actually I find there is a problem in term-mode: the first line is omitted. This sucks when using `less` as the PAGER(`git log`, or `man`; I know they can be avoided with `magit`/`man/worman` inside Emacs, but I sometimes forget it) and search words inside it. – Hongxu Chen Jul 27 '13 at 03:56
  • That doesn't happen for me. I use multiterm and bash. I just tried with ansi-term and bash. I can start a pager, search for things, etc., and the first line is always there (unless I scroll the buffer). – jpkotta Jul 29 '13 at 15:29
  • I don't know why, but I guess it's because I add such a line "XTerm*internalBorder: 0" in `~/.Xresources`(the default value is 2). But I haven't ensured that. – Hongxu Chen Jul 29 '13 at 23:29