In term-mode I've configured the keybindings for term-line-mode and term-char-mode as follows:
(setq term-bind-key-alist (list (cons "C-c C-j" '(lambda () (interactive) (term-line-mode) (evil-normal-state))) (cons "C-c C-k" '(lambda () (interactive) (term-char-mode) (evil-emacs-state) (end-of-buffer))) This gives the expected behavior when I type "C-c C-j" but only term-char-mode seems to be called when I type "C-c C-k". All of them are called if I type "C-c C-k" for a 2nd time. How can I get them to work on the first key press?
Edit 1
Here's the full configuration for term. Also, I mistakenly thought that this is a variable for term-mode, when it's actually a variable defined in multi-term. However, if I place this in the multi-term configuration it produces the same behavior
(use-package term :after helm :config (defun expose-global-binding-in-term (binding) (define-key term-raw-map binding (lookup-key (current-global-map) binding))) (expose-global-binding-in-term (kbd "C-x")) (define-key term-raw-map (kbd "M-x") 'helm-M-x) (setq term-scroll-to-bottom-on-output t) (setq term-scroll-show-maximum-output t)) (use-package multi-term :bind (("<C-next>" . multi-term-next) ("<C-prior>" . multi-term-prev) ("<f1>" . multi-term)) :config (require 'multi-term-ext) (setq multi-term-program "/bin/bash") (setq term-bind-key-alist (list (cons "C-c C-c" 'term-interrupt-subjob) (cons "C-z" 'term-stop-subjob) (cons "C-l" 'term-send-raw) (cons "C-r" 'term-send-raw) (cons "C-s" 'term-send-raw) (cons "M-f" 'term-send-forward-word) (cons "M-b" 'term-send-backward-word) (cons "C-c C-j" '(lambda () (interactive) (term-line-mode) (evil-normal-state))) (cons "C-c C-k" '(lambda () (interactive) (evil-emacs-state) (term-char-mode) (end-of-buffer))) (cons "M-DEL" 'term-send-backward-kill-word) (cons "M-d" 'term-send-forward-kill-word) (cons "<C-left>" 'term-send-backward-word) (cons "<C-right>" 'term-send-forward-word) (cons "C-y" 'term-paste)))) Edit 2
I've modified the multi-term configuration so that these keybindings are outside of term-bind-key-alist but I'm still getting the same behavior.
(use-package multi-term :bind (("<C-next>" . multi-term-next) ("<C-prior>" . multi-term-prev) ("<f1>" . multi-term) ("C-c C-j" . (lambda () (interactive) (term-line-mode) (evil-normal-state))) ("C-c C-k" . (lambda () (interactive) (evil-emacs-state) (term-char-mode) (end-of-buffer)))) :config (require 'multi-term-ext) (setq multi-term-program "/bin/bash") (setq term-bind-key-alist (list (cons "C-c C-c" 'term-interrupt-subjob) (cons "C-z" 'term-stop-subjob) (cons "C-l" 'term-send-raw) (cons "C-r" 'term-send-raw) (cons "C-s" 'term-send-raw) (cons "M-f" 'term-send-forward-word) (cons "M-b" 'term-send-backward-word) (cons "M-DEL" 'term-send-backward-kill-word) (cons "M-d" 'term-send-forward-kill-word) (cons "<C-left>" 'term-send-backward-word) (cons "<C-right>" 'term-send-forward-word) (cons "C-y" 'term-paste)))) Edit 3
The version below now works. The trick, as pointed out by Phil in his answer, is that term-bind-key-alist doesn't bind keys for term-mode-map (used by term-line-mode). I believe it only binds keys for term-raw-map, or some combination of that and term-raw-escape-map. The reason that term-char-mode was still called (and the other two functions weren't) when using "C-c C-k" in term-line-mode was that it's the default keybinding in term-line-mode.
(use-package term :after (helm evil) :bind (:map term-mode-map ("C-c C-k" . (lambda () (interactive) (evil-emacs-state) (term-char-mode) (goto-char (point-max))))) :config (defun expose-global-binding-in-term (binding) (define-key term-raw-map binding (lookup-key (current-global-map) binding))) (expose-global-binding-in-term (kbd "C-x")) (define-key term-raw-map (kbd "M-x") 'helm-M-x) (setq term-scroll-to-bottom-on-output t) (setq term-scroll-show-maximum-output t)) (use-package multi-term :bind (("<C-next>" . multi-term-next) ("<C-prior>" . multi-term-prev) ("<f1>" . multi-term)) :config (require 'multi-term-ext) (setq multi-term-program "/bin/bash") (setq term-bind-key-alist (list (cons "C-c C-c" 'term-interrupt-subjob) (cons "C-z" 'term-stop-subjob) (cons "C-l" 'term-send-raw) (cons "C-r" 'term-send-raw) (cons "C-s" 'term-send-raw) (cons "M-f" 'term-send-forward-word) (cons "M-b" 'term-send-backward-word) ;; I've defined "C-c C-k" in term's configuration since it must be defined in ;; term-mode-map. It could be placed here as a define-key in config, but this way we ;; get to keep use-package's typical syntax. (cons "C-c C-j" '(lambda () (interactive) (term-line-mode) (evil-normal-state))) (cons "M-DEL" 'term-send-backward-kill-word) (cons "M-d" 'term-send-forward-kill-word) (cons "<C-left>" 'term-send-backward-word) (cons "<C-right>" 'term-send-forward-word) (cons "C-y" 'term-paste))))