Skip to content

vim

4 posts with the tag “vim”

Neovim拼写检查

这里记录如何在Neovim启用内置的拼写检查功能。

首先,添加拼写检查语言:

set spelllang=en,cjk

上面的配置,将拼写语言设置为encjkcjk选项用于防止将CJK字符被标记为拼写错误。

CJK: 中日韩统一表意文字(英语:CJK Unified Ideographs),也称统一汉字、统汉码(英语:Unihan),目的是要把分别来自中文、日文、韩文、越南文、壮文、琉球文中,起源相同、本义相同、形状一样或稍异的表意文字,在ISO 10646及Unicode标准赋予相同编码。 所谓“起源相同、本义相同”、主要是汉字,包括繁体字、简化字、日本汉字(漢字/かんじ)、韩国汉字(漢字/한자)、琉球汉字(漢字/ハンジ)、越南的喃字(𡨸喃/Chữ Nôm)与儒字(𡨸儒/Chữ Nho)、方块壮字(𭨡倱/sawgun)。

cjk配置项,也记录在 Nvim doc 文档中:

Chinese, Japanese and other East Asian characters are normally marked as errors, because spell checking of these characters is not supported. If ‘spelllang’ includes “cjk”, these characters are not marked as errors. This is useful when editing text with spell checking while some Asian words are present.

使Nvim启用拼写检查功能,需要运行命令:set spell。下面可以添加一个映射来切换拼写检查:

nnoremap <silent> <F11> :set spell!<cr>

或者

vim.api.nvim_set_keymap('n', '<F11>', [[<Cmd>set spell!<CR>]], { noremap = true, silent = true })

此时,可以按来切换拼写检查。

此外,也可以在init.lua中通过创建autocmd,根据文件类型(filetype),来自动切换拼写检查功能,如:

local spell_group = vim.api.nvim_create_augroup("spell_group", { clear = true })
vim.api.nvim_create_autocmd("FileType", {
pattern = { "lua", "python", "go" },
command = "setlocal spell spelllang=en_us,cjk",
group = spell_group,
})
vim.api.nvim_create_autocmd("FileType", {
pattern = { "markdown" },
command = "setlocal nospell",
group = spell_group,
})
vim.api.nvim_create_autocmd("TermOpen", {
pattern = "*", -- disable spellchecking in the embeded terminal
command = "setlocal nospell",
group = spell_group,
})

上面的配置,在luaptyhongo文件中启用拼写检查,并将拼写语言设置为en_us,cjk,在Markdown文件禁用拼写检查, 同时在内嵌终端(embeded terminal)中禁用拼写检查。

在插入模式时,当输入了NeoVim认为是拼写错误的单词时,会在其下方显示下划线。要更正错误,可以依次按下<C-x>s键,此时 会显示一个建议正确单词的菜单列表,可以选择其中一项来更正拼写。

normal模式,可以使用下面的快捷键来快速处理拼写错误问题:

  • [s: 跳转到上一处拼写错误
  • ]s: 跳转到下一处拼写错误
  • z=: 对光标下或之后的单词,显示建议正确的拼写单词
  • zg: 将光标下的单词作为正确拼写单词加入到’spellfile’
  • zw: 和zg类似,只是zw是将这个单词标记为拼写错误的单词

spelloptions配置选项默认值是"",此时,注释中的驼峰拼写的单词,会被判定为拼写错误,如: camel case

可以通过配spelloptions启动驼峰单词拼写:

vim.opt.spelloptions = "camel"

判断规则:

When a word is CamelCased, assume “Cased” is a

separate word: every upper-case character in a word
that comes after a lower case character indicates the
start of a new word.

NeoVim调试Python、Golang

在上两篇中NeoVim开发环境配置NeoVim配置Go开发环境(进阶), 完成了将NeoVim作为IDE最基本常用功能的,这里将进一步完成对Python、Golang调试环境的配置。

在NeoVim上进行调试(Python、Golang)有nvim-dapvimspector可做选择,这里 将使用vimspector进行调试工作。

在plug.vim中添加:

Plug 'puremourning/vimspector'

:PlugInstall安装插件。 在init.vim中,添加:

let g:vimspector_enable_mappings='HUMAN'

将vimspector 快捷键映射配置为HUMAN模式:

