emacs-libvterm icon indicating copy to clipboard operation
emacs-libvterm copied to clipboard

vterm and evil-mode

Open Sbozzolo opened this issue 4 years ago • 40 comments

Many people use evil-mode, but unfortunately, I know almost nothing about it. It would be great to collect known problems/workarounds regarding vterm+evil and add them to the README. Help (PRs) would greatly be appreciated in this respect.

In general, it would also be useful to know what vterm can do to support evil-mode better.

Thanks

Sbozzolo avatar Apr 30 '20 04:04 Sbozzolo

evil-collection integrates with vterm. evil-collection/modes/vterm/evil-collection-vterm.el

rynffoll avatar May 03 '20 08:05 rynffoll

Some evil-mode user use the cursor's shape and color as evil-state indicator, for example:

(setq evil-insert-state-cursor '(bar "#00FF00")
      evil-visual-state-cursor '(box "#FF00FF")
      evil-normal-state-cursor '(box "#E2E8EF"))

will set the cursor as a green bar in insert state; a white box in normal state; a magenta box in visual state.

The problem with vterm is, sometimes it dose not respect the cursor shape. I don't know how to reproduce it consistently but sometimes after I leaved the vterm buffer then re-visit it, the cursor will change to bar shape while it should be a box shape.

ghost avatar May 06 '20 10:05 ghost

One annoyance I have is the following scenario:

  1. Enter insert mode, type some text
  2. Enter normal mode, move cursor back a bit
  3. Enter insert mode, start typing

When doing step 3, the cursor jumps back to the end of the line when typing. I guess vterm doesn't track the cursor in normal mode as it does in insert mode (moving in insert mode using arrow keys work fine).

Using normal mode, it's possible to move the cursor out of the prompt (like vterm-copy-mode), and in that case it makes sense that the cursor is reset when typing.

Ideally, when entering insert mode, the vterm cursor position should either be set to the current point if within the prompt, or to the last cursor position if outside it.

chip2n avatar Jul 14 '20 07:07 chip2n

One annoyance I have is the following scenario:

  1. Enter insert mode, type some text
  2. Enter normal mode, move cursor back a bit
  3. Enter insert mode, start typing

When doing step 3, the cursor jumps back to the end of the line when typing. I guess vterm doesn't track the cursor in normal mode as it does in insert mode (moving in insert mode using arrow keys work fine).

Using normal mode, it's possible to move the cursor out of the prompt (like vterm-copy-mode), and in that case it makes sense that the cursor is reset when typing.

Ideally, when entering insert mode, the vterm cursor position should either be set to the current point if within the prompt, or to the last cursor position if outside it.

Yes, we do not really support evil-mode at the moment. My understanding is that the most common way to have it with vterm is to set evil-mode to always use emacs-mode (in vterm buffers), then, the shell is configured with a VI emulation mode.

Sbozzolo avatar Jul 14 '20 12:07 Sbozzolo

One annoyance I have is the following scenario:

  1. Enter insert mode, type some text
  2. Enter normal mode, move cursor back a bit
  3. Enter insert mode, start typing

When doing step 3, the cursor jumps back to the end of the line when typing. I guess vterm doesn't track the cursor in normal mode as it does in insert mode (moving in insert mode using arrow keys work fine). Using normal mode, it's possible to move the cursor out of the prompt (like vterm-copy-mode), and in that case it makes sense that the cursor is reset when typing. Ideally, when entering insert mode, the vterm cursor position should either be set to the current point if within the prompt, or to the last cursor position if outside it.

Yes, we do not really support evil-mode at the moment. My understanding is that the most common way to have it with vterm is to set evil-mode to always use emacs-mode (in vterm buffers), then, the shell is configured with a VI emulation mode.

Would someone be able to point to an example of how to set this up?

I think I can figure out the "always use emacs-mode in vterm buffers" part, but how do I configure my shell for VI emulation? I'm using Oh My Zsh and vi-mode, which works in iTerm2, but I'm not sure how to get it to work in emacs vterm.

yosevu avatar Jul 19 '20 00:07 yosevu

Some evil-mode user use the cursor's shape and color as evil-state indicator, for example:

(setq evil-insert-state-cursor '(bar "#00FF00")
      evil-visual-state-cursor '(box "#FF00FF")
      evil-normal-state-cursor '(box "#E2E8EF"))

will set the cursor as a green bar in insert state; a white box in normal state; a magenta box in visual state.

The problem with vterm is, sometimes it dose not respect the cursor shape. I don't know how to reproduce it consistently but sometimes after I leaved the vterm buffer then re-visit it, the cursor will change to bar shape while it should be a box shape.

I have the same problem and I think I found a way to reproduce it.

  1. Enter insert mode
  2. List git branches on a git enabled folder using git branch
  3. Press q to exit git branch

After doing that, the cursor is shaped like it's on normal state, even though it's actually on insert state

leodcs avatar Jul 23 '20 19:07 leodcs

One annoyance I have is the following scenario:

  1. Enter insert mode, type some text
  2. Enter normal mode, move cursor back a bit
  3. Enter insert mode, start typing

When doing step 3, the cursor jumps back to the end of the line when typing. I guess vterm doesn't track the cursor in normal mode as it does in insert mode (moving in insert mode using arrow keys work fine). Using normal mode, it's possible to move the cursor out of the prompt (like vterm-copy-mode), and in that case it makes sense that the cursor is reset when typing. Ideally, when entering insert mode, the vterm cursor position should either be set to the current point if within the prompt, or to the last cursor position if outside it.

Yes, we do not really support evil-mode at the moment. My understanding is that the most common way to have it with vterm is to set evil-mode to always use emacs-mode (in vterm buffers), then, the shell is configured with a VI emulation mode.

Would someone be able to point to an example of how to set this up?

I think I can figure out the "always use emacs-mode in vterm buffers" part, but how do I configure my shell for VI emulation? I'm using Oh My Zsh and vi-mode, which works in iTerm2, but I'm not sure how to get it to work in emacs vterm.

@yosevu I have the opposite issue, could you share how you set it to always use emacs-mode in vterm buffers? Below are some links on how to setup vi emulation for your shell bash zsh

jackmac92 avatar Aug 12 '20 21:08 jackmac92

One annoyance I have is the following scenario:

  1. Enter insert mode, type some text
  2. Enter normal mode, move cursor back a bit
  3. Enter insert mode, start typing

When doing step 3, the cursor jumps back to the end of the line when typing. I guess vterm doesn't track the cursor in normal mode as it does in insert mode (moving in insert mode using arrow keys work fine).

Using normal mode, it's possible to move the cursor out of the prompt (like vterm-copy-mode), and in that case it makes sense that the cursor is reset when typing.

Ideally, when entering insert mode, the vterm cursor position should either be set to the current point if within the prompt, or to the last cursor position if outside it.

Does anyone please have some workaround for this? evil-mode is my main motivation for migrating my terminal from urxvt to emacs.

FrostyX avatar Aug 17 '20 14:08 FrostyX

One annoyance I have is the following scenario:

  1. Enter insert mode, type some text
  2. Enter normal mode, move cursor back a bit
  3. Enter insert mode, start typing

When doing step 3, the cursor jumps back to the end of the line when typing. I guess vterm doesn't track the cursor in normal mode as it does in insert mode (moving in insert mode using arrow keys work fine). Using normal mode, it's possible to move the cursor out of the prompt (like vterm-copy-mode), and in that case it makes sense that the cursor is reset when typing. Ideally, when entering insert mode, the vterm cursor position should either be set to the current point if within the prompt, or to the last cursor position if outside it.

Does anyone please have some workaround for this? evil-mode is my main motivation for migrating my terminal from urxvt to emacs.

We do, https://github.com/Sbozzolo/vterm-extra This pakcage provide a function that copy the current command line to a new buffer then when edit finished, replace the old command line with the new command line

ghost avatar Aug 17 '20 14:08 ghost

One annoyance I have is the following scenario:

  1. Enter insert mode, type some text
  2. Enter normal mode, move cursor back a bit
  3. Enter insert mode, start typing

When doing step 3, the cursor jumps back to the end of the line when typing. I guess vterm doesn't track the cursor in normal mode as it does in insert mode (moving in insert mode using arrow keys work fine). Using normal mode, it's possible to move the cursor out of the prompt (like vterm-copy-mode), and in that case it makes sense that the cursor is reset when typing. Ideally, when entering insert mode, the vterm cursor position should either be set to the current point if within the prompt, or to the last cursor position if outside it.

Yes, we do not really support evil-mode at the moment. My understanding is that the most common way to have it with vterm is to set evil-mode to always use emacs-mode (in vterm buffers), then, the shell is configured with a VI emulation mode.

Would someone be able to point to an example of how to set this up? I think I can figure out the "always use emacs-mode in vterm buffers" part, but how do I configure my shell for VI emulation? I'm using Oh My Zsh and vi-mode, which works in iTerm2, but I'm not sure how to get it to work in emacs vterm.

@yosevu I have the opposite issue, could you share how you set it to always use emacs-mode in vterm buffers? Below are some links on how to setup vi emulation for your shell bash zsh

I think evil-emacs-state-modes can be used for this purpose. I haven't tried it, but saw it discussed in this article: Living in Emacs

yosevu avatar Aug 23 '20 00:08 yosevu

I don't use evil, but I would expect the following to work:

(add-hook 'vterm-mode-hook (lambda () (setq evil-default-state 'emacs)))

