akermu / emacs-libvterm

Emacs libvterm integration
GNU General Public License v3.0
1.72k stars 137 forks source link

vterm and evil-mode #313

Open Sbozzolo opened 4 years ago

Sbozzolo commented 4 years ago

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

rynffoll commented 4 years ago

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

ghost commented 4 years ago

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.

chip2n commented 4 years ago

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.

Sbozzolo commented 4 years ago

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.

yosevu commented 4 years ago

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.

leodcs commented 4 years ago

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

jackmac92 commented 4 years ago

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

FrostyX commented 4 years ago

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.

ghost commented 4 years ago

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

yosevu commented 4 years ago

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

Sbozzolo commented 4 years ago

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.

wikoion commented 4 years ago

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 commented 4 years ago

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?

Sbozzolo commented 4 years ago

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?

wikoion commented 4 years ago

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.

Sbozzolo commented 4 years ago

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 commented 4 years ago

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.

wikoion commented 4 years ago

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

kongds commented 4 years ago

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)
blahgeek commented 4 years ago

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:

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

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

csheaff commented 4 years ago

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

jixiuf commented 3 years ago

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
cobac commented 3 years ago

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.

mjlbach commented 3 years ago

@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

akoppela commented 3 years ago

Evil mode works quite well for me in vterm.

mjlbach commented 3 years ago

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?

meliache commented 3 years ago

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))))
wvandeun commented 3 years ago

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

eeshugerman commented 3 years ago

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

tikudev commented 3 years ago

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

eeshugerman commented 3 years ago

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.

Can anyone comment on this? Sounds promising!

I'm curious how it would compare to term's term-line-mode. As I recall term-line-mode works pretty well with evil, but not great. I'm fuzzy on the details though as it's been a while since I used term and for some reason it's crashing when I try to run it right now.

chaoky commented 2 years ago

(vterm-goto-char (point)) was an easy solution for fixing the pointer location after moving with a command mode (evil/boon/fly-keys) which is the most annoying one

luveti commented 2 years ago

For those of us who don't want vterm ever messing with our cursor, we can use dynamic binding to prevent set_cursor_type from changing the cursor:

(advice-add #'vterm--redraw :around (lambda (fun &rest args) (let ((cursor-type cursor-type)) (apply fun args))))

Idea courtesy of /u/wasamasa on the emacs subreddit.

This should be cheaper than tiku91's work around.

mikefarmer01 commented 2 years ago

Where do I put this?

For those of us who don't want vterm ever messing with our cursor, we can use dynamic binding to prevent set_cursor_type from changing the cursor:

(advice-add #'vterm--redraw :around (lambda (fun &rest args) (let ((cursor-type cursor-type)) (apply fun args))))

Idea courtesy of /u/wasamasa on the emacs subreddit.

This should be cheaper than tiku91's work around.

eugercek commented 2 years ago

@luveti Thank you! It was a huge issue for me 🙏 Could you elaborate on why it's cheaper than tiku91's workaround.

chaoky commented 2 years ago

(vterm-goto-char (point)) was an easy solution for fixing the pointer location after moving with a command mode (evil/boon/fly-keys) which is the most annoying one

(defadvice! +vterm-update-cursor (orig-fn &rest args) :before #'vterm-send-key (vterm-goto-char (point)))

meliache commented 2 years ago

@chaoky

(defadvice! +vterm-update-cursor (orig-fn &rest args) :before #'vterm-send-key (vterm-goto-char (point)))

I don't have defadvice!, but I assume the nadvice.el version of that would be

  (define-advice vterm-send-key
      (:before (orig-fn &rest args) +vterm-update-cursor)
    (vterm-goto-char (point)))
edgar-vincent commented 2 years ago

Hello everyone,

Using a vanilla Emacs 28.1 configuration with only evil, evil-collection and vterm installed, I don't seem to be able to insert properly. This is what happens:

  1. M-x vterm
  2. insert-state is entered automatically.
  3. When type, nothing gets displayed, including after having pressed i.
  4. When I press Backspace, everything I typed in 3. suddenly gets displayed, with the point at the end of the line, as expected.
  5. I press RET.
  6. Same symptoms as 3.

I have the same issue under Doom Emacs, and have had it for as long as I can remember.

Has anyone experienced that?

Thanks a lot!

chaoky commented 2 years ago
(let ((cursor-type cursor-type)) (apply fun args))

yep ty, I forgot that's a macro from doom

chaoky commented 2 years ago

you can also add an advice for evil/flykeys/boon insert command like

(defadvice! +vterm-update-cursor-boon (orig-fn &rest args) :before #'boon-insert (vterm-goto-char (point)))

this could also be buffer local to vterm