KeyMappingFunction
F5<Plug>VimspectorContinueWhen debugging, continue. Otherwise start debugging.
F3<Plug>VimspectorStopStop debugging.
F4<Plug>VimspectorRestartRestart debugging with the same configuration.
F6<Plug>VimspectorPausePause debuggee.
F9<Plug>VimspectorToggleBreakpointToggle line breakpoint on the current line.
<leader>F9<Plug>VimspectorToggleConditionalBreakpointToggle conditional line breakpoint or logpoint on the current line.
F8<Plug>VimspectorAddFunctionBreakpointAdd a function breakpoint for the expression under cursor
<leader>F8<Plug>VimspectorRunToCursorRun to Cursor
F10<Plug>VimspectorStepOverStep Over
F11<Plug>VimspectorStepIntoStep Into
F12<Plug>VimspectorStepOutStep out of current function scope

下面是各个语言调试使用的Adapter:

通过:VimspectorInstall debugpy:VimspectorInstall delve 完成对python、go 调试adapter的安装。

由于NeoVim的LSP指定当前根目录是各LSP Server提供的功能,在调试Ptyon时,在目录中添加.pyrightconfig.json文件:

{
"executionEnvironments": [
{"root": "."}
]
}

如上配置,将.pyrightconfig.json文件所在目录,作为Root目录。

配置调试器,添加配置文件 .vimspector.json:

{
"configurations": {
"run": {
"adapter": "debugpy",
"default": true,
"configuration": {
"request": "launch",
"type": "python",
"cwd": "${workspaceRoot}",
"stopOnEntry": true,
"program": "${file}"
},
"breakpoints": {
"exception": {
"raised": "N",
"uncaught": "",
"userUnhandled": ""
}
}
}
}
}

configuration.program指定要调试的程序,可以通过configuration.env配置调试时程序的环境变量,configuration.args配置参数。 如在调试一个scrapy的爬虫程序时,通过program指定scrapy位置,args指定启动的具体spider:

{
"configurations": {
"run": {
"adapter": "debugpy",
"default": true,
"configuration": {
"request": "launch",
"type": "python",
"program": "~/opt/miniconda3/envs/p3/bin/scrapy",
"cwd": "${workspaceRoot}",
"stopOnEntry": true,
"args": ["crawl", "${fileBasenameNoExtension}"]
},
"breakpoints": {
"exception": {
"raised": "N",
"uncaught": "",
"userUnhandled": ""
}
}
}
}
}

配置调试器,添加配置文件 .vimspector.json,如:

{
"configurations": {
"default": {
"adapter": "delve",
"default": true,
"configuration": {
"request": "launch",
"mode": "debug",
"cwd": "${workspaceRoot}",
"stopOnEntry": true,
"program": "${file}",
"args": [
"-http_addr","localhost:8084"
]
},
"breakpoints": {
"exception": {
"raised": "N",
"uncaught": "",
"userUnhandled": ""
}
}
}
}
}

指定adapter为delve来调试go程序,program指定要调试的程序文件,args指定参数http_addr=localhost:8084

  1. vimspector
  2. Debugging python in neovim
  3. Neovim — Debugging Application
  4. Programming Go in Neovim
  5. nvim-lsconfig Configurations
  6. vim-delve
  7. golang: debugging application in neovim
  8. nvim-dap
  9. debug-adapter-configuration

NeoVim配置Go开发环境

在上一篇NeoVim开发环境配置中记录了NeoVim的基本插件配置,随着了解的深入,这里对NeoVim的插件配置进行一步优化处理。

首先对配置进行切分,避免配置都混杂在init.vim中,不利于管理,下面是我的配置文件结构:

Terminal window
$HOME/.config/nvim/
├── after
└── plugin
├── coq_nvim.rc.vim
├── defx.rc.vim
├── fugitive.rc.vim
├── lspconfig.rc.vim
└── treesitter.rc.vim
├── init.vim
├── macos.vim
├── maps.vim
└── plug.vim

init.vim: 根配置文件

macos.vim: mscOS特殊配置

plug.vim :Vim-plug插件配置

maps.vim:快捷键配置

after/plugin: 放置插件的配置脚本,这里面的文件也会在vim每次启动的时候加载,不过是等待plugin加载完成之后才加载after里的内容,所以叫做after。VIM USER MANUAL runtimepath