This should force evil to be in the emacs state in vterm buffers, which in practice means that vi keybindings are disabled and you can enable them in your shell.

Sbozzolo avatar Aug 23 '20 14:08 Sbozzolo

Currently this works reasonably well:

(evil-define-key 'normal vterm-mode-map "h" 'vterm-send-left)
(evil-define-key 'normal vterm-mode-map "l" 'vterm-send-right)
(evil-define-key 'normal vterm-mode-map "b" 'vterm-send-M-b)
(evil-define-key 'normal vterm-mode-map "e" 'vterm-send-M-f)
(evil-define-key 'normal vterm-mode-map "db" 'vterm-send-C-w)
(evil-define-key 'normal vterm-mode-map "de" 'vterm-send-M-d)
(evil-define-key 'normal vterm-mode-map "p" 'vterm-yank)
(evil-define-key 'normal vterm-mode-map "P" '(lambda ()
                                               (interactive)
                                               (vterm-send-C-b)
                                               (vterm-yank)))

It's not a like for like replacement, but basic movement can be added like this. I think you could replace most of the functionality like this. Only thing I'm really missing is selections for visual mode, is there a vterm way to send C-Space to set a mark?

wikoion avatar Aug 24 '20 11:08 wikoion

Currently this works reasonably well:

(evil-define-key 'normal vterm-mode-map "h" 'vterm-send-left)
(evil-define-key 'normal vterm-mode-map "l" 'vterm-send-right)
(evil-define-key 'normal vterm-mode-map "b" 'vterm-send-M-b)
(evil-define-key 'normal vterm-mode-map "e" 'vterm-send-M-f)
(evil-define-key 'normal vterm-mode-map "db" 'vterm-send-C-w)
(evil-define-key 'normal vterm-mode-map "de" 'vterm-send-M-d)
(evil-define-key 'normal vterm-mode-map "p" 'vterm-yank)
(evil-define-key 'normal vterm-mode-map "P" '(lambda ()
                                               (interactive)
                                               (vterm-send-C-b)
                                               (vterm-yank)))

