ONE DUDE`S BLOG

/media/28ef3400-a805-11eb-90a1-572baa95ca30.webp

Neovim - современная замена vim

29.01.2022
Настройка 1 Из лучших текстовых редакторов. Список плагинов.

Для тех кто хочет просто что-то скопировать, вам сюда

Про neovim

:ID: neovim

Neovim - логическая замена другого, более древнего редактора - vim

Почему именно neovim? Все просто, vim/neovim это 1 из лучших редакторов кода, он сочитает в себе относительно большое количество преимуществ:

  • Скорость работы с текстом. Она просто на несколько порядков выше чем у аналогичных инструментов, таких как idea/vscode/sublime и т.д.

    Сама по себе, скорость работы не столь важна, т.к. большинство времени разработчик тратит на аналитические процессы, однако, работа с кодом не отрываясь от клавиатуры, приводит к следующему эффекту

  • Минимизация дополнительных когнетивных нагрузок. Каждый раз, когда я отвлекался на перетягивания панелек мышкой, выделение куска текста для того чтобы скопировать его, установку каретки на нужную строку..я тратил свою концентрацию, я задумывался над этим. Это очень похоже на императивное и декларативное программирование. Вим позволяет не задумываться над тем как сделать, он позволяет переложить ответственность исполнения на мышечную память, которая не требует участия мозга. Это неплохо расслабляет, настолько, что когда я пытался вернуться в иде, я просто не осилил.

  • Производительность. Тут все просто, неовим ОЧЕНЬ быстрый редактор, сильно быстрее чем intellij idea, vscode и emacs. Оy открывает гигантские файлы за какие-то доли секунды. При этом потребление памяти весьма скромное. С полным обвесом оно не достигает даже 150мб (потребление памяти я не отношу к плюсу, т.к. на сегодняшний день, железо это не большая проблема)

  • Комьюнити. В виме прекрасное комьюнити, огромное количество хорошо реализованных плагинов на достаточном уровне качества.

  • Ты начнешь лучше понимать cli, unix, ast (abstract syntax tree), а также то, как работают языки программирования (насколько это полезные навыки? решать тебе)

Преимущества перед vim

  • Lua. Lua это язык на котором конфигурируется neovim, при этом, для любителей vimscript, также нашлось место непонятно правда зачем, vimscript ужасен.
  • Встроенный lsp (language server protocol), позволяющий взаимодействовть с большим количеством языков программирования и фреймворков.

Установка neovim

Посмотреть можно тут Для macos

brew install neovim

Пакетный менеджер Packer.nvim

Официальный репозиторий packer

Установка

git clone https://github.com/wbthomason/packer.nvim\
 ~/.local/share/nvim/site/pack/packer/start/packer.nvim

Перед всеми скриптами использовать следующее:

local execute = vim.api.nvim_command
local fn = vim.fn

local install_path = fn.stdpath('data')..'/site/pack/packer/opt/packer.nvim'

if fn.empty(fn.glob(install_path)) > 0 then
  execute('!git clone https://github.com/wbthomason/packer.nvim '..install_path)
  execute 'packadd packer.nvim'
end

plugins.lua

return require('packer').startup(function(use)
    use 'wbthomason/packer.nvim'
    ...
end)

Основные настройки

Настройки

Настройка подсветки

cmd "hi clear CursorLine"
cmd "hi cursorlinenr guibg=NONE guifg=#abb2bf"

cmd "set nobackup"
cmd "set nowritebackup"
cmd "hi LineNr guifg=#42464e guibg=NONE"
cmd "hi Comment guifg=#42464e"

cmd "hi SignColumn guibg=NONE"
cmd "hi VertSplit guibg=NONE guifg=#2a2e36"
cmd "hi EndOfBuffer guifg=#1e222a"
cmd "hi PmenuSel guibg=#98c379"
cmd "hi Pmenu  guibg=#282c34"

Навигация с разным выбранным языком (Ru/en)

cmd "set langmap=ФИСВУАПРШОЛДЬТЩЗЙКЫЕГМЦЧНЯ;ABCDEFGHIJKLMNOPQRSTUVWXYZ,фисвуапршолдьтщзйкыегмцчня;abcdefghijklmnopqrstuvwxyz"

Табуляция

vim.api.nvim_exec(
    [[
  set tabstop=2
  set shiftwidth=2
  set expandtab
  set smartindent
  ]], false)

Persistent Undo между сессиями

vim.api.nvim_exec(
[[
  set undodir=~/.vim/undodir
  if !isdirectory("/tmp/.vim-undo-dir")
    call mkdir("/tmp/.vim-undo-dir", "", 0700)
  endif
  set undodir=/tmp/.vim-undo-dir
  set undofile
]], false)

Folding

vim.api.nvim_exec([[
  set foldmethod=indent
  set foldnestmax=10
  set nofoldenable
  set foldlevel=2
  set foldcolumn=0
  highlight foldcolumn guibg=none
]], false)

Сочитания клавиш

-- Quick window resize
vim.api.nvim_set_keymap(
    "n",
    "<S-l>",
    ":vertical resize -5<CR>",
    {
        noremap = true,
        silent = true
    }
)
vim.api.nvim_set_keymap(
    "n",
    "<S-h>",
    ":vertical resize +5<CR>",
    {
        noremap = true,
        silent = true
    }
)

vim.api.nvim_set_keymap(
    "n",
    "<S-j>",
    ":resize +5<CR>",
    {
        noremap = true,
        silent = true
    }
)

vim.api.nvim_set_keymap(
    "n",
    "<S-k>",
    ":resize -5<CR>",
    {
        noremap = true,
        silent = true
    }
)

-- Exit current buffer
vim.api.nvim_set_keymap(
    "n",
    "<Leader>q",
    ":bp<bar>sp<bar>bn<bar>bd<CR>",
    {
        noremap = true,
        silent = true
    }
)

-- Save/past clipboard
cmd 'noremap <Leader>y "+y'
cmd 'noremap <Leader>p "+p'

vim.api.nvim_exec([[
  :nmap <c-s> :w<CR>
  :imap <c-s> <Esc>:w<CR>a
]], false)

Множественная вставка без загрязнения текущего буфера

vim.api.nvim_exec([[
  xnoremap <expr> p 'pgv"'.v:register.'y`>'
  xnoremap <expr> P 'Pgv"'.v:register.'y`>'
]], false) -- multiple past without buffer trash

