Skip to Content
Technical Articles
Author's profile photo David Kunz

Why I switched to Neovim

Update: Added Configuration Video Part 1
Update 2: Added Configuration Video Part 2
Update 3: Added Configuration Video Part 3

In my professional career, I’ve exclusively used IDEs for software development even though they:

  • have long startup times
  • are bloated and slow
  • have inefficient key bindings
  • require a mouse

The reason for that is because I desperately needed (and still need) many of their features which plain text editors couldn’t properly provide, namely:

  • language features for all my used languages (go to definition, autocompletion, etc.)
  • a debugger

However, I really like the features of my favourite text editor Vim, it:

  • is 100% keyboard driven
  • has a command centric approach with a huge amount of commands
  • is modal
  • does not need a GUI and can run in your terminal
  • is highly configurable using simple text files
  • has a low memory footprint

Having already invested many years in Vim (which has an immense learning curve), I did not want to give up my acquired skills. Unfortunately, I never managed to add the needed features to Vim.

So instead of adapting Vim to be more IDE-like, I tried to make my IDEs behave more like Vim using plugins and keybindings. Depending on the IDE, this worked to some extend, but I was never really happy with it because a lot of commands were not supported, keystrokes were occasionally ignored, many features still required a mouse and the problem of sluggishness persisted.

My most successful attempt was using VSCode with the Neo Vim extension where keybindings are not just mapped, but a complete instance of Neovim was run inside of VSCode. It worked really well, but the bloat of VSCode, which is an Electron app, still concerned me.

VSCode also introduced two very important innovations: The Language Server Protocol (LSP) and the lesser known Debug Adapter Protocol (DAP), which solve the problem of every editor/IDE having to support every programming language. Now, an editor/IDE only needs to support the LSP and the DAP. These innovations provide unified and standardised access to language and debugger features of specific programming languages.

Vim supports the LSP and DAP through plugins. Neovim is a fork of Vim and has a more modern governance structure (many contributors as opposed to only one), allowing the development of many new features, including native support for the LSP.

And now, after so many years, I finally managed to set up both the LSP and the DAP, providing Neovim with all the language features and debuggers I need. It wasn’t easy to set up and I had to write some scripts, but it works. Finally, there’s no reason to use IDEs anymore. I made the switch.

I created a short demo, showcasing some of the features.

 

I managed to make Neovim’s native LSP client use the LSP server of the SAP Cloud Application Programming Model (CAP) and I added syntax highlighting for cds files. DJ Adamsvideo on cds-lsp was of great help for me.

I can confidently say, I learned a lot during this process and I’ve grown as a programmer. I’m finally comfortable with my development setup and I’m curious of Neovim’s future innovations.

Thanks a lot for your time and keep your programming tools sharp,
David