It's not a like for like replacement, but basic movement can be added like this. I think you could replace most of the functionality like this. Only thing I'm really missing is selections for visual mode, is there a vterm way to send C-Space to set a mark?

Okay this actually works as a solution to the visual mode deletion:

(evil-define-key 'visual vterm-mode-map "d" 'vterm-send-M-w)

I'll try and put together a complete set of bindings that you could add to the README or something?

wikoion avatar Aug 24 '20 13:08 wikoion

Currently this works reasonably well:

(evil-define-key 'normal vterm-mode-map "h" 'vterm-send-left)
(evil-define-key 'normal vterm-mode-map "l" 'vterm-send-right)
(evil-define-key 'normal vterm-mode-map "b" 'vterm-send-M-b)
(evil-define-key 'normal vterm-mode-map "e" 'vterm-send-M-f)
(evil-define-key 'normal vterm-mode-map "db" 'vterm-send-C-w)
(evil-define-key 'normal vterm-mode-map "de" 'vterm-send-M-d)
(evil-define-key 'normal vterm-mode-map "p" 'vterm-yank)
(evil-define-key 'normal vterm-mode-map "P" '(lambda ()
                                               (interactive)
                                               (vterm-send-C-b)
                                               (vterm-yank)))

It's not a like for like replacement, but basic movement can be added like this. I think you could replace most of the functionality like this. Only thing I'm really missing is selections for visual mode, is there a vterm way to send C-Space to set a mark?