Плагины

Визуальная составляющая

Lualine - neovim status line

Lualine - Плагин для гибкой настройки статус бара

Отключение статус лайна для файлового менеджера

vim.api.nvim_exec([[
  function! DisableST()
  return " "
  endfunction
  au BufEnter NvimTree setlocal statusline=%!DisableST()
]], false)

Keybindings

Для работы с кейбиндами я использую whichkey - пакет для декларативной настройки сочетаний клавиш в neovim. Также, он позволяет напоминать о используемых сочетаниях клавиш, показывая их с небольшой задержкой. Данный пакет будет использоваться для настройки кейбиндов практически всех плагинов.

Я заранее создал 2 полезных сочитания клавиш, это SPC m e b для перекомпиляции текущего открытого буфера настроек, а также SPC h r e для перезагрузки конфигов и установки новых плагинов через packer. Остальные настройки можно посмотреть в моем репозитории.

Основные сочитания клавиш
local wk = require("which-key")

wk.register(
    {
        m = {
            name = "Compile",
            e = {
                b = {':luafile %<CR>:echo "Compiled!"<CR>', "Compile current lua file"}
            }
        },
        h = {
            name = "Hot",
            r = {
                name = "Reload",
                e = {
                    ":source ~/.config/nvim/lua/plugins.lua<CR>:source $MYVIMRC<CR>:PackerSync<CR>:echo 'Reloaded!'<CR>",
                    "Reload neovim"
                }
            }
        },
        -- ...
    },
    { prefix = "<space>" }
)

