Neovim Notes

2021-04-04 约 3181 字 预计阅读 7 分钟

Neovim-0.5版本集成了LSP,并且内置用lua来配置vim和编写vim插件,本来4月18号就该发布0.5版本了,已经过期7天了,还好可以使用nightly版本, 记录一下Nvim的配置过程,主要是LSP的集成,但是正式版本还没有发布,部分api和插件可能还有变化.

1. TODO

  • 新的lspconfig插件里添加了code-action,修改一下配置
  • 配置好python的环境
  • 配置好js/vue/ts的环境
  • 分离和转换配置为lua
  • fzf
  • start screen
  • statusline
  • 自动补全有问题
  • 什么是Text object, 如何定义
  • command command bang! 这些怎么用
  • LSP
    • treesitter集成
    • telescope集成
    • lspsaga集成
    • barbar配置,暂时没有需求
    • vista配置
    • 集成telescope来增强lsp支持
    • 集成lspsaga?,之前有错误
    • [-] 确保lsp的基本功能可用
      • 格式化
      • 补全
      • 自动import(lspsaga的code action里有)
      • diagnostics
      • workspace
      • code action, range action
      • finder
      • type defintion
      • outline
      • symbols
      • rename
      • refactor
    • 对齐插件

2. 问题

  • 如何配置
  • pyright怎么识别python的虚拟环境
  • 配置lua和init.vim分离
  • 补全插件和配置
  • 导航插件
  • 拆分nvim的配置

3. 学习

4. Reference

5. Commands

重启LSP server

1
:lua require('lspconfig').pyright.autostart()

检查是否启动

1
:lua print(vim.inspect(vim.lsp.buf_get_clients())) 

6. LSP

nvm0.5的核心功能,通过lua扩展实现了LSP,Neovim核心团队实现的LSP插件

参考: nvm-lspconfig

安装完插件以后就可以使用了

1
require'lspconfig'.<server>.setup{<config>}

6.1. setup方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
lspconfig.SERVER.setup{config}

  The `config` parameter has the same shape as that of
  |vim.lsp.start_client()|, with these additions and changes:

  {root_dir}
    Required for some servers, optional for others.
    Function of the form `function(filename, bufnr)`.
    Called on new candidate buffers being attached-to.
    Returns either a root_dir or nil.

    If a root_dir is returned, then this file will also be attached. You
    can optionally use {filetype} to help pre-filter by filetype.

    If a root_dir is returned which is unique from any previously returned
    root_dir, a new server will be spawned with that root_dir.

    If nil is returned, the buffer is skipped.

    See |lspconfig.util.search_ancestors()| and the functions which use it:
    - |lspconfig.util.root_pattern(pattern1, pattern2...)| is a variadic function which
      takes string patterns as arguments, and finds an ancestor 
      which contains one of the files matching the pattern. 
      Each pattern can be a specific filename, such as ".git", or a glob.  
      See `:help glob` for allowed patterns.  This is equivalent to
      coc.nvim's "rootPatterns"
    - Related utilities for common tools:
      - |lspconfig.util.find_git_root()|
      - |lspconfig.util.find_node_modules_root()|
      - |lspconfig.util.find_package_json_root()|

  {name}
    Defaults to the server's name.

  {filetypes}
    Set of filetypes to filter for consideration by {root_dir}.
    May be empty.
    Server may specify a default value.

  {autostart}
    Whether to automatically start a language server when a matching filetype is detected.
    Defaults to true.

  {settings}
    Map with case-sensitive keys corresponding to `workspace/configuration`
    event responses.
    We also notify the server *once* on `initialize` with
    `workspace/didChangeConfiguration`.
    If you change the settings later on, you must emit the notification
    with `client.workspace_did_change_configuration({settings})`
    Example: `settings = { keyName = { subKey = 1 } }`

  {on_attach}
    `function(client, bufnr)` Runs the on_attach function from the client's 
    config if it was defined. Useful for doing buffer-local setup.

  {on_new_config}
    `function(new_config, new_root_dir)` will be executed after a new configuration has been
    created as a result of {root_dir} returning a unique value. You can use this
    as an opportunity to further modify the new_config or use it before it is
    sent to |vim.lsp.start_client()|. If you set a custom `on_new_config`, ensure that 
    `new_config.cmd = cmd` is present within the function body.