Okay this actually works as a solution to the visual mode deletion:

(evil-define-key 'visual vterm-mode-map "d" 'vterm-send-M-w)

I'll try and put together a complete set of bindings that you could add to the README or something?

What is the difference between this approach and, say, this?

Sbozzolo avatar Aug 24 '20 20:08 Sbozzolo

Currently this works reasonably well:

(evil-define-key 'normal vterm-mode-map "h" 'vterm-send-left)
(evil-define-key 'normal vterm-mode-map "l" 'vterm-send-right)
(evil-define-key 'normal vterm-mode-map "b" 'vterm-send-M-b)
(evil-define-key 'normal vterm-mode-map "e" 'vterm-send-M-f)
(evil-define-key 'normal vterm-mode-map "db" 'vterm-send-C-w)
(evil-define-key 'normal vterm-mode-map "de" 'vterm-send-M-d)
(evil-define-key 'normal vterm-mode-map "p" 'vterm-yank)
(evil-define-key 'normal vterm-mode-map "P" '(lambda ()
                                               (interactive)
                                               (vterm-send-C-b)
                                               (vterm-yank)))

It's not a like for like replacement, but basic movement can be added like this. I think you could replace most of the functionality like this. Only thing I'm really missing is selections for visual mode, is there a vterm way to send C-Space to set a mark?

Okay this actually works as a solution to the visual mode deletion:

(evil-define-key 'visual vterm-mode-map "d" 'vterm-send-M-w)

I'll try and put together a complete set of bindings that you could add to the README or something?

What is the difference between this approach and, say, this?

The issue with that approach is that you have to disable evil mode for that to work properly, otherwise your escape key will trigger evil instead of zsh vi mode. When in emacs mode no evil bindings will work e.g. evil tab navigation, evil leader key binds. Personally I have most emacs navigation functions such as: kill window and buffer bound to leader combinations like ,kw. Copy and paste also becomes a bit of a nightmare of which shortcut do I use between these three modes.

wikoion avatar Aug 24 '20 21:08 wikoion

Currently this works reasonably well:

(evil-define-key 'normal vterm-mode-map "h" 'vterm-send-left)
(evil-define-key 'normal vterm-mode-map "l" 'vterm-send-right)
(evil-define-key 'normal vterm-mode-map "b" 'vterm-send-M-b)
(evil-define-key 'normal vterm-mode-map "e" 'vterm-send-M-f)
(evil-define-key 'normal vterm-mode-map "db" 'vterm-send-C-w)
(evil-define-key 'normal vterm-mode-map "de" 'vterm-send-M-d)
(evil-define-key 'normal vterm-mode-map "p" 'vterm-yank)
(evil-define-key 'normal vterm-mode-map "P" '(lambda ()
                                               (interactive)
                                               (vterm-send-C-b)
                                               (vterm-yank)))

It's not a like for like replacement, but basic movement can be added like this. I think you could replace most of the functionality like this. Only thing I'm really missing is selections for visual mode, is there a vterm way to send C-Space to set a mark?

Okay this actually works as a solution to the visual mode deletion:

(evil-define-key 'visual vterm-mode-map "d" 'vterm-send-M-w)

I'll try and put together a complete set of bindings that you could add to the README or something?

What is the difference between this approach and, say, this?

The issue with that approach is that you have to disable evil mode for that to work properly, otherwise your escape key will trigger evil instead of zsh vi mode. When in emacs mode no evil bindings will work e.g. evil tab navigation, evil leader key binds. Personally I have most emacs navigation functions such as: kill window and buffer bound to leader combinations like ,kw. Copy and paste also becomes a bit of a nightmare of which shortcut do I use between these three modes.

I see, thanks.

What about the following (temporary) solution: In vterm-extra, there is a command vterm-extra-edit-command-in-new-buffer. If you bind this function to a key, a new buffer appear where you can edit freely the command that will be sent to the terminal. The annoyance with this function is that for each command two additional keys have to pressed (one to enter in this mode, and one to leave it). What if I develop a similar minor-mode vterm-extra-minibuffer. With this minor mode, if you press enter on the prompt line in vterm buffers, you'll end up in the minibuffer, where you can use your evil commands, then, when you are done, you press enter again and the command is sent to the vterm buffer. When this minor mode is activated, this would be the only way to send commands to vterm.

