Live data from Hacker News

The State of Vim

lwn.net

191–200 of 203 posts

Re: The State of Vim

#191

Earlier quoted context omitted.

:! itself has not been stripped from neovim, it's the "interactive" :! that has been stripped (as the OP said) i.e if you do :!bash in vim you enter bash in neovim you won't

Thanks for the clarification. That makes sense and seems like a reasonable change to me.

I wouldn't say that `:!bash` is the most illustrative example of its impact. It bites you when you run any command that spits out a prompt, most commonly a [Yn] prompt. You can't use `:!` for these in nvim.

Re: The State of Vim

#192
post #50

Earlier quoted context omitted.

Unless your software deals with tracking people within an organization that will of course comply with the political parties that rule the regions where there software operate.

If Vim tracks you then that’s a willfull act that breaches trust. IMO no governance model can defend against supply chain attacks. IMO you shouldn’t try to fix things with governance model which it doesn’t fix. Use a governance model that leads to good governance. In technical and creative work single highest point of authority is best. Not because they have perfect knowledge or are the best but because dictator led…

One big question is why presumably "open source" projects still consider in 2025 to be acceptable to be hosted on Github (especially for those with the most important contributors not being USian).

Re: The State of Vim

#193
post #176

Earlier quoted context omitted.

Vim is more stable simply because it changes less often. Neovim is constantly improving its APIs, and that can break stuff. If you don't want to deal with breaking changes, just don't update. You can still use most plugins.

How do you propose I update my distro (fedora) and just don't update text editor? Are you in a habit of bringing a chroot with known good versions of your tools to every computer you ssh into? Like, I'd really want to have that. May it be I've missed some new thing that allows me to not update?

Don't install neovim with your system package manager, just like your other development tools. If you rely on a tool where the version makes a big difference, you should be in control of it, not the system package manager. You can build it from the source (which works fine) or use something like Bob [1].

[1]https://github.com/MordechaiHadad/bob

Re: The State of Vim

#194

Earlier quoted context omitted.

I loved LunarVim as well but after switching to AstroNvim I like it more. And it's easy to customize even for a very burned out dev like myself.

I also jumped ship to AstroNvim but I still prefer Lunarvim, I liked having all the config in just one file and some of its defaults. But I agree, Astro is the best distro currently maintained distro in my opinion.

One file worked fine until it didn't. At one point it was 500+ lines and became unwieldy to manage.

Though I might one day switch to Zed or Helix -- I want an editor that has more bells and whistles built-in and that I could just switch them off if I don't want them. Which should be a much smaller configuration footprint compared to what we have today with Neovim.

Re: The State of Vim

#195
post #176

Earlier quoted context omitted.

Vim is more stable simply because it changes less often. Neovim is constantly improving its APIs, and that can break stuff. If you don't want to deal with breaking changes, just don't update. You can still use most plugins.

How do you propose I update my distro (fedora) and just don't update text editor? Are you in a habit of bringing a chroot with known good versions of your tools to every computer you ssh into? Like, I'd really want to have that. May it be I've missed some new thing that allows me to not update?

/usr/local/bin

Re: The State of Vim

#196
post #139

Earlier quoted context omitted.

Why do Neovim users feel the need to take down Bram and Vim? Now you are taking credit for Bram's work! Why not make an application you love and leave everyone else alone? The community's behavior - what I see - is a deterrent to using Neovim.

It’s astonishing that you can arrive at this conclusion from my comment. He did great work, his development process did not scale. I am happy that I was able to use vim for more than a decade prior to neovim. The fact that after the neovim fork vims development started to pick up speed again is a fact (and doesn’t devalue bram’s work in any way). I am happy with bram’s work on vim and with the neovim devs and their w…

> his development process did not scale

I hope my development projects fail like Moolenaar's! Vim has been extraordinarily successful for decades, possibly the top 5 or 10 FOSS projects ever (?). Citing Vim as an example of development process failure is really incredible.

Re: The State of Vim

#197

Earlier quoted context omitted.

