I can change cursor shape in text console (TERM=linux or linux-16color) by this escape sequence, :

echo -e '\e[?6;c'

But I can't do it inside vim, below code should change cursor shape in insert mode, but it has no effect:

let &t_SI="\e[?0;c"
let &t_EI="\e[?6;c"

How to make it work?

The text console is not x terminal emulator, it's opened with ctrl-alt-f[3-6], I know how to do it with xterm or tmux.

2 Answers 2


Found a related discussion.

cnorm on my machine is


The tail \E[?0c will always reset cursor shape.

I thought I can use t_SI and t_EI if I remove it from cnorm (it's termcap code is ve):

let &t_ve= "\e[?25h"
let &t_SI = "\e[?0;c"
let &t_EI = "\e[?6;c"

But I can't see my cursor after executing above commands, looks like one has to set cursor shape in t_ve in text console(see update)?

I guess I can do it with autocmd:

augroup ag_tc_cursor | au!
  autocmd WinEnter,InsertLeave,CmdlineLeave * let &t_ve= "\e[?25h\e[?112c"
  autocmd InsertEnter,CmdlineEnter * let &t_ve= "\e[?25h\e[?0c"
augroup end

This will use blinking underscore cursor in insert or cmdline mode, static full block cursor in normal mode.

The character under cursor won't look clearly unless it's white, that basically make it useless(see update)?

If you want to change cursor for all applications, you can change cnorm and recompile terminfo.

Update, get black on white static soft cursor

According to Software cursor for VGA, current cell color is controlled by a 8 bit color byte:

7         6         5         4         3         2         1         0         
blink     bg_red    bg_green  bg_blue   bold      fg_red    fg_green  fg_blue

Soft cursor escape sequence has 3 parameters (first one fixed to 16?):


After some experiment, I believe the cursor color is defined as:

(current_color | select_bits) ^ toggle_bits

In order to get static black on white, we must make sure the final color byte is always 0 111 0 000 in binary no matter what current_color is.

We can set both the select_bits and toggle_bits to set it to 0 ( (x | 1) ^ 1 = 0 ), set select_bits only to set it to 1 ( (x | 1) ^ 0 = 1 ):

select_bits = 0B11111111 = 255
toggle_bits = 0B10001111 = 143

Put everything together:

augroup ag_tc_cursor | au!
  autocmd WinEnter,InsertLeave,CmdlineLeave * let &t_ve= "\e[?25h\e[?16;143;255c"
  autocmd InsertEnter,CmdlineEnter * let &t_ve= "\e[?25h\e[?0c"
augroup end

Update, remove autocmd, use t_SI, t_SE

It's a total mistake to do this by autocmd, InsertEnter won't be triggered by r.

For whatever reason, vim send t_vi upon InsertLeave, t_vi in linux defauts to:


It hide cursor and set cursor shape to invisible (I have no idea why would it do that) . That's why you can't see the cursor if you change only t_ve to "\e[?25h", to fix it, you must remove the cursor shape escape sequence ("\E[?1c") from t_vi .

Put everything together:

let &t_ve= "\e[?25h"
let &t_vi= "\e[?25l"
let &t_SI= "\e[?0c"
let &t_EI= "\e[?16;143;255c"
  • the link for " Software cursor for VGA" appears to be broken, directing me to localhost. Could you take a look / fix it?
    – Randall
    Feb 13, 2023 at 21:08

I tried this line from a part of the answer above:

let &t_ve= "\e[?25h\e[?16;143;255c"

I just put this line in my .vimrc. And this worked for me.
I got rid of the blinking underline cursor that happens in pure linux terminals when you use a Distro that does not have a Desktop Environment.
And now I have the solid non-blinking block that is usually standard in vim.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.