Программирование

Автодополнение с помощью nvim-cmp

Настройк автокомплита + tabnine + закругленных краев

Packer:

        use "hrsh7th/cmp-nvim-lsp"
        use "hrsh7th/cmp-buffer"
        use "hrsh7th/cmp-path"
        use "hrsh7th/cmp-cmdline"
        -- use "hrsh7th/nvim-cmp"
        use {"Iron-E/nvim-cmp", branch = "feat/completion-menu-borders"}
        use {"tzachar/cmp-tabnine", run = "./install.sh", requires = "hrsh7th/nvim-cmp"}
local tabnine = require("cmp_tabnine.config")
local cmd = vim.cmd
tabnine:setup(
    {
        max_lines = 1000,
        max_num_results = 20,
        sort = true,
        run_on_every_keystroke = true,
        snippet_placeholder = "..",
        ignored_file_types = {}
    }
)

local cmp = require "cmp"
local lspkind = require("lspkind")

cmd "set completeopt=menu,menuone,noselect"
cmd "highlight! CmpItemKindMethod guibg=NONE guifg=LightYellow"

cmp.setup(
    {
      window = {
        completion = {border = {"╭", "─", "╮", "│", "╯", "─", "╰", "│"}, scrollbar = "║"},
        documentation = {
            border = {"╭", "─", "╮", "│", "╯", "─", "╰", "│"},
            scrollbar = "║"
        },
      },
        -- win_mode = "rounded",
        snippet = {
            -- REQUIRED - you must specify a snippet engine
            expand = function(args)
                vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users.
                -- require('luasnip').lsp_expand(args.body) -- For `luasnip` users.
                -- vim.fn["UltiSnips#Anon"](args.body) -- For `ultisnips` users.
                -- require'snippy'.expand_snippet(args.body) -- For `snippy` users.
            end
        },
        mapping = {
            ["<C-b>"] = cmp.mapping(cmp.mapping.scroll_docs(-4), {"i", "c"}),
            ["<C-f>"] = cmp.mapping(cmp.mapping.scroll_docs(4), {"i", "c"}),
            ["<C-Space>"] = cmp.mapping(cmp.mapping.complete(), {"i", "c"}),
            ["<C-y>"] = cmp.config.disable, -- Specify `cmp.config.disable` if you want to remove the default `<C-y>` mapping.
            ["<C-e>"] = cmp.mapping(
                {
                    i = cmp.mapping.abort(),
                    c = cmp.mapping.close()
                }
            ),
            -- Accept currently selected item. If none selected, `select` first item.
            -- Set `select` to `false` to only confirm explicitly selected items.
            -- ['<CR>'] = cmp.mapping.confirm({ select = true }),
            ["<C-j>"] = cmp.mapping.select_next_item({behavior = cmp.SelectBehavior.Insert}),
            ["<C-k>"] = cmp.mapping.select_prev_item({behavior = cmp.SelectBehavior.Insert}),
            ["<Tab>"] = cmp.mapping(cmp.mapping.select_next_item(), {"i", "s"}),
            ["<S-Tab>"] = cmp.mapping(cmp.mapping.select_prev_item(), {"i", "s"}),
            ["<CR>"] = cmp.mapping.confirm(
                {
                    behavior = cmp.ConfirmBehavior.Replace,
                    select = true
                }
            )
        },
        sources = cmp.config.sources(
            {
                {name = "cmp_tabnine"},
                {name = "nvim_lsp"},
                {name = "orgmode"}
                -- { name = 'vsnip' }, -- For vsnip users.
                -- { name = 'luasnip' }, -- For luasnip users.
                -- { name = 'ultisnips' }, -- For ultisnips users.
                -- { name = 'snippy' }, -- For snippy users.
            },
            {
                {name = "buffer"}
            }
        ),
        formatting = {
            format = lspkind.cmp_format()
        },
        experimental = {native_menu = false}
    }
)

