156

I would like to know how to change, if possible, the cursor in Vim (in color, shape, etc.) depending on what mode you are in.

I am constantly forgetting that I am not in Insert mode and start typing code, which results in all sorts of crazy things happening. It would be helpful if there was some sort of visual indication on the cursor.

ib.
  • 27,830
  • 11
  • 80
  • 100
lanrat
  • 4,344
  • 10
  • 35
  • 41
  • 29
    I suggest you to learn one rule: stopped typing => exit insert mode. Then you will never observe a situation where you forgot that you are not in insert mode. – ZyX Jun 28 '11 at 15:29
  • 6
    @ZyX *except* when you forget to exit the insert mode after having stopped typing :p – gented May 09 '20 at 10:10
  • 12
    @ZyX that's a fine rule and I have always done that, but visual indicators are still important. Marijuana is legal now and I forget what I'm doing all the time. – felwithe Jun 17 '20 at 13:42

12 Answers12

153

The following works in xterm, urxvt, and other terminal emulators on Linux; iTerm2 on macOS; Git Bash with ConEmu on Windows; and more (see comments):

let &t_SI = "\e[6 q"
let &t_EI = "\e[2 q"

" reset the cursor on start (for older versions of vim, usually not required)
augroup myCmds
au!
autocmd VimEnter * silent !echo -ne "\e[2 q"
augroup END

