DEV Community

JT Ziolo
JT Ziolo

Posted on

Full NeoVim Config and Explanations for VSCode-NeoVim Users

Since around February of this year (2023), I've been doing most of my coding using the VSCode-NeoVim extension. For a while now, I've been interested in seeing what a plugin-enhanced NeoVim has to offer in terms of a full IDE experience. Unfortunately, every time I've tried to set up something like NvChad or LunarNvim, I've run into the same set of problems:

  • I don't need all of the plugins.
  • I don't know what many of the plugins are for.
  • I don't agree with the keybinds (they are almost always completely different than equivalent actions I've memorized when working in VSCode).

Even though I can fix all of the above, I don't want to spend a week doing that when:

  • I'm not the person who set up the plugins.
  • The NeoVim config code is split up across multiple files for some reason.
  • I have a working code editor already.

So until recently, I just stuck with VSCode-NeoVim. However, I recently had a breakthrough. After many phind searches and going through a lot of stack overflow posts of varying quality, I figured out how to set up NeoVim to include all the essential features of an IDE: a file browser, command palette, autocomplete, code actions, etc.

While doing so, I split up my init.lua file so that NeoVim will still work in VSCode-NeoVim.

My Configuration

Here is a gist containing my current init.lua file: https://gist.github.com/jt-ziolo/cac64c2d17d6036fc6a61a26898b91b2.

My NeoVim configuration, shown for a NextJS project

Here is a barebones example which shows how the init.lua file is set up:

vim.g.mapleader = " " -- Make sure to set `mapleader` before lazy so your mappings are correct

-- Set up lazy.nvim (the plugin manager)
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
    vim.fn.system({
        "git",
        "clone",
        "--filter=blob:none",
        "https://github.com/folke/lazy.nvim.git",
        "--branch=stable", -- latest stable release
        lazypath,
    })
end
vim.opt.rtp:prepend(lazypath)

if vim.g.vscode then
    -------------------------------------------------------------------
    -- The following applies ONLY for VSCode-NeoVim
    -- Everything under require("lazy") will be a subset of what is
    -- included in the settings for ordinary NeoVim
    -------------------------------------------------------------------

    require("lazy").setup({
        -- Plugin installs, which either just point to the github repo
        -- or which are based on lazy.nvim-specific instructions from
        -- the repo
    })

    -- Some settings can go here
    -- but I'm not sure what yet

    -- Requires
    -----------
    -- ex: require("hop").setup({})
    -- You will likely not put anything here
    -- ...

    -- Keybinds
    -----------
    -- ex: vim.keymap.set("n", "n", "nzz", {})
    -- ...
else
    -------------------------------------------------------------------
    -- The following applies ONLY for ordinary Neovim outside of VSCode
    -------------------------------------------------------------------

    require("lazy").setup({
        -- Plugin installs, which either just point to the github repo
        -- or which are based on lazy.nvim-specific instructions from
        -- the repo. The difference here is that you include plugins
        -- related to LSP functionality, code completion, etc.
    })

    -- Some settings can go here
    -- ex: vim.diagnostic.config({ virtual_text = false })

    -- Requires
    -----------
    -- ex: require("onedark").load()
    -- ...

    -- Keybinds
    -----------
    -- ex: vim.keymap.set("n", "<leader>i", "<cmd>Neoformat<CR>", { desc = "Neoformat" })
    -- ...
end

-------------------------------------------------------------------
-- The following applies for BOTH VSCode and ordinary Neovim
-- Note that we cannot call require("lazy").setup here,
-- so load your plugins in the prior two sections
-------------------------------------------------------------------

-- Requires
-----------
-- ex: require("hop").setup({})
-- ...

-- Keybinds
-----------
-- ex: vim.keymap.set("n", "n", "nzz", {})
-- ...

Enter fullscreen mode Exit fullscreen mode

What the Plugins Do

First off, let's define what "LSP" means:

The Language Server Protocol (LSP) defines the protocol used between an editor or IDE and a language server that provides language features like auto complete, go to definition, find all references etc. (https://microsoft.github.io/language-server-protocol/)

Many of the plugins that I will list are focused on LSP management and integration, so knowing what is meant by LSP will help you as you read through plugin documentation.

Here is a list of the important plugins and what they do, in terms that someone coming from VSCode could understand. Note that I have listed just the particular plugin that I'm currently using, but multiple options may exist. For example: snippy is just one option for adding a snippet system, other options I know of are vsnip, ultisnips, and luasnip and I'm certain that there are others out there.

Repo What It Does
"dcampos/nvim-snippy" Provides a snippet system
"dcampos/cmp-snippy" Integrates the snippet system with suggestions/autocomplete as you type
"hrsh7th/cmp-cmdline" Suggestions/autocomplete for NeoVim commands as you type (e.g. :write)
"hrsh7th/cmp-buffer" Suggestions/autocomplete for searches (/ and ?) as you type
"hrsh7th/cmp-nvim-lsp" Dependency for some plugins that interface with the LSP
"rsh7th/nvim-cmp" Dependency for previous 3 plugins
"jay-babu/mason-null-ls.nvim" Sets up Mason to work with null-ls
"jose-elias-alvarez/null-ls.nvim Dependency that is required by plugins which need to access code completion, warnings/errors (diagnostics), code actions, and related suggestion functionality
"neovim/nvim-lspconfig" Dependency that allows code completion, warnings/errors (diagnostics), code actions, and related suggestion functionality. Its an official neovim plugin.
"nvim-lua/plenary.nvim" A library of helper functions for neovim that is required by many plugins.
"nvim-telescope/telescope.nvim" Think of it as a replacement for the command palette.
"nvim-tree/nvim-tree.lua" A replacement for the explorer menu.
"nvim-treesitter/nvim-treesitter" Dependency which manages and provides access to the syntax tree for the current file, which is needed by plugins for things like detecting syntax errors, figuring out where an editor symbol is located in files, etc.
"sbdchd/neoformat" Formats files using any formatters you have installed.
"williamboman/mason-lspconfig.nvim" Allows the NeoVim LSP service to "see" the LSPs installed via Mason.
"williamboman/mason.nvim" Used to install/update formatters, LSPs, debuggers, and linters. Those things won't actually work without you installing other plugins, though.
"akinsho/bufferline.nvim" The tab bar on top of your editor, showing open tabs (buffers)
"folke/zen-mode.nvim" Zen mode
"nvim-lualine/lualine.nvim" The bottom bar that shows your current mode, the file name, scroll percentage, line/character number, git status, etc.
"nvim-tree/nvim-web-devicons" Dependency that is used to provide icons next to files for nvim-tree, and which is used by many other plugins as a source of devicons.
"nvimdev/lspsaga.nvim" Provides a better experience for things like renaming symbols, getting a floating terminal, showing a menu for the symbol under the cursor, etc. I use it mainly for navigating errors/warnings (diagnotics) with quick access to code actions. The documentation is full of screenshots: https://dev.neovim.pro/lspsaga/
"onsails/lspkind-nvim" Adds symbols to the suggestion/autocomplete window
"tpope/vim-eunuch" It lets you change the currently opened file, including renaming, changing permissions, deletion, etc. I'm not sure why it's called eunuch either, but it's made by tpope, and everything he makes is gold.
"windwp/nvim-autopairs" Auto-closes quotes, braces, parentheses, etc.
"windwp/nvim-ts-autotag" Auto-closes HTML, XML, and other markup tags as you type them.

I hope that this post helps you understand the role of each plugin, while avoiding the annoying experience of searching around for answers about what X error message means, figuring out what a plugin does, reading through pedantic responses about how it should be so clear and obvious to do something based on NeoVim's documentation... etc.

Why is It So Complicated?

One concept that some readers may struggle with (and which I had also struggled with) is why so many plugins are needed to get basic IDE features.

NeoVim, like vim, is minimalistic in its design. Out of the box (without any plugins installed), NeoVim is a very simple editor with modal text editing capabilities, sort of like Notepad++. Maybe this is all you want or need. For example, you don't need those IDE features if you only install NeoVim as a dependency for VSCode-NeoVim (nor would you want it, since they would probably conflict with VSCode).

However, if you do want IDE features, NeoVim's plugin capabilities and ecosystem are mature enough that you can add them. This allows you to set up a custom configuration tailored to your use, without the bloat of unused features or plugins.

Top comments (1)

Collapse
 
cadnav profile image
</cadnav>

Thanks, I’m interested in trying this. Would have been nice to preview some screenshots hehe. It’s still early, perhaps you can add em