安装 vim-plug$HOME/.local/share/nvim/site/autoload/plug.vim:

Terminal window
sh -c 'curl -fLo $HOME/.local/share/nvim/site/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'

我在$HOME/.config/nvim/plug.vim管理配置插件:

if has("nvim")
let g:plug_home = stdpath('data') . '/plugged'
endif
call plug#begin()
...
call plug#end()

为了使plug.vim配置生效,需要在init.vim中进行配置加载:

runtime ./plug.vim

此时,重启NeoVim,运行:PlugInstall进行插件安装。

此外其他几个配置文件:maps.vim,macos.vim 也需要手动配置加载:

if has("unix")
let s:uname = system("uname -s")
" Do mac stuff
if s:uname == "Darwin\n"
runtime ./macos.vim
endif
endif
runtime ./maps.vim

后续安装的插件,分个单独配置,放置到after/plugin目录下。

至此root配置(init.vim)、插件管理、快捷键管理、各插件独立进行配置,配置分离便于管理。

NERDTree是Vim最常用的插件之一,可以在Vim运行时显示目录和文件结构,类似TextMate左侧的文件浏览器,但操作起来更为方便。

目前还有另外一个目录和文件结构管理插件defx.nvim

  • 不依赖于 denite.nvim
  • Vim8/neovim 兼容(Vim8 需要 nvim-yarp)
  • 由 Python3 实现
  • 没有双重过滤器功能
  • 列功能
  • 类似于 denite.nvim 一样支持 source
  • 支持选项
  • 突出显示由列定义
  • 很少的命令(仅:Defx 命令?)
  • 扩展重命名
  • 支持标记
Plug 'Shougo/defx.nvim', { 'do': ':UpdateRemotePlugins' }

安装完成后,使用:Defx命令来使用:

img

每次使用时Buffer会充满整个窗口,并不是我们常用形态,此时需要再进行配置,指定显示的位置以及大小等:

call defx#custom#option('_', {
\ 'winwidth': 38,
\ 'direction': 'topleft',
\ 'split': 'vertical',
\ 'show_ignored_files': 0,
\ 'buffer_name': '',
\ 'toggle': 1,
\ 'resume': 1,
\ })

效果如下:

Defx -split=vertical

使用时通过输入Defx命令太过繁琐效率不高,可以通过设置快捷键来改善,maps.vim中添加:

nnoremap <silent>sf :<C-u>Defx
\ -auto-cd
\ -columns=mark:indent:icon:icons:filename:type:git<CR>

后续通过键入sf即可唤出文件目录管理。

after/plugin/defx.rc.vim 添加快捷键配置:

autocmd FileType defx call s:defx_my_settings()
function! s:defx_my_settings() abort
" Define mappings
nnoremap <silent><buffer><expr> <CR>
\ defx#do_action('open')
nnoremap <silent><buffer><expr> c
\ defx#do_action('copy')
nnoremap <silent><buffer><expr> m
\ defx#do_action('move')
nnoremap <silent><buffer><expr> p
\ defx#do_action('paste')
nnoremap <silent><buffer><expr> l
\ defx#do_action('open')
nnoremap <silent><buffer><expr> E
\ defx#do_action('open', 'vsplit')
nnoremap <silent><buffer><expr> P
\ defx#do_action('preview')
nnoremap <silent><buffer><expr> o
\ defx#do_action('open_tree', 'toggle')
nnoremap <silent><buffer><expr> K
\ defx#do_action('new_directory')
nnoremap <silent><buffer><expr> N
\ defx#do_action('new_file')
nnoremap <silent><buffer><expr> M
\ defx#do_action('new_multiple_files')
nnoremap <silent><buffer><expr> C
\ defx#do_action('toggle_columns',
\ 'mark:indent:icon:filename:type:size:time')
nnoremap <silent><buffer><expr> S
\ defx#do_action('toggle_sort', 'time')
nnoremap <silent><buffer><expr> d
\ defx#do_action('remove')
nnoremap <silent><buffer><expr> r
\ defx#do_action('rename')
nnoremap <silent><buffer><expr> !
\ defx#do_action('execute_command')
nnoremap <silent><buffer><expr> x
\ defx#do_action('execute_system')
nnoremap <silent><buffer><expr> yy
\ defx#do_action('yank_path')
nnoremap <silent><buffer><expr> .
\ defx#do_action('toggle_ignored_files')
nnoremap <silent><buffer><expr> ;
\ defx#do_action('repeat')
nnoremap <silent><buffer><expr> h
\ defx#do_action('cd', ['..'])
nnoremap <silent><buffer><expr> ~
\ defx#do_action('cd')
nnoremap <silent><buffer><expr> q
\ defx#do_action('quit')
nnoremap <silent><buffer><expr> <Space>
\ defx#do_action('toggle_select') . 'j'
nnoremap <silent><buffer><expr> *
\ defx#do_action('toggle_select_all')
nnoremap <silent><buffer><expr> j
\ line('.') == line('$') ? 'gg' : 'j'
nnoremap <silent><buffer><expr> k
\ line('.') == 1 ? 'G' : 'k'
nnoremap <silent><buffer><expr> <C-l>
\ defx#do_action('redraw')
nnoremap <silent><buffer><expr> <C-g>
\ defx#do_action('print')
nnoremap <silent><buffer><expr> cd
\ defx#do_action('change_vim_cwd')
endfunction