-- Use buffer source for `/` (if you enabled `native_menu`, this won't work anymore).
cmp.setup.cmdline(
    "/",
    {
        sources = {
            {name = "buffer"}
        }
    }
)

-- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore).
cmp.setup.cmdline(
    ":",
    {
        sources = cmp.config.sources(
            {
                {name = "path"}
            },
            {
                {name = "cmdline"}
            }
        )
    }
)

LSP (language server protocol)

Настройка lua

Инструкция по установке lua lsp

local runtime_path = vim.split(package.path, ";")
table.insert(runtime_path, "lua/?.lua")
table.insert(runtime_path, "lua/?/init.lua")

nvim_lsp.sumneko_lua.setup {
    apabilities = capabilities,
    on_attach = on_attach,
    settings = {
        Lua = {
            runtime = {
                -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim)
                version = "LuaJIT",
                -- Setup your lua path
                path = runtime_path
            },
            diagnostics = {
                -- Get the language server to recognize the `vim` global
                globals = {"vim", "use", "bubbles_theme"}
            },
            workspace = {
                -- Make the server aware of Neovim runtime files
                library = vim.api.nvim_get_runtime_file("", true)
            },
            -- Do not send telemetry data containing a randomized but unique identifier
            telemetry = {
                enable = false
            }
        }
    }
}

LSP stylelint

require "lspconfig".stylelint_lsp.setup {
    settings = {
        stylelintplus = {}
    }
}
Yaml

Перед настройкой: npm i -g yaml-language-server

require("lspconfig").yamlls.setup {
    settings = {
        yaml = {
            schemas = {
                ["https://json.schemastore.org/github-workflow.json"] = "/.github/workflows/*",
                ["https://raw.githubusercontent.com/instrumenta/kubernetes-json-schema/master/v1.18.0-standalone-strict/all.json"] = "/*.k8s.yaml",
            }
        }
    }
}
Angular

Перед настройкой необходимо установить Angular LSP

local project_library_path = "/usr/local/lib/node_modules"
local cmd = {
    "ngserver",
    "--stdio",
    "--tsProbeLocations",
    project_library_path,
    "--ngProbeLocations",
    project_library_path
}

require "lspconfig".angularls.setup {
    cmd = cmd,
    on_new_config = function(new_config, new_root_dir)
        new_config.cmd = cmd
    end
}

Улучшенная подсветка синтаксиса с помощью tree sitter.

Nvim autopair

Настройка, с учетом nvm-cmp
require("nvim-autopairs").setup(
    {
        disable_filetype = {"TelescopePrompt", "vim"}
    }
)

-- If you want insert `(` after select function or method item
local cmp_autopairs = require("nvim-autopairs.completion.cmp")
local cmp = require("cmp")
cmp.event:on("confirm_done", cmp_autopairs.on_confirm_done({map_char = {tex = ""}}))

Автоформатирование

Настройка
g.neoformat_javascript_prettier = {
    exe = "./node_modules/.bin/prettier",
    args = {"--write", "--config .prettierrc"},
    replace = 1
}
g.neoformat_typescript_prettier = {
    exe = "./node_modules/.bin/prettier",
    args = {"--write", "--config .prettierrc"},
    replace = 1
}

vim.api.nvim_exec(
    [[
let g:neoformat_javascript_prettier = {
      \ 'exe': './node_modules/.bin/prettier',
      \ 'args': ['--write', '--config .prettierrc'],
      \ 'replace': 1
      \ }
]],
    false
)

Отладка

Html

Терминал

Поиск с помощью telescope.

GIT

Файловые менеджеры

Работа с текстом

Другие полезные утилиты

Полные настройки можно посмотреть в моем репозитории

vim
workspace
редактор кода
neovim
2
9910