I propose this because it should be an easy extension of what I already have in vterm-extra..

Sbozzolo avatar Aug 24 '20 21:08 Sbozzolo

I had another idea. This is a very minimal sketch of a new minor mode, which at the moment is called vterm-extra-line-mode.

(defvar vterm-extra-line-mode-map nil)
(setq vterm-extra-line-mode-map (make-sparse-keymap))

(define-key vterm-extra-line-mode-map (kbd "<return>")
  'vterm-extra-read-and-send)

(define-minor-mode vterm-extra-line-mode "VTermLine"
  "Vterm extra line mode."
  (read-only-mode -1))

(defun vterm-extra-read-and-send ()
  (interactive)
  (let ((command (buffer-substring-no-properties
                 (vterm--get-prompt-point) (vterm--get-end-of-line))))
    (vterm-send-C-a)
    (vterm-send-C-k)
    (vterm-send-string command)
    (vterm-send-return)))

With this minor mode, the buffer is turned into writable, and you can use any evil command. When you hit enter, what is on screen is sent to vterm.

There's A LOT to be polished, but I think that this may be the core idea to enable using evil in the smoothest way. The idea is to send the updated string every time there's some interaction with the term, like hitting tab.

I am going to develop this as part of vterm-extra initially.

Sbozzolo avatar Aug 29 '20 03:08 Sbozzolo

I had another idea. This is a very minimal sketch of a new minor mode, which at the moment is called vterm-extra-line-mode.

(defvar vterm-extra-line-mode-map nil)
(setq vterm-extra-line-mode-map (make-sparse-keymap))

(define-key vterm-extra-line-mode-map (kbd "<return>")
  'vterm-extra-read-and-send)

(define-minor-mode vterm-extra-line-mode "VTermLine"
  "Vterm extra line mode."
  (read-only-mode -1))

(defun vterm-extra-read-and-send ()
  (interactive)
  (let ((command (buffer-substring-no-properties
                 (vterm--get-prompt-point) (vterm--get-end-of-line))))
    (vterm-send-C-a)
    (vterm-send-C-k)
    (vterm-send-string command)
    (vterm-send-return)))

With this minor mode, the buffer is turned into writable, and you can use any evil command. When you hit enter, what is on screen is sent to vterm.

There's A LOT to be polished, but I think that this may be the core idea to enable using evil in the smoothest way. The idea is to send the updated string every time there's some interaction with the term, like hitting tab.

I am going to develop this as part of vterm-extra initially.

This sounds like an ideal solution! Can you link to the branch in vterm-extra so I can try it out when there is some done? :)

wikoion avatar Sep 05 '20 08:09 wikoion

One annoyance I have is the following scenario:

  1. Enter insert mode, type some text
  2. Enter normal mode, move cursor back a bit
  3. Enter insert mode, start typing

When doing step 3, the cursor jumps back to the end of the line when typing. I guess vterm doesn't track the cursor in normal mode as it does in insert mode (moving in insert mode using arrow keys work fine). Using normal mode, it's possible to move the cursor out of the prompt (like vterm-copy-mode), and in that case it makes sense that the cursor is reset when typing. Ideally, when entering insert mode, the vterm cursor position should either be set to the current point if within the prompt, or to the last cursor position if outside it.

Yes, we do not really support evil-mode at the moment. My understanding is that the most common way to have it with vterm is to set evil-mode to always use emacs-mode (in vterm buffers), then, the shell is configured with a VI emulation mode.

Would someone be able to point to an example of how to set this up? I think I can figure out the "always use emacs-mode in vterm buffers" part, but how do I configure my shell for VI emulation? I'm using Oh My Zsh and vi-mode, which works in iTerm2, but I'm not sure how to get it to work in emacs vterm.

@yosevu I have the opposite issue, could you share how you set it to always use emacs-mode in vterm buffers? Below are some links on how to setup vi emulation for your shell bash zsh

I think evil-emacs-state-modes can be used for this purpose. I haven't tried it, but saw it discussed in this article: Living in Emacs

This piece of code can roughly handle this problem. After insert command, just moving shell point to the current point.

(defun evil-collection-vterm-insert (count &optional vcount skip-empty-lines)
  (interactive
   (list (prefix-numeric-value current-prefix-arg)
         (and (evil-visual-state-p)
              (memq (evil-visual-type) '(line block))
              (save-excursion
                (let ((m (mark)))
                  ;; go to upper-left corner temporarily so
                  ;; `count-lines' yields accurate results
                  (evil-visual-rotate 'upper-left)
                  (prog1 (count-lines evil-visual-beginning evil-visual-end)
                    (set-mark m)))))
         (evil-visual-state-p)))
  (evil-insert count vcount skip-empty-lines)
  (let ((p (point)))
    (vterm-reset-cursor-point)
    (while (< p (point))
      (vterm-send-left)
      (forward-char -1))
    (while (> p (point))
      (vterm-send-right)
      (forward-char 1))))
(evil-collection-define-key 'normal 'vterm-mode-map "i" 'evil-collection-vterm-insert)

kongds avatar Oct 10 '20 08:10 kongds

I don't think it's reasonable for vterm to support some vi mode keybindings for the shell. It's what the shell itself should do (bash, zsh, fish, etc. all supports some vi editing mode). It's like that it's not reasonable for iTerm2.app or urxvt to support vi mode keybindings. Vterm as a terminal emulator, does not (and should not) know anything about the content of it's program, which may not even be a shell.

vterm and shell works in two separated layers and evil works at the vterm layer. Vterm (maybe together with evil) provides raw keystroke input to shell and inspects the output of the shell.

Some good integration features between evil and vterm would be:

  • evil command "p" (paste) will send the content in kill ring as raw keystrokes to vterm
  • enter evil insert state (from normal state) will place the cursor at the correct position
  • provide better ways to define custom keybindings for vterm with evil

Some bad integration features between evil and vterm that we probably should not implement:

  • evil command "d" to delete current shell command line
  • evil command "a" to go to the beginning of the line of current line editing

For these feature requirements, people should look for "vterm custom keybindings" instead of "vterm evil integration"

blahgeek avatar Oct 15 '20 04:10 blahgeek

Hi, a solution that would work for alternative modal editing schemes, such as xah-fly-keys, would be much appreciated.

csheaff avatar Oct 22 '20 11:10 csheaff

after #455 is merged, command d c a I should work with:

(defun vterm-evil-insert ()
  (interactive)
  (vterm-goto-char (point))
  (call-interactively #'evil-insert))

(defun vterm-evil-append ()
  (interactive)
  (vterm-goto-char (1+ (point)))
  (call-interactively #'evil-append))

(defun vterm-evil-delete ()
  "Provide similar behavior as `evil-delete'."
  (interactive)
  (let ((inhibit-read-only t)
        )
    (cl-letf (((symbol-function #'delete-region) #'vterm-delete-region))
      (call-interactively 'evil-delete))))

(defun vterm-evil-change ()
  "Provide similar behavior as `evil-change'."
  (interactive)
  (let ((inhibit-read-only t))
    (cl-letf (((symbol-function #'delete-region) #'vterm-delete-region))
      (call-interactively 'evil-change))))

(defun my-vterm-hook()
  (evil-local-mode 1)
  (evil-define-key 'normal 'local "a" 'vterm-evil-append)
  (evil-define-key 'normal 'local "d" 'vterm-evil-delete)
  (evil-define-key 'normal 'local "i" 'vterm-evil-insert)
  (evil-define-key 'normal 'local "c" 'vterm-evil-change))

(add-hook 'vterm-mode-hook 'my-vterm-hook)

EDIT: d c should not work when your evil is byte compiled , see https://github.com/emacs-evil/evil-collection/pull/448#issuecomment-770144854 please use https://github.com/emacs-evil/evil-collection/blob/master/modes/vterm/evil-collection-vterm.el instead.

And vterm-delete-region doesn't work for zsh user, you need put this in your .zshrc,

# bind  DEL to delete-char  make `vterm-send-delete` delete char
bindkey "\e[3~" delete-char

jixiuf avatar Dec 04 '20 15:12 jixiuf

Hey, thanks for all the work.

I'm running master with evil-collection and @jixiuf 's snippets.

Some observations and problem reports:

  1. Insert command works as expected.
  2. Append command works as expected, but there is a cursor position issue.
  • Normal mode: ab[c]de ->
  • Press 'a' ->
    • Cursor shows after 'd': abcd|e ->
  • Start typing X -> - The cursor moves and the input in inserted in the correct position: abcXX|de
  1. Delete and change do not work.
  • The visual selection is deleted
  • But as soon as I start typing again the line is restored to the previous state and I'm typing at the end of the line.
  • @mjlbach talks about the same issue in https://github.com/hlissner/doom-emacs/pull/4373#issuecomment-739464602, although they seem to have solved the issue (?) It doesn't work for me.

I've added the following to my configuration and it might be useful to others.

(defun vterm-evil-append-line ()
    "Provide similar behavior as `evil-append-line'."
    (interactive)
    (let ((inhibit-read-only t))
      (vterm-end-of-line)
      (vterm-evil-append)))

and then add (evil-define-key 'normal 'local "A" 'vterm-evil-append-line) to the hook.

I've tried to define vterm-evil-insert-line too, but I can't get vterm-beggining-of-line to work, not even in Emacs mode.

Thanks again everyone.

cobac avatar Jan 28 '21 18:01 cobac

@cobac I haven't gotten it working, I instead am trying to merge these changes upstream in evil-collection https://github.com/emacs-evil/evil-collection/pull/448

Note, I have a minimum test-case now where delete-region works/doesn't work. See: https://github.com/emacs-evil/evil-collection/pull/448#issuecomment-768765408

mjlbach avatar Jan 28 '21 18:01 mjlbach

Evil mode works quite well for me in vterm.

akoppela avatar Apr 01 '21 04:04 akoppela

I bound a bunch of additional emacs-libvterm functions in evil collection: https://github.com/emacs-evil/evil-collection/pull/448

And there was recently a follow-up PR which was recently merged: https://github.com/emacs-evil/evil-collection/pull/461

I'm not sure what remains to be done?

mjlbach avatar Apr 01 '21 04:04 mjlbach

I'll post here a tip for users like me who don't need evil on the command line, but really would like to have it in copy-mode, which is also the behaviour that I use in the copy modes in tmux/alacritty. The vterm-mopy-mode-hook is called for for both entering or exiting the mode, so I came up with the following use-package declaration:

(use-package vterm
  :hook
  (vterm-mode . evil-emacs-state)
  (vterm-copy-mode . meliache/evil-normal-in-vterm-copy-mode)
  :config
  (defun meliache/evil-normal-in-vterm-copy-mode ()
    (if (bound-and-true-p vterm-copy-mode)
        (evil-normal-state)
      (evil-emacs-state))))

meliache avatar Apr 01 '21 11:04 meliache

I still seem to have issues when I ssh to another host from within vterm. Haven't debugged or looked into it to much yet...

wvandeun avatar Apr 01 '21 13:04 wvandeun

I just tried out shell-mode for the first time in a while and the evil integration there is seamless! Anyone know how it works and if the same approach could be applied to vterm? Is it because it's comint-derived?

@mjlbach I really appreciate your evil-collection contribution -- it allowed me to switch from ZSH's vi emulation. But I think re-implementing evil operators one by one is ultimately a losing battle: we'll always be lagging behind, missing features, duplicating effort, etc, and users' customized evil bindings don't carry over. I don't have a better idea though 😞 (unless, again, we can somehow do what comint/shell does, which seems unlikely but idk).

eeshugerman avatar Jun 23 '21 17:06 eeshugerman

Some evil-mode user use the cursor's shape and color as evil-state indicator, for example:

(setq evil-insert-state-cursor '(bar "#00FF00")
      evil-visual-state-cursor '(box "#FF00FF")
      evil-normal-state-cursor '(box "#E2E8EF"))

will set the cursor as a green bar in insert state; a white box in normal state; a magenta box in visual state.

The problem with vterm is, sometimes it dose not respect the cursor shape. I don't know how to reproduce it consistently but sometimes after I leaved the vterm buffer then re-visit it, the cursor will change to bar shape while it should be a box shape.

For me this is reproducible with a simple ls command. After ls I am still in insert mode but the cursor shows normal mode. Here is a fix I found:

(use-package vterm
  :config
  (advice-add #'vterm--redraw :after (lambda (&rest args) (evil-refresh-cursor evil-state)))
)

I hope this is helpful to some :)

tikudev avatar Jun 24 '21 10:06 tikudev