设置文件图标可以让文件目录使用起来更加舒适,此时需要使用任意一种Nerd Fonts字体,并配置好iTerm,以便在iTerm2中可以正常显示字体图标:

Terminal window
brew tap homebrew/cask-fonts
brew cask install font-hack-nerd-font

iTerm2配置:

image-20220121123108917

这里有一点需要注意的是,如果勾选了Use a different font for non-ASSII text,那么第二种字体也需要使用Nerd Fonts中的一种,不然还是无法正常显示图标。

配置好iTerm2后,还需要安装defx-icons插件,才能使defx.nvim显示出文件图标,plug.vim添加:

Plug 'kristijanhusak/defx-icons'

:PlugInstall安装重启后,就可以看到:

image-20220121123639182

此时发现文件图片和文件名重叠,添加下面配置即可:

let g:defx_icons_column_length = 2

此时效果如下:

image-20220121123849035

使用官方文档中的默认快捷键配置后,发现总是从当前窗口中,打开文件,很不符合习惯:

image-20220121124512001

如果想要和vscode一样,从右侧窗口打开文件,可以使用drop替代open来配置快捷键:

nnoremap <silent><buffer><expr> <CR> defx#do_action('drop')
nnoremap <silent><buffer><expr> l defx#do_action('drop')

文件名太长导致显示问题时,可以通过下面的方式,限制文件名可以显示的最大长度:

call defx#custom#column('filename', {
\ 'max_width': 26,
\})

mhinz/vim-startify 启动屏可以记录最近编辑的文件,使用对应数字编号就可以快速打开文件,使用起来非常方便。

image-20220121125121988

Neovim已经内置了语言服务器协议 (LSP)。LSP时一种开放的、基于JSON- RPC的协议,用于源代码编辑器和语言服务器之间的通信,可以提供特定于编程语言的功能,如:

  1. 调转到定义
  2. 自动完成
  3. 代码操作(自动格式化、包导入…)
  4. 显示方法签名
  5. 显示、转到参考
  6. 代码片段

从 0.5 版本开始,NeoVim 原生支持该协议。NeoVim在nvim-lspconfig 插件中维护了一个配置列表。该存储库包含设置和排除许多服务器故障的说明。

如果需要为自己刚兴趣的编程语言,需要为其安装和配置相应的LSP服务器,这些可以通过nvim-lspconfig插件来处理。

Plug 'neovim/nvim-lspconfig'

需要注意的是这个插件只是配置管理,我们还需要单独为相应的编程语言安装LSP服务器,具体详见server_configurations

安装Google的 golang lsp server见:

https://github.com/golang/tools/tree/master/gopls

激活LSP服务,以及完整配置如下, lspconfig.rc.vim:

require'lspconfig'.gopls.setup{}
if !exists('g:lspconfig')
finish
endif
lua << EOF
vim.lsp.set_log_level("debug")
EOF
lua << EOF
local nvim_lsp = require('lspconfig')
nvim_lsp.pyright.setup{}
nvim_lsp.gopls.setup{}
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.textDocument.completion.completionItem.snippetSupport = true
-- Use an on_attach function to only map the following keys
-- after the language server attaches to the current buffer
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
-- Enable completion triggered by <c-x><c-o>
buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')
-- Mappings.
local opts = { noremap=true, silent=true }
-- See `:help vim.lsp.*` for documentation on any of the below functions
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', 'ga', '<Cmd>lua vim.lsp.buf.code_action()<CR>', opts)
buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
buf_set_keymap('n', 'K', '<cmd>lua vim.lsp.buf.hover()<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', '<space>e', '<cmd>lua vim.diagnostic.open_float()<CR>', opts)
buf_set_keymap('n', '[d', '<cmd>lua vim.diagnostic.goto_prev()<CR>', opts)
buf_set_keymap('n', ']d', '<cmd>lua vim.diagnostic.goto_next()<CR>', opts)
buf_set_keymap('n', '<space>q', '<cmd>lua vim.diagnostic.setloclist()<CR>', opts)
buf_set_keymap('n', '<space>f', '<cmd>lua vim.lsp.buf.formatting()<CR>', opts)
end
-- Use a loop to conveniently call 'setup' on multiple 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,
flags = {
debounce_text_changes = 150,
}
}
end
nvim_lsp.gopls.setup{
cmd = {'gopls'},
-- for postfix snippets and analyzers
capabilities = capabilities,
settings = {
gopls = {
experimentalPostfixCompletions = true,
analyses = {
unusedparams = true,
shadow = true,
},
staticcheck = true,
},
},
on_attach = on_attach,
}
function goimports(timeoutms)
local context = { source = { organizeImports = true } }
vim.validate { context = { context, "t", true } }
local params = vim.lsp.util.make_range_params()
params.context = context
-- See the implementation of the textDocument/codeAction callback
-- (lua/vim/lsp/handler.lua) for how to do this properly.
local result = vim.lsp.buf_request_sync(0, "textDocument/codeAction", params, timeout_ms)
if not result or next(result) == nil then return end
local actions = result[1].result
if not actions then return end
local action = actions[1]
-- textDocument/codeAction can return either Command[] or CodeAction[]. If it
-- is a CodeAction, it can have either an edit, a command or both. Edits
-- should be executed first.
if action.edit or type(action.command) == "table" then
if action.edit then
vim.lsp.util.apply_workspace_edit(action.edit)
end
if type(action.command) == "table" then
vim.lsp.buf.execute_command(action.command)
end
else
vim.lsp.buf.execute_command(action)
end
end
EOF

配置gopls服务,提供跳转、查看定义、重命名等:

-- Mappings.
local opts = { noremap=true, silent=true }
-- See `:help vim.lsp.*` for documentation on any of the below functions
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', 'ga', '<Cmd>lua vim.lsp.buf.code_action()<CR>', opts)
buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)

format img

格式化代码快捷键配置:

buf_set_keymap('n', '<space>f', '<cmd>lua vim.lsp.buf.formatting()<CR>', opts)

保存文件时自动格式化:

" 保存代码前进行自动格式化
autocmd BufWritePre *.go lua vim.lsp.buf.formatting()

触发包导入有两种方式来解决,一种时通过code action来手动触发:

buf_set_keymap('n', 'ga', '<Cmd>lua vim.lsp.buf.code_action()<CR>', opts)

也可以通过保存文件时,自动触发:

function goimports(timeoutms)
local context = { source = { organizeImports = true } }
vim.validate { context = { context, "t", true } }
local params = vim.lsp.util.make_range_params()
params.context = context
-- See the implementation of the textDocument/codeAction callback
-- (lua/vim/lsp/handler.lua) for how to do this properly.
local result = vim.lsp.buf_request_sync(0, "textDocument/codeAction", params, timeout_ms)
if not result or next(result) == nil then return end
local actions = result[1].result
if not actions then return end
local action = actions[1]
-- textDocument/codeAction can return either Command[] or CodeAction[]. If it
-- is a CodeAction, it can have either an edit, a command or both. Edits
-- should be executed first.
if action.edit or type(action.command) == "table" then
if action.edit then
vim.lsp.util.apply_workspace_edit(action.edit)
end
if type(action.command) == "table" then
vim.lsp.buf.execute_command(action.command)
end
else
vim.lsp.buf.execute_command(action)
end
end

并配置:

autocmd BufWritePre *.go lua goimports(1000)