Just for the other side of the picture, I live in vim and use it as my terminal multiplexer. Vim’s my shell. I have thousands of buffers in vim and practically never leave it. I’ve used terminal multiplexers for years before I switched to vim in that capacity and never looked back. The integration it’s allowed between all my buffers and commands and shells is difficult to match in my opinion.

I'm going to try this. I use tmux but the idea of being able to use vim for everything seems nice. If you have tips/suggestions, I'm interested.

For me, some of the things that's really important for a terminal multiplexer include:

1) Keybindings having no conflicts with other terminal applications. For that, vim's default window-management key of is unfortunate, as it is very important for delete words in bash and readline. I remap that to (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 (). 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 and 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=
    noremap  
    noremap  
    noremap!  

    noremap c 
    noremap  
    noremap  
    noremap! c 
    noremap!  
    noremap!  
    tnoremap c 
    tnoremap  
    tnoremap  
    noremap q 
    noremap! q 
    tnoremap q 
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("\N", "") | endif
     autocmd WinLeave * if (mode() == 't') && (! exists('w:tu')) | call feedkeys("\N", 'x') | call Normalcursor () | elseif (mode(1) == 'nt') && (exists('w:tu')) | call feedkeys("i", 'ix') | endif

     tmap   ((mode() == 't') && get(w:, 'outcmd', 1)) ? 'N' : ''
     augroup end
    
    let &t_SI = "\e[6 q\e]12;#FF00DF\"
    let &t_EI = "\e[2 q\e]12;#FF00DF\"
    let &t_ti = "\e[4 q\e]12;#FF00DF\"
    let &t_te = "\e[2 q\e]12;#FF00DF\"
    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\" 
     let &t_vi ="\e[2 q\e]12;#FF00DF\"
     endfunction
    function! Echonormalcursor ()
     call echoraw("\e[2 q\e]12;#FF00DF\")
     endfunction
    function! Termcursor ()
     let &t_ve ="\e[4 q\e]12;#FF00DF\"
     let &t_vi ="\e[4 q\e]12;#FF00DF\"
     endfunction
    function! Echotermcursor ()
     call echoraw("\e[4 q\e]12;#FF00DF\")
     endfunction
    
    augroup termcursor
     au!
     autocmd ModeChanged *:n* let &t_ve ="\e[2 q\e]12;#FF00DF\"
     autocmd ModeChanged *:n* let &t_vi ="\e[2 q\e]12;#FF00DF\"
     autocmd ModeChanged i:* if &t_ve == "" | let &t_ve ="\e[2 q\e]12;#FF00DF\" | endif
     autocmd ModeChanged i:* if &t_vi == "" | let &t_vi ="\e[2 q\e]12;#FF00DF\" | endif
     autocmd ModeChanged *:i* let &t_ve =""
     autocmd ModeChanged *:i* let &t_vi =""
     autocmd ModeChanged *:t call echoraw("\e[4 q\e]12;#FF00DF\")
     autocmd ModeChanged *:t let &t_ve ="\e[4 q\e]12;#FF00DF\"
     autocmd ModeChanged *:t let &t_vi ="\e[4 q\e]12;#FF00DF\"
     autocmd ModeChanged t:* call echoraw("\e[2 q\e]12;#FF00DF\")
     autocmd ModeChanged t:* if (mode(1) != 'ct') | let &t_ve ="\e[2 q\e]12;#FF00DF\" | endif
     autocmd ModeChanged t:* if (mode(1) != 'ct') | let &t_vi ="\e[2 q\e]12;#FF00DF\" | endif
    
     let g:cmdlinedepth = 0
     autocmd CmdlineEnter * let g:cmdlinedepth = g:cmdlinedepth + 1 | let &t_ve = "\e[4 q\e]12;#FF00DF\" | let &t_vi = "\e[4 q\e]12;#FF00DF\"
     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\" | let &t_vi ="\e[2 q\e]12;#FF00DF\"
     autocmd CmdwinLeave * let &t_ve = "\e[4 q\e]12;#FF00DF\" | let &t_vi = "\e[4 q\e]12;#FF00DF\"
     
     " autocmd WinEnter * call echoraw("\e[2 q\e]12;#FF00DF\")

Re: The State of Vim

#198

Earlier quoted context omitted.

I'm going to try this. I use tmux but the idea of being able to use vim for everything seems nice. If you have tips/suggestions, I'm interested.

For me, some of the things that's really important for a terminal multiplexer include: 1) Keybindings having no conflicts with other terminal applications. For that, vim's default window-management key of is unfortunate, as it is very important for delete words in bash and readline. I remap that to (CTRL-Space) instead, which is basically used by no terminal program that I am aware of. The other key binding that trip…

(equivalently, if you use screen; the key point is the \eP and the \e\\ between which the real xterm escape codes go, or else screen will eat your escape codes which will never see the light of day)

    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("\N", "") | endif
     autocmd WinLeave * if (mode() == 't') && (! exists('w:tu')) | call feedkeys("\N", 'x') | call Normalcursor () | elseif (mode(1) == 'nt') && (exists('w:tu')) | call feedkeys("i", 'ix') | endif
    
     tmap   ((mode() == 't') && get(w:, 'outcmd', 1)) ? 'N' : ''
     augroup end
    
    let &t_SI = "\eP\e[6 q\e]12;#FF00DF\\e\\"
    let &t_EI = "\eP\e[2 q\e]12;#FF00DF\\e\\"
    let &t_ti = "\eP\e[4 q\e]12;#FF00DF\\e\\"
    let &t_te = "\eP\e[2 q\e]12;#FF00DF\\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\\e\\" 
     let &t_vi ="\eP\e[2 q\e]12;#FF00DF\\e\\"
     endfunction
    function! Echonormalcursor ()
     call echoraw("\eP\e[2 q\e]12;#FF00DF\\e\\")
     endfunction
    function! Termcursor ()
     let &t_ve ="\eP\e[4 q\e]12;#FF00DF\\e\\"
     let &t_vi ="\eP\e[4 q\e]12;#FF00DF\\e\\"
     endfunction
    function! Echotermcursor ()
     call echoraw("\eP\e[2 q\e]12;#FF00DF\\e\\")
     endfunction
    
    augroup termcursor
     au!
     autocmd ModeChanged *:n* let &t_ve ="\eP\e[2 q\e]12;#FF00DF\\e\\"
     autocmd ModeChanged *:n* let &t_vi ="\eP\e[2 q\e]12;#FF00DF\\e\\"
     autocmd ModeChanged i:* if &t_ve == "" | let &t_ve ="\eP\e[2 q\e]12;#FF00DF\\e\\" | endif
     autocmd ModeChanged i:* if &t_vi == "" | let &t_vi ="\eP\e[2 q\e]12;#FF00DF\\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\\e\\")
     autocmd ModeChanged *:t let &t_ve ="\eP\e[4 q\e]12;#FF00DF\\e\\"
     autocmd ModeChanged *:t let &t_vi ="\eP\e[4 q\e]12;#FF00DF\\e\\"
     autocmd ModeChanged t:* call echoraw("\eP\e[2 q\e]12;#FF00DF\\e\\")
     autocmd ModeChanged t:* if (mode(1) != 'ct') | let &t_ve ="\eP\e[2 q\e]12;#FF00DF\\e\\" | endif
     autocmd ModeChanged t:* if (mode(1) != 'ct') | let &t_vi ="\eP\e[2 q\e]12;#FF00DF\\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\\e\\" | let &t_vi = "\eP\e[4 q\e]12;#FF00DF\\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\\e\\" | let &t_vi ="\eP\e[2 q\e]12;#FF00DF\\e\\"
     autocmd CmdwinLeave * let &t_ve = "\eP\e[4 q\e]12;#FF00DF\\e\\" | let &t_vi = "\eP\e[4 q\e]12;#FF00DF\\e\\"
    
     " autocmd WinEnter * call echoraw("\eP\e[2 q\e]12;#FF00DF\\e\\")
     augroup end

Re: The State of Vim

#199

Earlier quoted context omitted.

I'm going to try this. I use tmux but the idea of being able to use vim for everything seems nice. If you have tips/suggestions, I'm interested.

For me, some of the things that's really important for a terminal multiplexer include: 1) Keybindings having no conflicts with other terminal applications. For that, vim's default window-management key of is unfortunate, as it is very important for delete words in bash and readline. I remap that to (CTRL-Space) instead, which is basically used by no terminal program that I am aware of. The other key binding that trip…

vimrc for 4)

    vnoremap s sgv
    vnoremap v vgv

    nnoremap  w '@_' .. ((v:count1 + (winnr() - 1)) % (winnr('$')) + 1) .. 'w'
    nnoremap  W '@_' .. (((- v:count1 + (winnr() - 1)) % (winnr('$')) + winnr('$')) % (winnr('$')) + 1) .. 'w'
    nnoremap  t '@_' .. ((v:count1 - 1) % (winnr('$')) + 1) .. 'w'
    nnoremap  b '@_' .. (((- v:count1) % (winnr('$')) + winnr('$')) % (winnr('$')) + 1) .. 'w'
    inoremap  
    map! w w
    map! W W
    map! t t
    map! b b
    tmap w Nw
    tmap W NW
    tmap t Nt
    tmap b Nb

Re: The State of Vim

#200

Earlier quoted context omitted.

I'm going to try this. I use tmux but the idea of being able to use vim for everything seems nice. If you have tips/suggestions, I'm interested.

For me, some of the things that's really important for a terminal multiplexer include: 1) Keybindings having no conflicts with other terminal applications. For that, vim's default window-management key of is unfortunate, as it is very important for delete words in bash and readline. I remap that to (CTRL-Space) instead, which is basically used by no terminal program that I am aware of. The other key binding that trip…

Some other things I do:

Invoke 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 m close windows instead:

    noremap m c
    noremap! m c
    tnoremap m c
Make p find the next window if there is no previous window:

    noremap   p ':wincmd p  if win_getid () == ' .. win_getid () .. '  wincmd w  endif '
    noremap!   p ':wincmd p  if win_getid () == ' .. win_getid () .. '  wincmd w  endif '
    tnoremap   p ':wincmd p  if win_getid () == ' .. win_getid () .. '  wincmd w  endif '
Use ~. 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) (~. is in analogy to the SSH quit keybinding ~.).

    noremap   ~. ':silent !screen -X detach'
    noremap!   ~. ':silent !screen -X detach'
    tnoremap   ~. ':silent !screen -X detach'
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   :tab splitgf
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  gt '@_' .. ((v:count1 + (tabpagenr () - 1)) % (tabpagenr('$') ) + 1) .. 'gt'
For ease of moving to the last tab:

    nnoremap  g '@_' .. (((v:count == 0) ? tabpagenr ('$') : v:count)) .. 'gt'
To consistently access the gt family of bindings regardless of mode:

    map gt gt
    map gT gT
    map g g
    map! gt gt
    map! gT gT
    map! g g
    tmap gt Ngt
    tmap gT NgT
    tmap g Ng
When you use 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   T
    nnoremap  T T:tabm -1
To access these two in any mode consistently:

    map!  
    map! T T
    tmap  N
    tmap T NT
Analogously to gt and gT, sometimes you may want to move your tabs around, or split them:

    function! SSStabmadjust(tabmnum)
     if a:tabmnum  s :tab split
    noremap   t '@_:' .. SSStabmadjust ((v:count1 + (tabpagenr () - 1 )) % (tabpagenr('$') ) + 1) .. 'tabm'
    noremap   T '@_:' .. SSStabmadjust (((- v:count1 + (tabpagenr () - 1 )) % (tabpagenr('$') ) + tabpagenr('$') ) % (tabpagenr('$') ) + 1) .. 'tabm'
    noremap    ':' .. ((v:count == 0) ? "" : SSStabmadjust ((v:count % (tabpagenr ('$') )) )) .. 'tabm'
    map! s s
    map! t t
    map! T T
    map!  
    tmap s Ns
    tmap t Nt
    tmap T NT
    tmap  N
Post reply on HN