Assigned tags

      19 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo DJ Adams
      DJ Adams

      Now THIS is the sort of blog post that I love to see on a Monday morning! Awesome and inspiring work, David, thanks for that. And I’m already looking forward to the next installment of your video series 💪(btw, subscribed!)

      Author's profile photo David Kunz
      David Kunz
      Blog Post Author

      Thanks a lot, DJ!

      Author's profile photo Marius Obert
      Marius Obert

      Thanks for this super interesting post, David!
      It's always nice to see how other developers set up their dev environments (even though I'm happy with mouse navigation 😅).

      Author's profile photo David Kunz
      David Kunz
      Blog Post Author

      Thanks a lot Marius Obert!

      Regarding speed, I'm on the Keyboard > Mouse > Touchpad front 🙂

      Author's profile photo Marius Obert
      Marius Obert

      I actually only use the touchpad and almost never touch the mouse 🙈

      Author's profile photo Helmut Tammen
      Helmut Tammen

      Hi David,

      thanks for sharing. I'm also a fan of vim for years but missed a lot of things you mentioned in your video. Curious to read your next blog / watch your next video.

      Author's profile photo David Kunz
      David Kunz
      Blog Post Author

      Hi Helmut,

      I'm glad you found it useful, here's my video on the configuration.

      Best regards,
      David

      Author's profile photo Helmut Tammen
      Helmut Tammen

      Great video!!
      Already copied most of it to my init.vim

      Is there a repository with you configuration on github?

      Can't await the next video. Don't have experience with DAP so far.

      Author's profile photo David Kunz
      David Kunz
      Blog Post Author

      Thanks a lot, Helmut!

      The configuration is available here: https://github.com/David-Kunz/vim/blob/master/init.vim

      Best regards,

      David

      Author's profile photo Nabi Zamani
      Nabi Zamani

      This is just such a treasure! And I thought I did pretty well with my vim configuration so far. I was so wrong 😀

      I absolutely enjoy how you precisely focus and how you cover exactly what needs to be told.

      Thank You!

      Author's profile photo David Kunz
      David Kunz
      Blog Post Author

      Hi Nabi Zamani,

      Thanks a lot for your kind words!

      Author's profile photo Jason Scott
      Jason Scott

      David Kunz  I  also use vim where possible. Some awesome ideas here which I’ve now adopted. Wondering with the LSP if it’s possible to also get the annotations editors to work.
      Does the cds lsp also include annotations in the cds files?

      Author's profile photo David Kunz
      David Kunz
      Blog Post Author

      Hi Jason,

      Great to see another Vim user! I haven't tried the server for annotations yet, but in principle it should also work.

      There's a plugin https://github.com/hrsh7th/nvim-cmp which should allow you to use snippets from your server.

      Best regards,
      David

      Author's profile photo Jason Scott
      Jason Scott

      Hi David Kunz I'm trying to work out how you have got the CDS LSP working... Watching DJ's videos shows that he's using ALE for the LSP integration; however from your init.vim file I can see you're not using that.

      So where do you place the CDS syntax file and what does your "$HOME/projects/startcdslsp" script look like?

      Author's profile photo David Kunz
      David Kunz
      Blog Post Author

      Hi Jason Scott ,

      Yes, I got it working with the following configuration:

       

      // init.lua:

      local lspconfig = require'lspconfig'
      local configs = require'lspconfig/configs'
      local on_attach = function(client, bufnr)
          local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end
          buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')
      end
      
      configs.sapcds_lsp = {
        default_config = {
          cmd = {vim.fn.expand("$HOME/projects/startcdslsp")}; -- this executable must be there
          filetypes = {'cds'};
          root_dir = function(fname)
            return vim.fn.getcwd()
          end;
          settings = {};
        };
      }
      if lspconfig.sapcds_lsp.setup then
        lspconfig.sapcds_lsp.setup{ on_attach = on_attach }
      end
      
      cmd([[
      augroup MyCDSCode
           autocmd!
           autocmd BufReadPre,FileReadPre *.cds set ft=cds
      augroup END
      ]])
      

      and the syntax file in ~/.config/nvim/syntax/cds.vim

      if exists("b:current_syntax")
        finish
      endif
      
      syntax match cdsComment "\v\/\/.*$"
      syntax region cdsComment start="\v/\*" end="\v\*/"
      
      syntax match cdsOtherStuff /=/
      syntax match cdsAnnotation /\v\@\S*/
      
      syntax match supportClassCds /\v(<|>)(Association to (one|many|)|Composition of (one|many|)|Boolean|Date|Time|DateTime|Timestamp|Number|Integer|Decimal|String)(<|>)/
      syntax match keywordStrongCds /\v(<|>)(key|as|on|with|namespace|import|using|define|extend|annotate|expose|context|service|abstract|aspect|entity|projection|view|event|type|facet|annotation|actions|action|function)(<|>)/
      syntax match keywordStrongControlCds /\v(<|>)from(<|>)/
      syntax region stringQuotedSingleCds start="\v'" end="\v'"
      syntax region stringQuotedDoubleCds start="\v\"" end="\v\""
      
      highlight link keywordStrongCds           Keyword
      highlight link keywordStrongControlCds    Keyword
      highlight link cdsOtherStuff              Keyword
      highlight link cdsComment                 Comment
      highlight link stringQuotedSingleCds      String
      highlight link stringQuotedDoubleCds      String
      highlight link supportClassCds            Constant
      highlight link cdsAnnotation              Function
      
      let b:curent_syntax = "cds"
      

       

      autocomplete

       

      autocomplete

      Author's profile photo Jason Scott
      Jason Scott

      David Kunz thanks. I have it sort-of working now.

      I just installed the cds-lsp via npm i -g @sap/cds-lsp and pointed the startcdslsp script to the executable.

      So I can start nvim and open a cds file. Syntax highlighting works... but commands like go-to-defintion and so on only work once and then not again. After the first use I get errors like this in the file:

      using {
      E 2 managed, ■ Artifact “managed” has not been found
      E 3 Currency, ■ Artifact “Currency” has not been found
      E 4 sap.common.CodeList ■ Artifact “sap” has not been found
      5 } from './common';

      It can no longer resolve any CDS dependencies. So I need to exit nvim and open it again for it to work each time.

       

      btw. I'm using an init.vim file and not init.lua - however it has the same code in it like so:

      " CDS - Add @sap/cds-lsp to lspconfig
      augroup MyCDSCode
          autocmd!
          autocmd BufReadPre,FileReadPre *.cds set ft=cds
      augroup END
      lua << EOF
      local lspconfig = require'lspconfig'
      local configs = require'lspconfig/configs'
      local on_attach = function(client, bufnr)
          local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end
          buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')
      end
      
      configs.sapcds_lsp = {
        default_config = {
          cmd = {vim.fn.expand("$HOME/dev/startcdslsp")}; -- this executable must be there
          filetypes = {'cds'};
          root_dir = function(fname)
            return vim.fn.getcwd()
          end;
          settings = {};
        };
      }
      if lspconfig.sapcds_lsp.setup then
        lspconfig.sapcds_lsp.setup{ on_attach = on_attach }
      end
      EOF
      
      Author's profile photo David Kunz
      David Kunz
      Blog Post Author

      Hi Jason Scott ,

      Yes, init.vim is also fine!

      I think you always make sure
      1) to install the dependencies, so you have a local node_modules folder
      2) that the root path is correct, you can check that with :LspInfo

      Best regards,
      David

      Author's profile photo Jason Scott
      Jason Scott

      Hi David Kunz  I think I found the issue by fluke. I simply ran :LspRestart and now it all works fine and I can 'gd' and ctrl-o back all day long.
      Maybe exiting neovim is not killing the cdslsp process such that all my config changes weren't taking effect?!? All good now.

      Author's profile photo David Kunz
      David Kunz
      Blog Post Author

      Hi Jason Scott ,

      That's good to hear, glad it works!

      Best regards,
      David