完成是开箱即用的。我们只需要将它映射到 vimomnifunc即可使我们的Ctrl+x,Ctrl+o工作:

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

完成

但是,每次触发都需要通过Ctrl+x,Ctrl+o来触发,十分不方便,为了自动触发,可以在通过安装新的插件ms-jpq/coq_nvim来完成,如:

" 增强代码自动完成
Plug 'ms-jpq/coq_nvim', {'branch': 'coq'}
" 9000+ Snippets
Plug 'ms-jpq/coq.artifacts', {'branch': 'artifacts'}
Plug 'ms-jpq/coq.thirdparty', {'branch': '3p'}

始终将所有操作复制到系统剪贴板:

set clipboard+=unnamedplus

目前基于内置lsp的功能已经比较完善,但是缺乏一个良好的操作UI,如重命名时,输入新名字的地方在窗口底部:

image-20220121173142281

使用async-lsp-finder后:

img

安装

Plug 'glepnir/lspsaga.nvim'

快捷键配置:

" 异步lsp查找
nnoremap <silent> gh :Lspsaga lsp_finder<CR>
" Code Action
nnoremap <silent><leader>ca :Lspsaga code_action<CR>
vnoremap <silent><leader>ca :<C-U>Lspsaga range_code_action<CR>
" 悬停文档
nnoremap <silent>K :Lspsaga hover_doc<CR>
" scroll down hover doc or scroll in definition preview
nnoremap <silent> <C-f> <cmd>lua require('lspsaga.action').smart_scroll_with_saga(1)<CR>
" scroll up hover doc
nnoremap <silent> <C-b> <cmd>lua require('lspsaga.action').smart_scroll_with_saga(-1)<CR>
" help
nnoremap <silent> gs :Lspsaga signature_help<CR>
" 重命名
nnoremap <silent>gr :Lspsaga rename<CR>
" 预览定义
nnoremap <silent> gd :Lspsaga preview_definition<CR>
" 浮动终端
nnoremap <silent> <A-d> :Lspsaga open_floaterm<CR>
tnoremap <silent> <A-d> <C-\><C-n>:Lspsaga close_floaterm<CR>
  1. neovim-lsp
  2. nvim-treesitter
  3. nvim-lspconfig
  4. defx.nvim
  5. defx.txt
  6. How to set up Neovim 0.5 + Modern plugins (LSP, Treesitter, Fuzzy finder, etc)
  7. dotfiles-public
  8. programming-go-in-neovim
  9. go-vim
  10. awesome-neovim
  11. VIM USER MANUAL
  12. runtimepath
  13. 如何配置 Vim 的 Golang 开发环境

NeoVim开发环境配置

img

在vscode等IDE中使用vim插件也已经很久了,最近发现了NeoVim的存在,之前也非常好奇国外的程序员为啥有许多,执着于编辑器之神(Vim) & 神的编辑器(Emacs),因此也尝试使用NeoVim配置了一套环境。

Bram Moolenaar 在写 Vim 时还是 90 年代初,至今已经 20 多年 过去了。其中,不仅包含了大量的遗留代码,而且程序的维护、Bug 的 修复、以及新特性的添加都变得越来越困难。为了解决这些问题,Neovim 项目应运而生。Neo 即“新”之意,它是 Vim 在这个新时代的重生。

根据 Neovim 的自述说明,在总体上,它将达到下列目的:

  • 通过简化维护以改进 Bug 修复及特性添加的速度;
  • 分派各个开发人员的工作;
  • 实现新的、现代化的用户界面,而不必修改核心源代码;
  • 利用新的、基于协同进程的新插件架构改善扩展性,并支持使用任何语言 编写插件

以上介绍来自linuxtoy

此外, 在最近的版本中, 还有非常值得注意的几点:

  • 实现了嵌入式终端模拟器, 可以跟各种REPL插件说再见了
  • 使用远程API(好像是socket), 不光能使用各种语言编写插件, 而且可以很方便的编写GUI版本, 甚至嵌入至IDE中
  • 由于内部优化了事件监听器还是什么的, 代码粘贴的时候, 可以自动识别, 不像vim里一样需要:set paste, 不然会出现蜜汁缩进和括号对
  • 直接支持剪贴板, 不需要重新编译