Other options (replace the number after \e[):

Ps = 0  -> blinking block.
Ps = 1  -> blinking block (default).
Ps = 2  -> steady block.
Ps = 3  -> blinking underline.
Ps = 4  -> steady underline.
Ps = 5  -> blinking bar (xterm).
Ps = 6  -> steady bar (xterm).

When you use tmux, it is important to use it like that (without the \<Esc>Ptmux; escape). tmux will keep track of the correct cursor shape when you switch windows/panes.

If it does not work for you, try either to set TERM=xterm-256color before starting tmux, or add this to your .tmux.conf (thanks @Steven Lu):

set -ga terminal-overrides ',*:Ss=\E[%p1%d q:Se=\E[2 q'
laktak
  • 57,064
  • 17
  • 134
  • 164
  • 4
    Works great in alacritty now – Steven Lu Dec 12 '17 at 22:16
  • Works perfect in xfce4-terminal – korst1k Dec 25 '17 at 16:04
  • @Charles About why it does not work in putty, see this: https://superuser.com/questions/304318/over-windows-terminal-change-cursor-width-or-color-in-vim-depending-on-mode – WesternGun Apr 26 '18 at 16:14
  • Works great with Kitty. However the 'optional reset cursor on start' code produces this jumble of characters in the command section at the bottom whenever you start vim. ^[[2;2R^[[>1;4000;13c^[]10;rgb:dddd/eeee/dddd^[\^[]11;rgb:1c1c/1c1c/1c1c^[\ Any fixes for this? – Ingadi Mar 31 '19 at 14:52
  • @MartianTomatoes Append `autocmd VimEnter * redraw!` to the `augroup`. –  Apr 26 '19 at 01:35
  • Using iterm and VIM8 there's a delay when going back to normal mode from insert. The cursor also remains after exiting vim. – DannyDannyDanny May 02 '19 at 13:52
  • Works on Linux (TERM=rxvt-unicode-256color) without tmux but not inside tmux :( – Agis Jun 07 '19 at 13:41
  • I realized this actually totally does not work for me in any terminal within tmux, on Ubuntu or macOS Mojave. I have been using the other answer with the Ptmux; escape, which makes it function transparently for tmux, and is not ideal. – Steven Lu Sep 30 '19 at 14:52
  • 1
    My Update: working finally with `set -ga terminal-overrides ',*:Ss=\E[%p1%d q:Se=\E[2 q'` in my tmux configuration. Apparently if you use `set` for `terminal-overrides` without `-a`, it will override the setting, which already has this there by default. – Steven Lu Sep 30 '19 at 17:09
  • Works perfectly on Tilix – mantish Mar 11 '20 at 03:28
  • 2
    the solution has a significant delay of changing shape from insert mode to normal mode on simple terminal (suckless st) – daGo Mar 23 '20 at 20:05
  • What should happen if we do not reset the cursor on start? –  Oct 06 '20 at 18:57
  • The tmux bit is very enlightening! Thanks a lot! – Gordon Bai Mar 12 '21 at 12:15
  • and for GNU screen you need to wrap it in `\eP` teriminal code `\e\\ ` . – Mikhail Modin Aug 24 '21 at 09:32
  • Thanks. I have added these lines to my /etc/vim/vimrc file – Liker777 Apr 19 '22 at 09:44
  • works great in Spacevim running on ITerm (MacOS) – Odohi David Jun 28 '22 at 12:17
134

A popular approach to indicate switching to and from Insert mode is toggling the cursorline option, which is responsible for whether the current screen line is highlighted (see :help cursorline):

:autocmd InsertEnter * set cursorline
:autocmd InsertLeave * set nocursorline

or, alternatively:

:autocmd InsertEnter,InsertLeave * set cul!

Modify the CursorLine highlighting group to change the styling of the cursor line to your liking (see :help :highlight and :help highlight-groups).

This approach assumes, of course, that you do not use the cursor line highlighting in Normal mode.

ib.
  • 27,830
  • 11
  • 80
  • 100
  • 9
    I also set cul to higlight bg instead of default underline: hi CursorLine cterm=NONE ctermbg=black – Niki Tonsky Nov 10 '11 at 08:21
  • 1
    Is there a reason this wouldn't work in cygwin's vim? I'm in the editor and entered both set of lines, and I haven't been able to set any sort of highlighting, beyond the full column or row highligting – TankorSmash Jul 09 '12 at 17:26
  • 1
    @Tankor: The `cursorline` option does not depend on any platform-specific capability; it is available on any Vim instance compiled with the `+syntax` feature (which is usually the case). – ib. Jan 15 '14 at 05:52
  • 1
    Of course, save that to your ~/.vimrc for permanence like zo: `echo 'autocmd InsertEnter,InsertLeave * set cul!' >>~/.vimrc` – alchemy Jun 01 '20 at 00:17
31

Not sure if anyone else is facing a delay after hitting the Esc key to go back to normal mode to show the block cursor but if so, this is the way I fix it too.

Actually I'm using iTerm2 and using Vim inside my terminal on macOS. And when entering to insert mode, the cursor still being a block and is kind of confusing when you are at insert mode or normal mode.

I wanted to show a thin line as cursor when in insert mode and back to block when in normal mode as MacVim does. And to do so it's pretty simple, just added this to my .vimrc file as described here:

let &t_SI = "\<Esc>]50;CursorShape=1\x7"
let &t_SR = "\<Esc>]50;CursorShape=2\x7"
let &t_EI = "\<Esc>]50;CursorShape=0\x7"

enter image description here

But as you can see there was a delay when hitting ESC to exit insert mode back to normal mode and show the block as cursor again. So to fix it I found this:

set ttimeout
set ttimeoutlen=1
set ttyfast

And now it works pretty fine as you can see:

fix delay going back to block as cursor

I hope it could help any one else!

Razzi Abuissa
  • 3,337
  • 2
  • 28
  • 29
alexventuraio
  • 8,126
  • 2
  • 30
  • 35
19

If you are using tmux and iTerm2 on macOS,
the following changes the cursor from a block to a cursor and highlights the current line

if exists('$TMUX')
  let &t_SI = "\<Esc>Ptmux;\<Esc>\<Esc>]50;CursorShape=1\x7\<Esc>\\"
  let &t_EI = "\<Esc>Ptmux;\<Esc>\<Esc>]50;CursorShape=0\x7\<Esc>\\"
else
  let &t_SI = "\<Esc>]50;CursorShape=1\x7"
  let &t_EI = "\<Esc>]50;CursorShape=0\x7"
endif
:autocmd InsertEnter * set cul
:autocmd InsertLeave * set nocul

credit: https://gist.github.com/andyfowler/1195581

ib.
  • 27,830
  • 11
  • 80
  • 100
user160917
  • 9,211
  • 4
  • 53
  • 63
  • 1
    Note this is *specific to iTerm*. Since the standard ones actually also work but also work in all the other supporting terminals, this is probably the wrong answer. Look here --> https://stackoverflow.com/a/42118416/340947 – Steven Lu Dec 12 '17 at 22:06
  • @StevenLu actually the one in your suggested answer didn't work for iTerm2 (Mac), while this one worked. This stuff is more fiddly than you might expect. – C S Sep 29 '19 at 07:57
  • This cursor stuff is definitely one of the fiddlier things out there. I just realized that don't even think I have a proper setup, as tmux does not appear to be performing cursor state tracking which some answers indicate is a possibility. I was plenty happy enough just to get vim to handle setting the cursor to a line on insert mode. – Steven Lu Sep 29 '19 at 12:40
  • I figured this stuff out. The solution is to tweak tmux to properly handle it, and it can be non-obvious. What I needed to do was ensure that my tmux config's `terminal-overrides` was only being appended to, so it didn't clobber the `,*:Ss=\E[%p1%d q:Se=\E[2 q` part of `terminal-overrides`. so my config looks like `set -sa terminal-overrides ",xterm-256color-italic:Tc"` (to set the 24-bit color enabling without trampling cursor styles Ss/Se. – Steven Lu Oct 04 '19 at 00:51
13

To change the shape of the cursor in different modes, you can add the following into your .vimrc file.

For the GNOME Terminal (version 2.26):

if has("autocmd")
  au InsertEnter * silent execute "!gconftool-2 --type string --set /apps/gnome-terminal/profiles/Default/cursor_shape ibeam"
  au InsertLeave * silent execute "!gconftool-2 --type string --set /apps/gnome-terminal/profiles/Default/cursor_shape block"
  au VimLeave * silent execute "!gconftool-2 --type string --set /apps/gnome-terminal/profiles/Default/cursor_shape ibeam"
endif

If you use more than one profile in GNOME Terminal, you might have to adapt this to your profiles.

For Konsole in KDE4:

let &t_SI = "\<Esc>]50;CursorShape=1\x7"
let &t_EI = "\<Esc>]50;CursorShape=0\x7"

This works with multiple tabs and windows.

See also: “Change cursor shape in different modes” on Vim Tips Wiki.

ib.
  • 27,830
  • 11
  • 80
  • 100
IvanGL
  • 751
  • 5
  • 22
  • 14
    I primarily use vim in tmux over ssh with putty. Is there a more universal option? – lanrat Jun 27 '11 at 05:21
  • 1
    Changing gnome-terminal's settings via a gconftool-2 command is a very bad idea. It does not only influence the terminal where your vim is running, but also all other current and future gnome-terminal tabs of the same profile. – egmont Sep 11 '16 at 18:38
  • 1
    this works for konsole, thank you. But one issue is that exiting insert mode is slooow, not sure why – Hoang Tran Jul 02 '17 at 11:35
  • 1
    @HoangTran use `set ttimeoutlen=0` – Bananach Aug 30 '17 at 07:10
  • how to apply this to all profiles. Eg I have One light and Foxnight profiles - When I use Default it only works for Foxnight profile. – daGo Oct 24 '19 at 11:54
11

You may try the Terminus Vim plugin:

In insert mode, the cursor shape changes to a thin vertical bar. In replace mode, it changes to an underline. On returning to normal mode, it reverts to the standard "block" shape.

ib.
  • 27,830
  • 11
  • 80
  • 100
Tim Gabets
  • 159
  • 1
  • 5
  • This seems like the most sensible solution. There should be a :set for this directly in VIM, standard. – user12711 Aug 09 '19 at 01:11
  • Requirements: gnome-terminal (https://wiki.gnome.org/Apps/Terminal) and other terminals using the VTE library (https://github.com/GNOME/vte): Partially supported (for example, supports cursor shape changes but not focus reporting). In my case (gnome-terminal 3.6.2) it doesn't work at all. – daGo Nov 17 '19 at 06:30
10

I find it useful to only have the cursor blinking in Insert mode and keep it static in other modes.

set guicursor+=n-v-c:blinkon0
ib.
  • 27,830
  • 11
  • 80
  • 100
user41365
  • 109
  • 1
  • 2
8

According to this post on "Vim Tips WiKi":

"To change the shape of the cursor in different modes, you can add the following into your vimrc:"

"For Terminal on macOS"

"Mode Settings

let &t_SI.="\e[5 q" "SI = INSERT mode
let &t_SR.="\e[4 q" "SR = REPLACE mode
let &t_EI.="\e[1 q" "EI = NORMAL mode (ELSE)

"Cursor settings:

"  1 -> blinking block
"  2 -> solid block 
"  3 -> blinking underscore
"  4 -> solid underscore
"  5 -> blinking vertical bar
"  6 -> solid vertical bar

Scripts for other OS are also included in that post.

oat
  • 384
  • 1
  • 6
  • 15
1

If you are using a modern version of nvim and you wanted to achieve this, you can avoid some of these fancy workarounds listed above.

The below settings will switch from block cursor in normal mode, to underline cursor in replace to line cursor in insert.

# ~/.tmux.conf
set -g default-terminal "screen-256color"
set -ga terminal-overrides ",*256col*:Tc"
set -ga terminal-overrides '*:Ss=\E[%p1%d q:Se=\E[ q',w

" ~/.vimrc
" Sets cursor styles
" Block in normal, line in insert, underline in replace
set guicursor=n-v-c-sm:block,i-ci-ve:ver25-Cursor,r-cr-o:hor20

I managed to get this working with the following settings pulled from these two sources.

tui-cursor-shape

guicursor

thrgamon
  • 438
  • 1
  • 5
  • 14
1

I don't think this adds much to the answers that other people have already provided but I wanted to somehow summarise things in one place and also have links to the relevant references.

This is what the relevant snippet from my .vimrc looks like:

    " Cursor appearance
    "
    " See also: [1]'ANSI Control Functions Summary', [2]DECSCUSR, [3]xterm+tmux
    "   entry in terminfo.src.
    " [1] https://www.vt100.net/docs/vt510-rm/chapter4.html
    " [2] https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
    " [3] https://raw.githubusercontent.com/mirror/ncurses/master/misc/terminfo.src
    "
    " On:
    " - entered insert mode
    let &t_SI = "^[[5 q^[]12;Magenta\007" " blinking bar (Ss) in magenta (Cs)
    " - entered replace mode
    let &t_SR = "^[[0 q^[]12;Red\007" " blinking block (Ss) in red (Cs)
    " - leaving insert/replace mode
    let &t_EI = "^[[2 q^[]112\007" " terminal power-on style (Se) and colour (Cr)

Note: The '^[' characters are actually one ESC (escape sequence) control character.

0

This works properly on xfce4-terminal:

add following script to your .vimrc

if has("autocmd")
  au InsertEnter * silent execute "!sed -i.bak -e 's/TERMINAL_CURSOR_SHAPE_BLOCK/TERMINAL_CURSOR_SHAPE_IBEAM/' ~/.config/xfce4/terminal/terminalrc"                                                                                          
  au InsertLeave * silent execute "!sed -i.bak -e 's/TERMINAL_CURSOR_SHAPE_IBEAM/TERMINAL_CURSOR_SHAPE_BLOCK/' ~/.config/xfce4/terminal/terminalrc"                                                                                          
  au VimLeave * silent execute "!sed -i.bak -e 's/TERMINAL_CURSOR_SHAPE_IBEAM/TERMINAL_CURSOR_SHAPE_BLOCK/' ~/.config/xfce4/terminal/terminalrc"  
endif

Brief: As You know xfce4-terminal keeps preferences in .config/xfce4/terminal/terminalrc file. The script changes TERMINAL_CURSOR_SHAPE_BLOCK to TERMINAL_CURSOR_SHAPE_IBEAM when you're in insert mode, and back to block when you leave insert mode or vim. Feel free to change IBEAM to anything you want (BLOCK, IBEAM and UNDERLINE available).

amirali
  • 1,888
  • 1
  • 11
  • 32
-1

I usually have the current vim mode onto statusline, among other things. If you seek simplicity, you can set only this information onto the statusline.

However, usually the really crazy things happen when you have caps lock depressed and are in command mode (since hjkl now are HJKL - just J and K is enough to make you pull your hair out when you don't understand what's happening. Do a :h J and :h K to see what I mean). Just beware the caps lock key and you'll be fine most of the time IMO.

GmonC
  • 10,924
  • 1
  • 30
  • 38
  • 46
    How does this answer the question? – David Rivers Aug 04 '15 at 19:55
  • 2
    @DavidRivers It's an application of the XY problem where the OP was asking for a resolution to his problem (not knowing about being in vim normal mode and wanting the cursor to change to indicate it) but turned out satisfied with an alternative (and IMO not a great) solution (enhancing his statusline with the state) – Steven Lu Dec 12 '17 at 22:05