Surely, there will still be emacs and vim users 50 years from now, but the user numbers and the community power will diminish as the graybeards gradually leave this plane.
Surely, there will still be emacs and vim users 50 years from now, but the user numbers and the community power will diminish as the graybeards gradually leave this plane.
Emacs is fundamentally an interactive shell, like Bash. It has a text editor, also like Bash. It is of course generally more powerful and featureful than Bash.
Hence, people sometimes live in Emacs, because it's a shell like Bash or Gnome or KDE.
I use Emacs and VSCode. VSCode for some code repos, and Emacs for general computer usage.
Meanwhile, Vim is a text editor. It is neither a shell nor an IDE, although it can be adapted somewhat into an IDE.
I also use vi (alongside Emacs and VSCode). vi is for editing some text if I am not in Emacs for some reason or if I temporarily borked my Emacs config.
(I also use ed, for when I'm in a dumb terminal or I don't want to lose screen context.)
Vim or Emacs "dying" is not really an issue, although Vim or Emacs losing enough mindshare to keep them up to date as competitive IDE options, maybe that might happen.
1) Keybindings having no conflicts with other terminal applications. For that, vim's default window-management key of <C-w> is unfortunate, as it is very important for delete words in bash and readline. I remap that to <C-@> (CTRL-Space) instead, which is basically used by no terminal program that I am aware of. The other key binding that trips me up are the default vim keybindings to kill the terminal (<C-w><C-c>). If I am midway attempting a window action, but realise something is taking too long and want to stop the job, the keybinding kills my whole shell. If I really want to kill my terminal, I can always issue ZQ or :q! in normal mode.
2) Change my cursor shapes based on which mode I'm in (normal, insert, or terminal/command), which helps me easily tell the mode.
3) Improve the default keybinding for going from terminal back to terminal normal mode. I find the default keybindings <C-\><C-n> and <C-w>N too difficult to type because I need to use this binding very much.
4) Be able to move between windows with the same, consistent set of keybindings no matter which mode I'm in (e.g. not having to go back to normal mode first, from insert or terminal mode). In the same vein, when I land on a buffer I always expect to be in normal mode, so I can start moving around immediately and yank stuff without remembering whether I'm in a terminal or a non-terminal buffer. When I need to manipulate the terminal program I can always `i` or `a`.
I have quite a few other customisations to my vim terminal, but I think these are the most essential ones.
vimrc for 1)
set termwinkey=<C-@>
noremap <C-@> <C-w>
noremap <C-@><CR> <C-w><CR>
noremap! <C-@> <Esc><C-w>
noremap <C-@>c <Nop>
noremap <C-@><C-c> <Nop>
noremap <C-@><C-q> <Nop>
noremap! <C-@>c <Nop>
noremap! <C-@><C-c> <Nop>
noremap! <C-@><C-q> <Nop>
tnoremap <C-@>c <Nop>
tnoremap <C-@><C-c> <Nop>
tnoremap <C-@><C-q> <Nop>
noremap <C-@>q <Nop>
noremap! <C-@>q <Nop>
tnoremap <C-@>q <Nop>
vimrc for 2) and 3) augroup term_normal
au!
autocmd WinNew * let w:winnew = 1
autocmd CmdlineEnter * let w:outcmd = 0
autocmd CmdlineLeave * let w:outcmd = 1
autocmd WinEnter * if exists ('w:winnew') | unlet w:winnew | if (mode() == 't') | call Termcursor () | endif | elseif get(w:, 'outcmd', 1) && (mode() == 't') | call feedkeys("\<C-@>N", "") | endif
autocmd WinLeave * if (mode() == 't') && (! exists('w:tu')) | call feedkeys("\<C-@>N", 'x') | call Normalcursor () | elseif (mode(1) == 'nt') && (exists('w:tu')) | call feedkeys("i", 'ix') | endif
tmap <expr> <C-@><C-@> ((mode() == 't') && get(w:, 'outcmd', 1)) ? '<C-@>N' : '<C-@><C-@>'
augroup end
let &t_SI = "\e[6 q\e]12;#FF00DF\<C-g>"
let &t_EI = "\e[2 q\e]12;#FF00DF\<C-g>"
let &t_ti = "\e[4 q\e]12;#FF00DF\<C-g>"
let &t_te = "\e[2 q\e]12;#FF00DF\<C-g>"
let &t_Us = "\e[4:2m"
let &t_ds = "\e[4:4m"
let &t_Ds = "\e[58:5:4m\e[4:5m"
function! Normalcursor ()
let &t_ve ="\e[2 q\e]12;#FF00DF\<C-g>"
let &t_vi ="\e[2 q\e]12;#FF00DF\<C-g>"
endfunction
function! Echonormalcursor ()
call echoraw("\e[2 q\e]12;#FF00DF\<C-g>")
endfunction
function! Termcursor ()
let &t_ve ="\e[4 q\e]12;#FF00DF\<C-g>"
let &t_vi ="\e[4 q\e]12;#FF00DF\<C-g>"
endfunction
function! Echotermcursor ()
call echoraw("\e[4 q\e]12;#FF00DF\<C-g>")
endfunction
augroup termcursor
au!
autocmd ModeChanged *:n* let &t_ve ="\e[2 q\e]12;#FF00DF\<C-g>"
autocmd ModeChanged *:n* let &t_vi ="\e[2 q\e]12;#FF00DF\<C-g>"
autocmd ModeChanged i:* if &t_ve == "" | let &t_ve ="\e[2 q\e]12;#FF00DF\<C-g>" | endif
autocmd ModeChanged i:* if &t_vi == "" | let &t_vi ="\e[2 q\e]12;#FF00DF\<C-g>" | endif
autocmd ModeChanged *:i* let &t_ve =""
autocmd ModeChanged *:i* let &t_vi =""
autocmd ModeChanged *:t call echoraw("\e[4 q\e]12;#FF00DF\<C-g>")
autocmd ModeChanged *:t let &t_ve ="\e[4 q\e]12;#FF00DF\<C-g>"
autocmd ModeChanged *:t let &t_vi ="\e[4 q\e]12;#FF00DF\<C-g>"
autocmd ModeChanged t:* call echoraw("\e[2 q\e]12;#FF00DF\<C-g>")
autocmd ModeChanged t:* if (mode(1) != 'ct') | let &t_ve ="\e[2 q\e]12;#FF00DF\<C-g>" | endif
autocmd ModeChanged t:* if (mode(1) != 'ct') | let &t_vi ="\e[2 q\e]12;#FF00DF\<C-g>" | endif
let g:cmdlinedepth = 0
autocmd CmdlineEnter * let g:cmdlinedepth = g:cmdlinedepth + 1 | let &t_ve = "\e[4 q\e]12;#FF00DF\<C-g>" | let &t_vi = "\e[4 q\e]12;#FF00DF\<C-g>"
autocmd CmdlineLeave * let g:cmdlinedepth = g:cmdlinedepth - 1 | if g:cmdlinedepth == 0 | if (mode(1) == 'ct') | call Termcursor () | else | call Normalcursor () | endif | endif
autocmd CmdwinEnter * let &t_ve ="\e[2 q\e]12;#FF00DF\<C-g>" | let &t_vi ="\e[2 q\e]12;#FF00DF\<C-g>"
autocmd CmdwinLeave * let &t_ve = "\e[4 q\e]12;#FF00DF\<C-g>" | let &t_vi = "\e[4 q\e]12;#FF00DF\<C-g>"
" autocmd WinEnter * call echoraw("\e[2 q\e]12;#FF00DF\<C-g>") augroup term_normal
au!
autocmd WinNew * let w:winnew = 1
autocmd CmdlineEnter * let w:outcmd = 0
autocmd CmdlineLeave * let w:outcmd = 1
autocmd WinEnter * if exists ('w:winnew') | unlet w:winnew | if (mode() == 't') | call Termcursor () | endif | elseif get(w:, 'outcmd', 1) && (mode() == 't') | call feedkeys("\<C-@>N", "") | endif
autocmd WinLeave * if (mode() == 't') && (! exists('w:tu')) | call feedkeys("\<C-@>N", 'x') | call Normalcursor () | elseif (mode(1) == 'nt') && (exists('w:tu')) | call feedkeys("i", 'ix') | endif
tmap <expr> <C-@><C-@> ((mode() == 't') && get(w:, 'outcmd', 1)) ? '<C-@>N' : '<C-@><C-@>'
augroup end
let &t_SI = "\eP\e[6 q\e]12;#FF00DF\<C-g>\e\\"
let &t_EI = "\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\"
let &t_ti = "\eP\e[4 q\e]12;#FF00DF\<C-g>\e\\"
let &t_te = "\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\"
let &t_Us = "\eP\e[4:2m\e\\"
let &t_ds = "\eP\e[4:4m\e\\"
let &t_Ds = "\eP\e[58:5:3m\e[4:5m\e\\"
function! Normalcursor ()
let &t_ve ="\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\"
let &t_vi ="\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\"
endfunction
function! Echonormalcursor ()
call echoraw("\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\")
endfunction
function! Termcursor ()
let &t_ve ="\eP\e[4 q\e]12;#FF00DF\<C-g>\e\\"
let &t_vi ="\eP\e[4 q\e]12;#FF00DF\<C-g>\e\\"
endfunction
function! Echotermcursor ()
call echoraw("\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\")
endfunction
augroup termcursor
au!
autocmd ModeChanged *:n* let &t_ve ="\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\"
autocmd ModeChanged *:n* let &t_vi ="\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\"
autocmd ModeChanged i:* if &t_ve == "" | let &t_ve ="\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\" | endif
autocmd ModeChanged i:* if &t_vi == "" | let &t_vi ="\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\" | endif
autocmd ModeChanged *:i* let &t_ve =""
autocmd ModeChanged *:i* let &t_vi =""
autocmd ModeChanged *:t call echoraw("\eP\e[4 q\e]12;#FF00DF\<C-g>\e\\")
autocmd ModeChanged *:t let &t_ve ="\eP\e[4 q\e]12;#FF00DF\<C-g>\e\\"
autocmd ModeChanged *:t let &t_vi ="\eP\e[4 q\e]12;#FF00DF\<C-g>\e\\"
autocmd ModeChanged t:* call echoraw("\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\")
autocmd ModeChanged t:* if (mode(1) != 'ct') | let &t_ve ="\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\" | endif
autocmd ModeChanged t:* if (mode(1) != 'ct') | let &t_vi ="\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\" | endif
" TODO -- doesnt restore from redraw?
let g:cmdlinedepth = 0
autocmd CmdlineEnter * let g:cmdlinedepth = g:cmdlinedepth + 1 | let &t_ve = "\eP\e[4 q\e]12;#FF00DF\<C-g>\e\\" | let &t_vi = "\eP\e[4 q\e]12;#FF00DF\<C-g>\e\\"
autocmd CmdlineLeave * let g:cmdlinedepth = g:cmdlinedepth - 1 | if g:cmdlinedepth == 0 | if (mode(1) == 'ct') | call Termcursor () | else | call Normalcursor () | endif | endif
autocmd CmdwinEnter * let &t_ve ="\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\" | let &t_vi ="\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\"
autocmd CmdwinLeave * let &t_ve = "\eP\e[4 q\e]12;#FF00DF\<C-g>\e\\" | let &t_vi = "\eP\e[4 q\e]12;#FF00DF\<C-g>\e\\"
" autocmd WinEnter * call echoraw("\eP\e[2 q\e]12;#FF00DF\<C-g>\e\\")
augroup end vnoremap <C-@>s <C-w>sgv
vnoremap <C-@>v <C-w>vgv
nnoremap <expr> <C-@>w '@_' .. ((v:count1 + (winnr() - 1)) % (winnr('$')) + 1) .. '<C-w>w'
nnoremap <expr> <C-@>W '@_' .. (((- v:count1 + (winnr() - 1)) % (winnr('$')) + winnr('$')) % (winnr('$')) + 1) .. '<C-w>w'
nnoremap <expr> <C-@>t '@_' .. ((v:count1 - 1) % (winnr('$')) + 1) .. '<C-w>w'
nnoremap <expr> <C-@>b '@_' .. (((- v:count1) % (winnr('$')) + winnr('$')) % (winnr('$')) + 1) .. '<C-w>w'
inoremap <C-@><C-@> <C-@>
map! <C-@>w <Esc><C-@>w
map! <C-@>W <Esc><C-@>W
map! <C-@>t <Esc><C-@>t
map! <C-@>b <Esc><C-@>b
tmap <C-@>w <C-@>N<C-@>w
tmap <C-@>W <C-@>N<C-@>W
tmap <C-@>t <C-@>N<C-@>t
tmap <C-@>b <C-@>N<C-@>bInvoke terminals on directories (instead of netrw). So, I can e.g. sp. to split to a new terminal.
function! Isdir(dir) abort
return !empty(a:dir) && (isdirectory(a:dir) ||
\ (!empty($SYSTEMDRIVE) && isdirectory('/'..tolower($SYSTEMDRIVE[0])..a:dir)))
endfunction
augroup terminal-explorer
au!
au VimEnter * sil! au! FileExplorer *
au VimEnter * sil! au! Network *
au VimEnter * sil! au! AuNetrwEvent *
" au FileType netrw cd % | bw | exe 'terminal ++curwin'
au BufEnter * if &filetype != 'netrw' && Isdir(expand('%')) | lcd % | exe bufnr("%") ..'bufdo terminal ++curwin' | endif
augroup end
Make <C-@>m close windows instead: noremap <C-@>m <C-w>c
noremap! <C-@>m <Esc><C-w>c
tnoremap <C-@>m <C-@>c
Make <C-@>p find the next window if there is no previous window: noremap <expr> <silent> <C-@>p ':<C-u>wincmd p <Bar> if win_getid () == ' .. win_getid () .. ' <Bar> wincmd w <Bar> endif <CR>'
noremap! <expr> <silent> <C-@>p '<Esc>:<C-u>wincmd p <Bar> if win_getid () == ' .. win_getid () .. ' <Bar> wincmd w <Bar> endif <CR>'
tnoremap <expr> <silent> <C-@>p '<C-@>:<C-u>wincmd p <Bar> if win_getid () == ' .. win_getid () .. ' <Bar> wincmd w <Bar> endif <CR>'
Use <C-@>~. to detach the GNU screen that my vim is running in (I put my vim in a screen with `unbindall` i.e. I use screen merely for keeping my vim alive) (<C-@>~. is in analogy to the SSH quit keybinding <CR>~.). noremap <expr> <silent> <C-@>~. ':<C-u>silent !screen -X detach<CR>'
noremap! <expr> <silent> <C-@>~. '<C-@>:<C-u>silent !screen -X detach<CR>'
tnoremap <expr> <silent> <C-@>~. '<C-@>:<C-u>silent !screen -X detach<CR>'
With gf and gF, opening files just from a terminal grep is practically more convenient than vim's :grep. For gf in a new tab: map <silent> <C-@><C-f> :<C-u>tab split<CR>gf
With terminal multiplexing in vim, you start getting a lot of buffers. You can consider getting a custom tabline. Other tab management features become more important too. You might expect [count]gt to behave just like gt for [count] times: nnoremap <expr> gt '@_' .. ((v:count1 + (tabpagenr () - 1)) % (tabpagenr('$') ) + 1) .. 'gt'
For ease of moving to the last tab: nnoremap <expr> g<C-t> '@_' .. (((v:count == 0) ? tabpagenr ('$') : v:count)) .. 'gt'
To consistently access the gt family of bindings regardless of mode: map <C-@>gt gt
map <C-@>gT gT
map <C-@>g<C-t> g<C-t>
map! <C-@>gt <Esc>gt
map! <C-@>gT <Esc>gT
map! <C-@>g<C-t> <Esc>g<C-t>
tmap <C-@>gt <C-@>Ngt
tmap <C-@>gT <C-@>NgT
tmap <C-@>g<C-t> <C-@>Ng<C-t>
When you use <C-w>T a lot to move your windows in to new tabs, you might sometimes want to move them to the previous tab instead of the next one: nnoremap <silent> <C-@><C-t> <C-w>T
nnoremap <silent> <C-@>T <C-w>T:<C-u>tabm -1<CR>
To access these two in any mode consistently: map! <C-@><C-t> <Esc><C-@><C-t>
map! <C-@>T <Esc><C-@>T
tmap <C-@><C-t> <C-@>N<C-@><C-t>
tmap <C-@>T <C-@>N<C-@>T
Analogously to gt and gT, sometimes you may want to move your tabs around, or split them: function! SSStabmadjust(tabmnum)
if a:tabmnum < tabpagenr ()
return a:tabmnum - 1
else
return a:tabmnum
endif
endfunction
noremap <silent> <C-@><C-g>s :<C-u>tab split<CR>
noremap <expr> <silent> <C-@><C-g>t '@_:<C-u>' .. SSStabmadjust ((v:count1 + (tabpagenr () - 1 )) % (tabpagenr('$') ) + 1) .. 'tabm<CR>'
noremap <expr> <silent> <C-@><C-g>T '@_:<C-u>' .. SSStabmadjust (((- v:count1 + (tabpagenr () - 1 )) % (tabpagenr('$') ) + tabpagenr('$') ) % (tabpagenr('$') ) + 1) .. 'tabm<CR>'
noremap <expr> <silent> <C-@><C-g><C-t> ':<C-u>' .. ((v:count == 0) ? "" : SSStabmadjust ((v:count % (tabpagenr ('$') )) )) .. 'tabm<CR>'
map! <C-@><C-g>s <Esc><C-@><C-g>s
map! <C-@><C-g>t <Esc><C-@><C-g>t
map! <C-@><C-g>T <Esc><C-@><C-g>T
map! <C-@><C-g><C-t> <Esc><C-@><C-g><C-t>
tmap <C-@><C-g>s <C-@>N<C-@><C-g>s
tmap <C-@><C-g>t <C-@>N<C-@><C-g>t
tmap <C-@><C-g>T <C-@>N<C-@><C-g>T
tmap <C-@><C-g><C-t> <C-@>N<C-@><C-g><C-t> map <expr> <C-@>1 Termcountmap(1, "")
map <expr> <C-@>2 Termcountmap(2, "")
map <expr> <C-@>3 Termcountmap(3, "")
map <expr> <C-@>4 Termcountmap(4, "")
map <expr> <C-@>5 Termcountmap(5, "")
map <expr> <C-@>6 Termcountmap(6, "")
map <expr> <C-@>7 Termcountmap(7, "")
map <expr> <C-@>8 Termcountmap(8, "")
map <expr> <C-@>9 Termcountmap(9, "")
map! <expr> <C-@>1 Termcountmap(1, '<Esc>')
map! <expr> <C-@>2 Termcountmap(2, '<Esc>')
map! <expr> <C-@>3 Termcountmap(3, '<Esc>')
map! <expr> <C-@>4 Termcountmap(4, '<Esc>')
map! <expr> <C-@>5 Termcountmap(5, '<Esc>')
map! <expr> <C-@>6 Termcountmap(6, '<Esc>')
map! <expr> <C-@>7 Termcountmap(7, '<Esc>')
map! <expr> <C-@>8 Termcountmap(8, '<Esc>')
map! <expr> <C-@>9 Termcountmap(9, '<Esc>')
tmap <expr> <C-@>1 Termcountmap(1, '<C-@>N')
tmap <expr> <C-@>2 Termcountmap(2, '<C-@>N')
tmap <expr> <C-@>3 Termcountmap(3, '<C-@>N')
tmap <expr> <C-@>4 Termcountmap(4, '<C-@>N')
tmap <expr> <C-@>5 Termcountmap(5, '<C-@>N')
tmap <expr> <C-@>6 Termcountmap(6, '<C-@>N')
tmap <expr> <C-@>7 Termcountmap(7, '<C-@>N')
tmap <expr> <C-@>8 Termcountmap(8, '<C-@>N')
tmap <expr> <C-@>9 Termcountmap(9, '<C-@>N')
function! Termcountmap(initcount, normalkeys)
let termcount = a:initcount
while 1
try
let char = getchar()
catch /^Vim:Interrupt$/
return ""
endtry
if type(char) == 0
let char = nr2char(char)
endif
if char == '0'
let termcount = termcount * 10
elseif char == '1'
let termcount = termcount * 10 + 1
elseif char == '2'
let termcount = termcount * 10 + 2
elseif char == '3'
let termcount = termcount * 10 + 3
elseif char == '4'
let termcount = termcount * 10 + 4
elseif char == '5'
let termcount = termcount * 10 + 5
elseif char == '6'
let termcount = termcount * 10 + 6
elseif char == '7'
let termcount = termcount * 10 + 7
elseif char == '8'
let termcount = termcount * 10 + 8
elseif char == '9'
let termcount = termcount * 10 + 9
elseif char == 'g'
return a:normalkeys .. termcount .. 'g'
elseif char == "\<C-g>"
return a:normalkeys .. termcount .. "\<C-@>\<C-g>"
elseif char == 'w'
return a:normalkeys .. termcount .. "\<C-@>w"
elseif char == 'W'
return a:normalkeys .. termcount .. "\<C-@>W"
elseif char == 't'
return a:normalkeys .. termcount .. "\<C-@>t"
elseif char == 'b'
return a:normalkeys .. termcount .. "\<C-@>b"
else
return a:normalkeys .. ":\<C-u>" .. termcount .. ' wincmd ' .. char .. "\<CR>\<C-l>"
endif
endwhile
endfunction
map <expr> g<C-@> <C-@>g
map <expr> g1 Prefixcountmap (v:count * 10 + 1, "", 'g')
map <expr> g2 Prefixcountmap (v:count * 10 + 2, "", 'g')
map <expr> g3 Prefixcountmap (v:count * 10 + 3, "", 'g')
map <expr> g4 Prefixcountmap (v:count * 10 + 4, "", 'g')
map <expr> g5 Prefixcountmap (v:count * 10 + 5, "", 'g')
map <expr> g6 Prefixcountmap (v:count * 10 + 6, "", 'g')
map <expr> g7 Prefixcountmap (v:count * 10 + 7, "", 'g')
map <expr> g8 Prefixcountmap (v:count * 10 + 8, "", 'g')
map <expr> g9 Prefixcountmap (v:count * 10 + 9, "", 'g')
tmap <expr> <c-@>g1 Prefixcountmap (v:count * 10 + 1, '<c-@>n', 'g')
tmap <expr> <c-@>g2 Prefixcountmap (v:count * 10 + 2, '<c-@>n', 'g')
tmap <expr> <c-@>g3 Prefixcountmap (v:count * 10 + 3, '<c-@>n', 'g')
tmap <expr> <c-@>g4 Prefixcountmap (v:count * 10 + 4, '<c-@>n', 'g')
tmap <expr> <c-@>g5 Prefixcountmap (v:count * 10 + 5, '<c-@>n', 'g')
tmap <expr> <c-@>g6 Prefixcountmap (v:count * 10 + 6, '<c-@>n', 'g')
tmap <expr> <c-@>g7 Prefixcountmap (v:count * 10 + 7, '<c-@>n', 'g')
tmap <expr> <c-@>g8 Prefixcountmap (v:count * 10 + 8, '<c-@>n', 'g')
tmap <expr> <c-@>g9 Prefixcountmap (v:count * 10 + 9, '<c-@>n', 'g')
map <expr> <C-@><C-g>1 Prefixcountmap (v:count * 10 + 1, "", '<C-@><C-g>')
map <expr> <C-@><C-g>2 Prefixcountmap (v:count * 10 + 2, "", '<C-@><C-g>')
map <expr> <C-@><C-g>3 Prefixcountmap (v:count * 10 + 3, "", '<C-@><C-g>')
map <expr> <C-@><C-g>4 Prefixcountmap (v:count * 10 + 4, "", '<C-@><C-g>')
map <expr> <C-@><C-g>5 Prefixcountmap (v:count * 10 + 5, "", '<C-@><C-g>')
map <expr> <C-@><C-g>6 Prefixcountmap (v:count * 10 + 6, "", '<C-@><C-g>')
map <expr> <C-@><C-g>7 Prefixcountmap (v:count * 10 + 7, "", '<C-@><C-g>')
map <expr> <C-@><C-g>8 Prefixcountmap (v:count * 10 + 8, "", '<C-@><C-g>')
map <expr> <C-@><C-g>9 Prefixcountmap (v:count * 10 + 9, "", '<C-@><C-g>')
map! <expr> <C-@><C-g>1 Prefixcountmap (v:count * 10 + 1, '<Esc>', '<C-@><C-g>')
map! <expr> <C-@><C-g>2 Prefixcountmap (v:count * 10 + 2, '<Esc>', '<C-@><C-g>')
map! <expr> <C-@><C-g>3 Prefixcountmap (v:count * 10 + 3, '<Esc>', '<C-@><C-g>')
map! <expr> <C-@><C-g>4 Prefixcountmap (v:count * 10 + 4, '<Esc>', '<C-@><C-g>')
map! <expr> <C-@><C-g>5 Prefixcountmap (v:count * 10 + 5, '<Esc>', '<C-@><C-g>')
map! <expr> <C-@><C-g>6 Prefixcountmap (v:count * 10 + 6, '<Esc>', '<C-@><C-g>')
map! <expr> <C-@><C-g>7 Prefixcountmap (v:count * 10 + 7, '<Esc>', '<C-@><C-g>')
map! <expr> <C-@><C-g>8 Prefixcountmap (v:count * 10 + 8, '<Esc>', '<C-@><C-g>')
map! <expr> <C-@><C-g>9 Prefixcountmap (v:count * 10 + 9, '<Esc>', '<C-@><C-g>')
tmap <expr> <C-@><C-g>1 Prefixcountmap (v:count * 10 + 1, '<C-@>N', '<C-@><C-g>')
tmap <expr> <C-@><C-g>2 Prefixcountmap (v:count * 10 + 2, '<C-@>N', '<C-@><C-g>')
tmap <expr> <C-@><C-g>3 Prefixcountmap (v:count * 10 + 3, '<C-@>N', '<C-@><C-g>')
tmap <expr> <C-@><C-g>4 Prefixcountmap (v:count * 10 + 4, '<C-@>N', '<C-@><C-g>')
tmap <expr> <C-@><C-g>5 Prefixcountmap (v:count * 10 + 5, '<C-@>N', '<C-@><C-g>')
tmap <expr> <C-@><C-g>6 Prefixcountmap (v:count * 10 + 6, '<C-@>N', '<C-@><C-g>')
tmap <expr> <C-@><C-g>7 Prefixcountmap (v:count * 10 + 7, '<C-@>N', '<C-@><C-g>')
tmap <expr> <C-@><C-g>8 Prefixcountmap (v:count * 10 + 8, '<C-@>N', '<C-@><C-g>')
tmap <expr> <C-@><C-g>9 Prefixcountmap (v:count * 10 + 9, '<C-@>N', '<C-@><C-g>')
function! Prefixcountmap(initcount, prefix, countprefix)
let termcount = a:initcount
while 1
try
let char = getchar()
catch /^Vim:Interrupt$/
return ""
endtry
if type(char) == 0
let char = nr2char(char)
endif
if char == '0'
let termcount = termcount * 10
elseif char == '1'
let termcount = termcount * 10 + 1
elseif char == '2'
let termcount = termcount * 10 + 2
elseif char == '3'
let termcount = termcount * 10 + 3
elseif char == '4'
let termcount = termcount * 10 + 4
elseif char == '5'
let termcount = termcount * 10 + 5
elseif char == '6'
let termcount = termcount * 10 + 6
elseif char == '7'
let termcount = termcount * 10 + 7
elseif char == '8'
let termcount = termcount * 10 + 8
elseif char == '9'
let termcount = termcount * 10 + 9
else
return a:prefix .. termcount .. a:countprefix .. char
endif
endwhile
endfunctionAlso, I don't really miss anything from more advanced ides when in vim. There are great packages for almost anything.
I went from vim to neovim, but the LSPs for python/go(lang) for large files (not that large, maybe 10k loc) seem to really bog it down (back then, no idea if it's better now), whereas with VS Code it was still performant enough. So I ended up using VS Code with Vim bindings.
And yes, with ad hoc work, I still end up using system vim when just doing simple edits (e.g. adding a line to README.md or somesuch)
emacs is surely on a decline, but it’s not obvious that Vim is on the same trend.
This matches “theory” and anecdotal evidence: the people who chose emacs probably didn’t like modal editing, and when “better” IDEs came along they just switched. But there’s nothing like Vim (except editors specifically inspired by Vim), and those haven’t gotten any traction if only because every one of us Vim users have hjkl muscle memory burned into our brains.
https://trends.google.com/trends/explore?date=all&q=%2Fm%2F0...
both decline, but emacs is steeper
I will concede that VS Code is the default for many, but I just can't get productive in it anymore. I mainly use intellij, which has its own issues. But I can't say I've ever mastered any editor, the closest was sublime text, and that mastery mainly came from being able to use cmd+p and global search effectively.
At this point, however, I do not really use Neovim anymore. I switched to Zed, the Vim emulation is pretty good and customizable and most functionality I want is already there along with incoming support for Jupyter Notebooks. VSCode also has these features.
It is fun to use Vim/Neovim but unless I need to use it, I doubt I will return to it.
In the end, it doesn't really matter what other people are using. If Vim (or Emacs) works for you, then you can basically keep using it until the end of time since code are just text files, and these things don't really change all that much (outside of encodings, which is the biggest problem with older editors – but I don't see UTF-8 replaced any time soon, if ever).
I don't really know what the kids these days are up to, but I don't think it really matters. I guess there's still few Bill Joys around using ed, but the existence of vi, Vim, VSCode, or anything else doesn't really take away anything for them.
MANPAGER=nvim --clean -c "colo sorbet" +Man!
Startup speed is blistering.My current config is pretty stable, and not that large. But if it were causing issues, I'd seriously consider only doing LSP setup, which is not that onerous with the latest APIs (it was already fairly easy with `vim.lsp.start`, but `vim.lsp.config` and `vim.lsp.enable` make it easier still: https://neovim.io/doc/user/lsp.html).
Apart from that, I don’t really know what an application would be to Emacs as nvim is to Vim. It’s more like nvim is to Vim what Emacs is to nano, except Emacs came first.
A multithreaded version of emacs would also be an interesting addition; I read some arguments against moving emacs to a multithreaded model, but I don't really remember them.
Everyone including the maintainers would like this to happen. The arguments against it are technical hurdles. Emacs is a large ball of global state and the lisp evaluator hooks into everything, including the display engine, so it's not clear to anyone how to disentangle things to the point where the interpreter lock can be released.
emacs is 4% vs VSCode 73%, so it's not popular, though vim still is
Visual Studio Code 73.6%
Visual Studio 29.3%
IntelliJ IDEA 26.8%
Notepad++ 23.9%
Vim 21.6%
Android Studio 16.1%
PyCharm 15.1%
Jupyter Notebook/JupyterLab 12.8%
Neovim 12.5%
...
Emacs 4.2%
...
Spacemacs 0.4%
So Vim + Neovim = 34.1%, essentially second to Visual Studio, the overwhelming leader.