macOS/OS X 上使用Homebrew安装

Terminal window
brew install neovim

更多安装方式参考:Installing Neovim

安装

Terminal window
sh -c 'curl -fLo "${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'

基本使用

neovim继承自vim,基本支持vim的所有特性,可以直接使用vim的配置文件:

Terminal window
mkdir -p ${XDG_CONFIG_HOME:=$HOME/.config}
ln -s ~/.vim $XDG_CONFIG_HOME/nvim
ln -s ~/.vimrc $XDG_CONFIG_HOME/nvim/init.vim

也可以重新开始配置neovim

Terminal window
mkdir -p ~/.config/ ~/.config/nvim
touch ~/.config/ ~/.config/nvim/init.vim

Plug插件,需要在 call plug#begin()call plug#end() 节点中,使用Plug命令进行声明,如:

Terminal window
call plug#begin()
" The default plugin directory will be as follows:
" - Vim (Linux/macOS): '~/.vim/plugged'
" - Vim (Windows): '~/vimfiles/plugged'
" - Neovim (Linux/macOS/Windows): stdpath('data') . '/plugged'
" You can specify a custom plugin directory by passing it as the argument
" - e.g. `call plug#begin('~/.vim/plugged')`
" - Avoid using standard Vim directory names like 'plugin'
" Make sure you use single quotes
" Using a tagged release; wildcard allowed (requires git 1.9.2 or above)
Plug 'fatih/vim-go', { 'tag': '*' }
" Initialize plugin system
call plug#end()

配置好插件后,进行安装升级

Terminal window
:PlugInstall
:PlugUpdate
:PlugUpgrade

查看已经安装的插件状态

Terminal window
:PlugStatus

更多资料,参考vim-plug

方便开发使用,需要对下面一些基本功能进行配置:

  1. 目录管理 - nerdtree
  2. 文件模糊搜索 - fzf
  3. 代码缩略图 - tagbar
  4. 主题配色 - molokai
  5. 状态栏 - airline
  6. 编程语言相关插件(vim-go)
  7. 自动补全- neocomplete.vim
  8. 其他(vim-stratify)

常用非常流行的目录管理插件nerdtree

Terminal window
Plug 'scrooloose/nerdtree'
nnoremap <leader>n :NERDTreeFocus<CR>
nnoremap <C-n> :NERDTree<CR>
nnoremap <C-t> :NERDTreeToggle<CR>
nnoremap <C-f> :NERDTreeFind<CR>

配置快捷键Ctr + n, Ctrl + t, Ctrl +f

fzf 是一个非常高效实用且美观的命令行工具,并且配置有对应的 vim 插件 fzf.vim。比如下面这个效果图,我们可以让 fzf 在中间进行显示,有点类似于 IDEA 的搜索窗口。

image-20220118164902042

fzf.vim 依赖fzf,安装插件前需要先安装好fzf:

Terminal window
brew install fzf

使用插件:

Terminal window
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'

NeoVim命令模式下输入:Files :Buffers即可弹出模糊搜索窗口进行搜索

更多信息参考:fzf.vimfzf

Tagbar是一个Vim插件,它提供了一种简单的方法来浏览当前文件的标记并获得其结构的概述。它通过创建一个侧边栏来显示当前文件的ctags-generated标记,并按其范围排序。

image-20220118170918463

安装插件,并配置快捷键F8:

Terminal window
" tagbar
Plug 'majutsushi/tagbar'
nnoremap <F8> :TagbarToggle<cr>

如果您这样做,F8键将切换Tagbar窗口,当然也可以配置任何其他自己想要的快捷键。

更多资料参考:tagbar

主题的话根据个人喜好选择。

Terminal window
Plug 'fatih/molokai'
syntax enable
set t_Co=256
let g:rehash256 = 1
let g:molokai_original = 1
colorscheme molokai
Terminal window
Plug 'vim-airline/vim-airline'
Plug 'vim-airline/vim-airline-themes'

或者

Terminal window
Plug 'morhetz/gruvbox'
" 使用配色方案gruvbox
colorscheme gruvbox

更多主题样式配置,常见:vim-airline gruvbox

使用vim/neogim进行go语言的开发需要vim-go

Terminal window
" go 主要插件
Plug 'fatih/vim-go', { 'tag': '*' }
" go 中的代码追踪,输入 gd 就可以自动跳转
Plug 'dgryski/vim-godef'

