Is it possible to send an 'cd' command to xterm from emacs? - shell

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?

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))

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))))

Related

Mouse control when using emacs in tmux

I'm trying using Emacs and tmux in the Terminal.app, and having difficulty getting the mouse to work correctly.
If I use Emacs outside of tmux, then I can use the mouse to click on text to jump around the buffer.
However, if I am inside tmux, and I start editing a file in Emacs, then I can't click around. I have to do
M-x load-file ~/.emacs.d/init.el
.. to get it working.
Here is the content of my init.el
(require 'package) ;; You might already have this line
(when (< emacs-major-version 24)
;; For important compatibility libraries like cl-lib
(add-to-list 'package-archives '("gnu" . "http://stable.gnu.org/packages/")
'("melpa" . "http://melpa.org/packages/")))
(package-initialize) ;; You might already have this line
;; magit
(global-set-key (kbd "C-x g") 'magit-status)
(global-set-key (kbd "C-x M-g") 'magit-dispatch-popup)
(global-set-key (kbd "C-c SPC") 'ace-jump-mode)
;; mouse
;; enable mouse reporting for terminal emulators
(unless window-system
(xterm-mouse-mode 1)
(global-set-key [mouse-4] (lambda ()
(interactive)
(scroll-down 1)))
(global-set-key [mouse-5] (lambda ()
(interactive)
(scroll-up 1))))
..and my tmux.conf
set -g mouse on
bind X confirm-before kill-session
bind C-s set-window-option synchronize-panes
bind r source-file ~/.tmux.conf \; display "Reloaded!"
set -g window-active-style 'fg=colour250,bg=black'
bind -t emacs-copy C-WheelUpPane halfpage-up
bind -t emacs-copy C-WheelDownPane halfpage-down
# plugins
set -g #plugin 'nhdaly/tmux-scroll-copy-mode'
run '~/.tmux/plugins/tpm/tpm'
Versions
tmux version 2.1
emacsclient 24.5
macOS 10.11.4
This worked for me:
(xterm-mouse-mode 1)
https://unix.stackexchange.com/questions/252995/how-can-mouse-support-be-enabled-in-terminal-emacs/406519#406519

Emacs on mac: bind command-v to C-u M-! pbpaste

On Mac OS X, I want cmd-v to execute C-u M-! pbpaste.
I want to do this because it makes pasting a very large amount of text faster.
How can I define that binding in my .emacs file?
if you really, really want to do it simply add this to your .emacs
(defun my-pbpaste ()
(interactive)
(shell-command "pbpaste" t)
)
(global-set-key '[M-v] 'my-pbpaste)

Emacs shell mode open file in buffer

My setup:
Emacs terminal mode (emacs -nw)
inside it, use the shell mode (invoked with M-x ansi-term)
inside this shell, connect to a remote server with ssh
Suppose I'm browsing the remote server inside the shell and find a file I want to edit. Is there a command to open it as a parallel buffer/window?
The only method I know to open a file from the shell is to do emacs -nw again, which isn't quite convenient because a) I don't keep the shell open and b) it's really a different Emacs session, so for instance the "yank buffer" is different.
Edit: if there is a different/better way to work with a remote server with Emacs I'm just as interested; it's what I'm trying to do.
It's best to use tramp.
I have this shortcut (I call it with smex):
(defun connect-remote ()
(interactive)
(dired "/user#domain.com:/"))
This opens a dired buffer on the remote. You just use it as any dired buffer.
I've had a function to open a term from dired for a while, but I've
added an option to ssh from a tramp dired buffer just now:
(defun dired-open-term ()
"Open an `ansi-term' that corresponds to current directory."
(interactive)
(let ((current-dir (dired-current-directory)))
(term-send-string
(terminal)
(if (file-remote-p current-dir)
(let ((v (tramp-dissect-file-name current-dir t)))
(format "ssh %s#%s\n"
(aref v 1) (aref v 2)))
(format "cd '%s'\n" current-dir)))))
(defun terminal ()
"Switch to terminal. Launch if nonexistent."
(interactive)
(if (get-buffer "*terminal*")
(switch-to-buffer "*terminal*")
(term "/bin/bash")))
And this is the shortcut that I use:
(define-key dired-mode-map (kbd "`") 'dired-open-term)
You could use tramp from within your original emacs session to browse the remote server via ssh, using dired. Then, any remote file you open is opened in your local emacs session.
If you prefer to avoid dired and want to browse with a shell, you can prepend the remote location (/name#host:/path/from/pwd) to the file name. You can automate that with a function.

Copy/Paste in emacs ansi-term shell

I have configured my emacs to run zsh shell within ansi-term. However, copy/paste no longer works i.e. nothing is getting pasted from kill-ring to the terminal.
Changing the TERM to vt100, or eterm doesn't solve the problem.
Would appreciate any ideas or solution.
To provide context I have configured ansi-term as follows:
(global-set-key "\C-x\C-a" '(lambda ()(interactive)(ansi-term "/bin/zsh")))
(global-set-key "\C-x\ a" '(lambda ()(interactive)(ansi-term "/bin/zsh")))
You may want to simply switch between character mode and line mode while using the terminal. C-c C-j will run term-line-mode, which treats the terminal buffer more like a normal text-buffer in which you can move the cursor and yank text. You can switch back to character mode by running term-char-mode with C-c C-k.
As described in this lovely blog snippet, there's a function, term-paste, in term.el, that does exactly what you want. By default it's bound only to S-insert but the blog's recommended C-c C-y seems like a good suggestion.
ansi-term, in char-mode, takes the ordinary bindings for the terminal emulation. You need a new binding, plus a way to output to ansi-term correctly. I use this:
(defun ash-term-hooks ()
;; dabbrev-expand in term
(define-key term-raw-escape-map "/"
(lambda ()
(interactive)
(let ((beg (point)))
(dabbrev-expand nil)
(kill-region beg (point)))
(term-send-raw-string (substring-no-properties (current-kill 0)))))
;; yank in term (bound to C-c C-y)
(define-key term-raw-escape-map "\C-y"
(lambda ()
(interactive)
(term-send-raw-string (current-kill 0)))))
(add-hook 'term-mode-hook 'ash-term-hooks)
When you do this, C-c C-y will yank. It only does one yank, though, and you can't cycle through your kill-buffer. It's possible to do this, but I haven't implemented it yet.
The above solutions work well for copying text from some buffer to ansi-term, but they aren't able to copy text from ansi-term to another buffer (eg copy a command you just ran to a shell script you're editing). Adding this to my .emacs file solved that problem for me (in Emacs 24.4):
(defun my-term-mode-hook ()
(define-key term-raw-map (kbd "C-y") 'term-paste)
(define-key term-raw-map (kbd "C-k")
(lambda ()
(interactive)
(term-send-raw-string "\C-k")
(kill-line))))
(add-hook 'term-mode-hook 'my-term-mode-hook)
Note that if you want to bind kill/yank to a keystroke that starts with the ansi-term escape characters (by default C-c and C-x), and want this to work in the unlikely event that those change, you can instead define your keystrokes (without the leading escape) to term-raw-escape-map, as is done in user347585's answer.
These other solutions don't work well for me, switching between character mode and line mode causes ansi-term to stop working properly randomly, and setting ansi-term's term-paste to C-c C-y (based on Glyph's link), didn't work the code snippet was for term, not ansi-term:
(eval-after-load "ansi-term"
'(define-key ansi-term-raw-map (kbd "C-c C-y") 'term-paste))
I enabled xterm-mouse-mode, after that I was able to select text using mouse and copy using standard Mac command C button in ansi-term in emacs GUI in Mac OS X,

Opening browser from emacs script?

I have the following emacs lisp snippet that will launch my browser from within emacs and open the specified pages. However when I run it as a script from a shell nothing happens. What more do I need to do? I tried dropping (interactive).
#!/usr/bin/emacs --script
(defun surf-news ()
(interactive)
(progn
(browse-url "http://news.ycombinator.com")
(browse-url "http://stackoverflow.com")
))
(surf-news)
A neat function I discovered yesterday is M-x webjump which has recently been added to emacs.
As Ryan Thompson mentioned above, you can use xdg-open in Emacs.
Change:
(browse-url "http://news.ycombinator.com")
(browse-url "http://stackoverflow.com")
To:
(browse-url-xdg-open "http://news.ycombinator.com")
(browse-url-xdg-open "http://stackoverflow.com"))
I found the answer on this site, at the bottom, where it describes a Mac OS pty bug. I had to add this line and a slight delay between urls.
(setq process-connection-type nil)
Here's the complete solution.
#!/usr/bin/emacs --script
(setq process-connection-type nil);; pty's broken on the Mac
(defun surf ()
(progn
(browse-url "http://news.ycombinator.com")
(sleep-for 0.5); We need a delay
(browse-url "http://stackoverflow.com")
))
;;
;; This is what's going on behind the scenes
;;(setq url "http://www.google.com")
;;(start-process (concat "open " url) nil "open" url)
(surf)
On linux, if you are in GNOME, KDE, or probably almost any graphical environment, there is probably a command called xdg-open. This command basically takes its argument and opens it with the desktop default application. It handles both files and URLs. So generally when I need to say "Open this in the default application," I use xdg-open.
I think Mac OS has a similar command just called open.

Resources