Keyboard shortcuts in char run mode (ansi-term) in Emacs - shell

I use WindMove in Emacs 24.1 to move around multiple windows using keyboard shortcuts:
(global-set-key (kbd "M-J") 'windmove-left) ; move to window on the left
(global-set-key (kbd "M-L") 'windmove-right) ; move " " the right
(global-set-key (kbd "M-I") 'windmove-up) ; move " " above
(global-set-key (kbd "M-K") 'windmove-down); ; move " " below
Is there a way to associate these WindMove keyboard shortcuts with char run mode on an ansi-term? I would like to avoid having to switch into line run mode for moving between windows. After a while it becomes tedious to type C-c C-k and C-c C-j back and forth to go into/leave the terminal.

The code below will work for you. It uses the Emacs advising mechanism, which allows a user to dynamically change a function's behavior without modifying its source code directly. In this case, it is used to make the winmove-* functions run term-char-mode before executing their original definition. If you are also using other window-selecting functions, such as other-window, besides winmove-*, you can advise those functions in the same way. Refer to Advising Functions for details on the advising mechanism.
The code also handles the issue related to the term-raw-map keymap. term-raw-map is not defined until term.el is fully loaded (or M-xansi-term is executed). So you should add the (define-key term-raw-map ...) forms to the term-load-hook hook, which is automatically run when term.el is loaded, instead of putting them at the top level of the init file.
(global-set-key (kbd "M-J") 'windmove-left)
(global-set-key (kbd "M-L") 'windmove-right)
(global-set-key (kbd "M-I") 'windmove-up)
(global-set-key (kbd "M-K") 'windmove-down)
(defun ansi-term-char-mode ()
(if (string= (buffer-name) "*ansi-term*")
(term-char-mode)))
(defadvice windmove-left (before windmove-left-ansi-term (&optional arg))
(ansi-term-char-mode))
(defadvice windmove-right (before windmove-right-ansi-term (&optional arg))
(ansi-term-char-mode))
(defadvice windmove-up (before windmove-up-ansi-term (&optional arg))
(ansi-term-char-mode))
(defadvice windmove-down (before windmove-down-ansi-term (&optional arg))
(ansi-term-char-mode))
(add-hook 'term-load-hook
(lambda ()
(define-key term-raw-map (kbd "M-J") 'windmove-left)
(ad-activate 'windmove-left)
(define-key term-raw-map (kbd "M-L") 'windmove-right)
(ad-activate 'windmove-right)
(define-key term-raw-map (kbd "M-I") 'windmove-up)
(ad-activate 'windmove-up)
(define-key term-raw-map (kbd "M-K") 'windmove-down)
(ad-activate 'windmove-down)))

By default, term-char-mode forwards most keys to the terminal, without interpreting them within Emacs, which is why windmove keybindings are not working.
Here is a way to override the term-char-mode keymap to force windmove bindings to be interpreted instead of forwarded:
(eval-after-load "term"
'(progn
(define-key term-raw-map (kbd "M-J") 'windmove-left)
(define-key term-raw-map (kbd "M-L") 'windmove-right)
;; ...
))

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 windmove key in Mac

I set Alt as the windmove key to switch between frames in Emacs under Mac.
(windmove-default-keybindings 'meta)
This works fine for the GUI version Emacs (the one with the widgets and other windows decorations), but not if I start emacs with emacs -nw from a Mac Terminal.app. For example, if I split window first with C-x 2, and press Alt + <Down>, then Emacs reports
ESC + <Down> is undefined.
Can anyone help?
Emacs version is 24.4 installed from brew install.
It seems the easiest way is to just install iterm2. And in the Preferences > Profiles tab. Select your profile on the left, and then open the Keyd tab and set the option key to +ESC.
Then in your emacs setup set the key manually,
(global-set-key (kbd "ESC <up>") 'windmove-up)
(global-set-key (kbd "ESC <down>") 'windmove-down)
(global-set-key (kbd "ESC <right>") 'windmove-right)
(global-set-key (kbd "ESC <left>") 'windmove-left)
I suggest you to use iterm2 since it's a better terminal. But in case you want to use terminal.app don't forget to check the Use option as meta key in Preferences > Settings > Keyboard, it works to some extend with the default emacs.
The same issue is true for Ubuntu when I use terminator as a terminal.
You can work around this problem by using the win-switch package which works fine in every case for me. Here you have a simple configuration that you can put in your init file (.e.g.: .emacs):
;; install win-switch package using package manager
(if (package-installed-p 'win-switch)
nil
(package-install 'win-switch))
;; my favourite quick keybindings
(global-set-key (kbd "M-<left>") 'windmove-left)
(global-set-key (kbd "M-<right>") 'windmove-right)
(global-set-key (kbd "M-<up>") 'windmove-up)
(global-set-key (kbd "M-<down>") 'windmove-down)
The win-switch package has many other powerful utilities which are further detailed in the commentary part of the code.

How to rebind C-a and C-e in emacs back to Home and End on mac?

I am using logitech pc keyboard with my eMac and want to use Home and End buttons as usual. I've already rebound them for mac terminal. And want to rebind them in emacs as well.
Like this:
(global-set-key [home] 'move-beginning-of-line)
(global-set-key [end] 'move-end-of-line)
As for Terminal.app, its default key bindings grab Home and End for itself (to scroll to the beginning and end of the terminal output), and lets Shift-Home and Shift-End through to the application. You can switch this around in under "Settings" -> "Keyboard" in the Terminal preferences.
In your .emacs file put something like this:
(add-hook 'after-init-hook
'(lambda ()
(define-key global-map [C-home] 'beginning-of-buffer)
(define-key global-map [C-end] 'end-of-buffer)
(define-key global-map [home] 'beginning-of-line)
(define-key global-map [end] 'end-of-line)
;;; much more semi private stuff deleted
))
It works for me since ancient times.

Why don't Shift+arrow bindings work in clojure-mode in emacs terminal?

If I runs emacs in a terminal (i.e start emacs in iTerm2 with emacs -nw)
using windmove and it's default bindings, I should be able to navigate between windows using various combinations of Shift + → ← ↑ ↓, Also paredit has bindings that involve Ctrl/Meta + → ← ↑ ↓, these all work fine in (say) an elisp mode buffer.
Looks like the arrow keys functionality relies on emacs decoding terminal escape sequences, via (I think) the input-decode-map
However, if I set the major mode as clojure-mode then the decoding of the escape sequences appears to be disabled (or overwritten). When I execute those bindings I just get the escape sequence instead.
What's going on with the bindings in clojure-mode ?
Versions:
emacs 24.3.1 (have tried maxosxforemacs.com version and homebrew)
clojure-mode 20131117.2306 (have tried other versions)
OSX 10.8.5
iTerm2 1.0.0.20131124
(disclaimer: I raised this as an issue on clojure-mode, but no solution is forthcoming)
UPDATE 2013/12/10: To be absolutely clear: this problem is specific to clojure-mode. emacs -nw in iTerm + arrow keys works fine in other major modes. I'm sure I'm doing something silly that is causing this, I'd like to know what.
Almost identical setup here, but no similar problem. Here's what I would do anyway. First, evaluate the following emacs-lisp code in the scratch buffer.
(progn
(define-key input-decode-map "\e[1;2D" [S-left])
(define-key input-decode-map (kbd "M-[ 1 ; 2 C") [S-right])
(define-key input-decode-map (kbd "M-[ 1 ; 2 B")[S-down])
(define-key input-decode-map "\e[1;2A" [S-up])
(define-key input-decode-map "\e[1;6A" [S-C-up])
(define-key input-decode-map "\e[1;6B" [S-C-down]))
Try the windmove bindings when clojure-mode is activated. If this fixes your problem, and assuming your TERM environment variable is set to xterm-256color, put the following in your init.el
(if (equal "xterm-256color" (tty-type))
(progn
(define-key input-decode-map "\e[1;2D" [S-left])
(define-key input-decode-map (kbd "M-[ 1 ; 2 C") [S-right])
(define-key input-decode-map (kbd "M-[ 1 ; 2 B")[S-down])
(define-key input-decode-map "\e[1;2A" [S-up])
(define-key input-decode-map "\e[1;6A" [S-C-up])
(define-key input-decode-map "\e[1;6B" [S-C-down])))
Hope this helps.
Check your settings in Iterm, more specifically the "Global shortcut keys". Those will take precedence over what is sent to emacs. C-Shift-Arrow is used to switch tabs in Iterm I believe and may be interfering with emacs.

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,

Resources