更多配置参考:vim-go

代码自动补全,需要使用deoplete.nvim

安装依赖:

Terminal window
pip3 install pynvim
pip3 install msgpack

安装配置插件

Plug 'Shougo/deoplete.nvim', { 'do': ':UpdateRemotePlugins' }
let g:deoplete#enable_at_startup = 1

配置TAB快捷键完成自动提示输入:

Terminal window
" <TAB>: completion.
inoremap <expr><TAB> pumvisible() ? "\<C-n>" : "\<TAB>"

至此重启NeoVim后,自动补全会根据当前文件中已有的名字进行猜测并补全。为了根据不同的语言特性提供更加完善的补全效果,需要安装相应的。 如对于Python可以再安装deoplete-jedi 依赖安装

Terminal window
pip3 install --user jedi --upgrade

插件安装:

Plug 'deoplete-plugins/deoplete-jedi'

修改配置后,使用:PlugInstall命令进行安装完成后重启NeoVim,此时就可以基于jedi在NeoVim上对Python提供完美的自动补全功能。

更多配置参考:deoplete.nvim

vim-startify 为Vim/NeoVim开屏页美化插件,可以记录最近编辑的文件,使用对应数字编号就可以快速打开文件,使用起来非常方便。

image-20220118172551047

安装:

Terminal window
Plug 'mhinz/vim-startify'

完整的配置init.vim

Terminal window
call plug#begin()
" The default plugin directory will be as follows:
" - Vim (Linux/macOS): '~/.vim/plugged'
" - Vim (Windows): '~/vimfiles/plugged'
" - Neovim (Linux/macOS/Windows): stdpath('data') . '/plugged'
" You can specify a custom plugin directory by passing it as the argument
" - e.g. `call plug#begin('~/.vim/plugged')`
" - Avoid using standard Vim directory names like 'plugin'
" Make sure you use single quotes
" The NERDTree is a file system explorer for the Vim editor.
Plug 'preservim/nerdtree'
" indentation guides to all lines
Plug 'lukas-reineke/indent-blankline.nvim'
" fzf
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'
" 状态栏美化
Plug 'vim-airline/vim-airline'
Plug 'vim-airline/vim-airline-themes'
" tagbar
Plug 'majutsushi/tagbar'
nnoremap <F8> :TagbarToggle<cr>
" vim开屏页美化插件,可以记录最近编辑的文件,使用对应数字编号就可以快速打开文件,使用起来非常方便。
Plug 'mhinz/vim-startify'
" AutoComplete
Plug 'Shougo/deoplete.nvim'
" Python AutoComplete
Plug 'deoplete-plugins/deoplete-jedi'
let g:deoplete#enable_at_startup = 1
" Insert or delete brackets, parens, quotes in pair.
Plug 'jiangmiao/auto-pairs'
" 配色方案
Plug 'morhetz/gruvbox'
call plug#end()
set encoding=utf-8
set tabstop=4
set softtabstop=4
set shiftwidth=4
" 表示Tab自动转换成空格
set expandtab
" 表示换行后自动缩进
set autoindent
" 智能对齐
set smartindent
" 当文件在外部被修改时,自动重新读取
set autoread
" 显示行号、 显示当前行行号,其它行的行号都是以当前行为基准从 1 开始增加(即相对行号)
set number relativenumber
" 设置配色方案
colorscheme gruvbox
let g:airline_theme='gruvbox'
" 启用语法高亮
syntax enable
" 使用黑色主题-light dark
set bg=dark
" vim记住的历史操作的数量,默认的是20
set history=40
" NERDTree
nnoremap <leader>n :NERDTreeFocus<CR>
nnoremap <C-n> :NERDTree<CR>
nnoremap <C-t> :NERDTreeToggle<CR>
nnoremap <C-f> :NERDTreeFind<CR>
" <TAB>: completion.
inoremap <expr><TAB> pumvisible() ? "\<C-n>" : "\<TAB>"
  1. 维基百科-Vim
  2. 精通 VIM ,此文就够了
  3. nerdtree
  4. fzf
  5. him-startify
  6. tagbar
  7. vim-airline
  8. vim-go
  9. neocomplete.vim
  10. programming-go-in-neovim