6.2. 自定义配置

自己定义的一个lsp服务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
local lspconfig = require'lspconfig'
local configs = require'lspconfig/configs'
-- Check if it's already defined for when reloading this file.
if not lspconfig.foo_lsp then
  configs.foo_lsp = {
    default_config = {
      cmd = {'/home/ashkan/works/3rd/lua-language-server/run.sh'};
      filetypes = {'lua'};
      root_dir = function(fname)
        return lspconfig.util.find_git_ancestor(fname) or vim.loop.os_homedir()
      end;
      settings = {};
    };
  }
end
lspconfig.foo_lsp.setup{}

6.3. 补全和键绑定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
local nvim_lsp = require('lspconfig')
local on_attach = function(client, bufnr)
  local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
  local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end

  buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')

  -- Mappings.
  local opts = { noremap=true, silent=true }
  buf_set_keymap('n', 'gD', '<Cmd>lua vim.lsp.buf.declaration()<CR>', opts)
  buf_set_keymap('n', 'gd', '<Cmd>lua vim.lsp.buf.definition()<CR>', opts)
  buf_set_keymap('n', 'K', '<Cmd>lua vim.lsp.buf.hover()<CR>', opts)
  buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
  buf_set_keymap('n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
  buf_set_keymap('n', '<space>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)
  buf_set_keymap('n', '<space>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)
  buf_set_keymap('n', '<space>wl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)
  buf_set_keymap('n', '<space>D', '<cmd>lua vim.lsp.buf.type_definition()<CR>', opts)
  buf_set_keymap('n', '<space>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
  buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
  buf_set_keymap('n', '<space>e', '<cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>', opts)
  buf_set_keymap('n', '[d', '<cmd>lua vim.lsp.diagnostic.goto_prev()<CR>', opts)
  buf_set_keymap('n', ']d', '<cmd>lua vim.lsp.diagnostic.goto_next()<CR>', opts)
  buf_set_keymap('n', '<space>q', '<cmd>lua vim.lsp.diagnostic.set_loclist()<CR>', opts)

  -- Set some keybinds conditional on server capabilities
  if client.resolved_capabilities.document_formatting then
    buf_set_keymap("n", "<space>f", "<cmd>lua vim.lsp.buf.formatting()<CR>", opts)
  elseif client.resolved_capabilities.document_range_formatting then
    buf_set_keymap("n", "<space>f", "<cmd>lua vim.lsp.buf.range_formatting()<CR>", opts)
  end

  -- Set autocommands conditional on server_capabilities
  if client.resolved_capabilities.document_highlight then
    vim.api.nvim_exec([[
      hi LspReferenceRead cterm=bold ctermbg=red guibg=LightYellow
      hi LspReferenceText cterm=bold ctermbg=red guibg=LightYellow
      hi LspReferenceWrite cterm=bold ctermbg=red guibg=LightYellow
      augroup lsp_document_highlight
        autocmd! * <buffer>
        autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()
        autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()
      augroup END
    ]], false)
  end
end

-- Use a loop to conveniently both setup defined servers 
-- and map buffer local keybindings when the language server attaches
local servers = { "pyright", "rust_analyzer", "tsserver" }
for _, lsp in ipairs(servers) do
  nvim_lsp[lsp].setup { on_attach = on_attach }
end

7. 语言配置

7.1. bash

  • https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md#bashls

  • https://github.com/bash-lsp/bash-language-server

1
npm i -g bash-language-server

7.2. Lua

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
git clone https://hub.fastgit.org/sumneko/lua-language-server
# 在vim里替换github的地址
# 执行下面的替换命令
# :%s/github\.com/hub\.fastgit\.org/g
# 然后把子项目拉下来
git submodule update --init --recursive
# 编译关联项目
cd 3rd/luamake
ninja -f ninja/linux.ninja
cd ../..
./3rd/luamake/luamake rebuild

配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
-- ###########################
-- Lua LSP
-- ###########################

-- set the path to the sumneko installation; if you previously installed via the now deprecated :LspInstall, use
local sumneko_root_path = '/home/coco/softs/lua-language-server'
local sumneko_binary = sumneko_root_path.."/bin/"..system_name.."/lua-language-server"

nvim_lsp.sumneko_lua.setup {
  cmd = {sumneko_binary, "-E", sumneko_root_path .. "/main.lua"};
  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 = vim.split(package.path, ';'),
      },
      diagnostics = {
        -- Get the language server to recognize the `vim` global
        globals = {'vim'},
      },
      workspace = {
        -- Make the server aware of Neovim runtime files
        library = {
          [vim.fn.expand('$VIMRUNTIME/lua')] = true,
          [vim.fn.expand('$VIMRUNTIME/lua/vim/lsp')] = true,
        },
      },
      -- Do not send telemetry data containing a randomized but unique identifier
      telemetry = {
        enable = false,
      },
    },
  },
  on_attach=on_attach
}

7.3. Golang

1
go get golang.org/x/tools/gopls@latest

7.4. Vim script

1
npm install -g vim-language-server

7.5. json

1
npm install -g vscode-json-languageserver

7.6. python

1
npm i -g pyright

LSP settings

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
-- vim:set ft=lua et sts=4 ts=4 sw=4 tw=78:                                                                          
local on_attach = function(client, bufnr)                                                                            
	require('completion').on_attach()
	local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
	local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end

    buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')

    -- Mappings.                                                                                                 
    local opts = { noremap=true, silent=true }                                                                   
    buf_set_keymap('n', 'gD', '<Cmd>lua vim.lsp.buf.declaration()<CR>', opts)
    buf_set_keymap('n', 'gd', '<Cmd>lua vim.lsp.buf.definition()<CR>', opts)
    buf_set_keymap('n', 'K', '<Cmd>lua vim.lsp.buf.hover()<CR>', opts)              
    buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)   
    buf_set_keymap('n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
    buf_set_keymap('n', '<space>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)
    buf_set_keymap('n', '<space>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)
    buf_set_keymap('n', '<space>wl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)
    buf_set_keymap('n', '<space>D', '<cmd>lua vim.lsp.buf.type_definition()<CR>', opts)
    buf_set_keymap('n', '<space>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
    buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
    buf_set_keymap('n', '<space>e', '<cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>', opts)
    buf_set_keymap('n', '[d', '<cmd>lua vim.lsp.diagnostic.goto_prev()<CR>', opts)
    buf_set_keymap('n', ']d', '<cmd>lua vim.lsp.diagnostic.goto_next()<CR>', opts)
    buf_set_keymap('n', '<space>q', '<cmd>lua vim.lsp.diagnostic.set_loclist()<CR>', opts)

    -- Set some keybinds conditional on server capabilities                                 
    if client.resolved_capabilities.document_formatting then
    buf_set_keymap("n", "<space>f", "<cmd>lua vim.lsp.buf.formatting()<CR>", opts)
    elseif client.resolved_capabilities.document_range_formatting then
    buf_set_keymap("n", "<space>f", "<cmd>lua vim.lsp.buf.range_formatting()<CR>", opts)
    end                  

    -- Set autocommands conditional on server_capabilities
    if client.resolved_capabilities.document_highlight then
    vim.api.nvim_exec([[                                                                                                                                                                                                       
    hi LspReferenceRead cterm=bold ctermbg=red guibg=LightYellow                                                                                                                                                               
    hi LspReferenceText cterm=bold ctermbg=red guibg=LightYellow
    hi LspReferenceWrite cterm=bold ctermbg=red guibg=LightYellow
    augroup lsp_document_highlight
    autocmd! * <buffer>
    autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()
    autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()
    augroup END
    ]], false)
    end
end
local nvim_lsp = require('lspconfig')
local util = require 'lspconfig/util'
nvim_lsp.pyright.setup{
    -- on_attach=require'completion'.on_attach
    on_attach=on_attach
}

最重要的部分,和pyenv整合,可以识别项目的虚拟环境,在项目里添加pyrightconfig.json

1
2
3
4
{                                                                                                       
    "venvPath": "/home/coco/.pyenv/versions/3.9.2/envs",                     
    "venv": "daocidi"                                                                                                         
}

7.7. javascript

7.7.1. Node js设置(tsserver)

1
npm install -g typescript typescript-language-server

7.7.2. Deno js设置(denols)

Install denojs

1
curl -fsSL https://deno.land/x/install/install.sh | sh

修改环境变量

1
2
3
4
5
# ======================================
# denojs
# ======================================
export DENO_INSTALL=$HOME/.deno
export PATH="$DENO_INSTALL/bin:$PATH"

8. 相关插件

8.1. ctag安装

1
2
git clone https://hub.fastgit.org/universal-ctags/ctags.git --depth=1

8.2. packer.nvim

https://github.com/wbthomason/packer.nvim

新的neovim包管理lua实现

8.3. tree-sitter

https://github.com/tree-sitter/tree-sitter

用来解析语法的,为了更好的语法着色?

8.4. telescope.nvim

https://github.com/nvim-telescope/telescope.nvim

一个fuzzy查询的工具, 支持文件,git,lsp和treesitter

8.5. nvim-tree.lua

https://github.com/kyazdani42/nvim-tree.lua

文件导航,lua的一个实现

  • move around like in any vim buffer

  • <CR> or o on .. will cd in the above directory

  • <C-]> will cd in the directory under the cursor

  • <BS> will close current opened directory or parent

  • type a to add a file. Adding a directory requires leaving a leading / at the end of the path.

    you can add multiple directories by doing foo/bar/baz/f and it will add foo bar and baz directories and f as a file

  • type r to rename a file

  • type <C-r> to rename a file and omit the filename on input

  • type x to add/remove file/directory to cut clipboard

  • type c to add/remove file/directory to copy clipboard

  • type p to paste from clipboard. Cut clipboard has precedence over copy (will prompt for confirmation)

  • type d to delete a file (will prompt for confirmation)

  • type ]c to go to next git item

  • type [c to go to prev git item

  • type ‘-’ to naviate up to the parent directory of the current file/directory

  • if the file is a directory, <CR> will open the directory otherwise it will open the file in the buffer near the tree

  • if the file is a symlink, <CR> will follow the symlink (if the target is a file)

  • <C-v> will open the file in a vertical split

  • <C-x> will open the file in a horizontal split

  • <C-t> will open the file in a new tab

  • <Tab> will open the file as a preview (keeps the cursor in the tree)

  • I will toggle visibility of folders hidden via |g:nvim_tree_ignore|

  • H will toggle visibility of dotfiles (files/folders starting with a .)

  • R will refresh the tree

  • Double left click acts like <CR>

  • Double right click acts like <C-]>

8.6. defx

https://github.com/Shougo/defx.nvim

文件导航

8.7. completion-nvim

https://github.com/nvim-lua/completion-nvim

补全插件,旨在提供更好的补全体验,只支持neovim0.5的内置LSP,不支持其他LSP插件

8.8. nvim-compe

https://github.com/hrsh7th/nvim-compe

另一个补全插件

8.9. vim-which-key

https://github.com/liuchengxu/vim-which-key

8.10. hop

https://github.com/phaazon/hop.nvim

类似easymotion的一个移动增强

8.11. vim-floaterm

https://github.com/voldikss/vim-floaterm

浮动的终端窗口插件

8.12. lspsaga

https://github.com/glepnir/lspsaga.nvim

lsp插件, 将lspconfig里的命令集中进行管理,提供统一的接口

8.13. dashboard-nvim

https://github.com/glepnir/dashboard-nvim

启动界面

8.14. codi.vim

https://github.com/metakirby5/codi.vim

一个scratchpad插件,支持大部分主流语言

8.15. galaxyline.nvim

https://github.com/glepnir/galaxyline.nvim

一个新的nvim的powerline, 文档比较少,定制稍微麻烦点

8.16. lightline.vim

https://github.com/itchyny/lightline.vim

可自定义的statusline,比较少的依赖,定制比较简单

8.17. barbar

https://github.com/romgrk/barbar.nvim

tab栏增强插件

8.18. nvim-bufferline.lua

https://github.com/akinsho/nvim-bufferline.lua

8.19. vim-clap

liuchengxu/vim-clap: Modern performant generic finder and dispatcher for Vim and NeoVim (github.com)

一个fuzzy查询

8.20. vim-signify

mhinz/vim-signify: Show a diff using Vim its sign column. (github.com)

在状态栏显示文件的改动

8.21. vim-easy-align

https://github.com/junegunn/vim-easy-align

自动对齐插件

8.22. nvim-web-devicons

https://github.com/kyazdani42/nvim-web-devicons

vim-devicons的lua实现

8.23. limelight.vim

https://github.com/junegunn/limelight.vim

集中注意力写作, 高亮正在编辑的段落, 配合goyo使用

8.24. goyo.vim

https://github.com/junegunn/goyo.vim

zen模式写作,排除干扰,配合limelight使用

8.25. nvim-comment

https://github.com/terrortylor/nvim-comment

lua实现的注释插件

8.26. vim-bookmarks

https://github.com/MattesGroeger/vim-bookmarks

书签插件,可以定制icon

8.27. gitsigns.nvim

https://github.com/lewis6991/gitsigns.nvim

git导航和视图工具

8.28. git-blame.nvim

https://github.com/f-person/git-blame.nvim

lua版的git blame工具

8.29. plenary.nvim

https://github.com/nvim-lua/plenary.nvim

lua的一些包装,写插件的时候有用

8.30. formatter.nvim

https://github.com/mhartington/formatter.nvim

格式化插件

1
npm i -g prettier lua-fmt

8.31. lspkind-nvim

https://github.com/onsails/lspkind-nvim

美化lsp提示,增加图标

8.32. nvim-lightbulb

https://github.com/kosayoda/nvim-lightbulb

模仿vscode的交互式提示信息,比如需要import的时候,选择性操作

8.33. indent-blankline.nvim

https://github.com/lukas-reineke/indent-blankline.nvim

给缩进加上竖线

8.34. nvim-ts-rainbow

https://github.com/p00f/nvim-ts-rainbow

给闭合标签加上彩色,方便识别

9. 主题

9.1. oceanic-material

glepnir/oceanic-material: Oceanic Material Colorscheme on Vim/NeoVim (github.com)

9.2. gruvbuddy

tjdevries/gruvbuddy.nvim: Gruvbox colors using https://github.com/tjdevries/colorbuddy.vim

installation

1
2
3
4
5
Plug 'tjdevries/colorbuddy.vim'
Plug 'tjdevries/gruvbuddy.nvim'

" And then somewhere in your vimrc, to set the colorscheme
lua require('colorbuddy').colorscheme('gruvbuddy')

9.3. zephyr-nvim

glepnir/zephyr-nvim: A dark neovim colorscheme written in lua (github.com)

TAG: vim ide
文章作者 : Cocding