种草很久的neovim工具使用
由于一直羡慕大神们用vim工具快速的编辑代码,并且羡慕能够不断优化适合自己的IDE工具。所以选择了neovim作为自己的IDE工具进行配置。 其实,自己是在vscode中使用的vim插件进行编辑,但是还是不能完全摆脱鼠标的操作,且一些功能在windows和macos上使用的不太一样,所以最终狠心学习一下neovim,以及开始尝试搭建自己的vim IDE工具。
目标
适合自己的才是最好的,之前看了很多大神使用的各种插件,确实效率很高,让人羡慕不已,但是单单是把他们的插件配置拿过来是没有用的,倒不如自己从头搭建一个属于自己的IDE。 插件的查找方式从自己的需求出发,列出自己可能会用到的一些功能,在搜索需要的插件,个人认为这种方式可能更适合自己。
插件管理工具
要想安装插件,必须有个趁手的管理工具,从网上搜索好多人建议使用vim-plug这个插件。
vim-plug插件安装过程
- vim-plug插件github地址及安装方法:https://github.com/junegunn/vim-plug,安装方式参考github上的Readme说明即可。
- raw.githubusercontent.com 访问不了的问题解决
- 打开https://site.ip138.com/raw.Githubusercontent.com/,输入raw.githubusercontent.com,查询解析IP地址,选取一个IP地址,更改/etc/hosts,直接将raw.githubusercontent.com域名指向该IP地址。
- 重新执行github上的安装命令即可。
vim插件搜索网站
- https://vimawesome.com/
- 仅了解这一个网站,如果有更好的网站欢迎给我留言反馈
根据需求搜索需要的plug
vim-plug插件管理
- neovim配置文件所在位置./config/nvim/init.vim
- 向init.vim中写入自己的插件内容
- for example
" Specify a directory for plugins
" - For Neovim: stdpath('data') . '/plugged'
" - Avoid using standard Vim directory names like 'plugin'
call plug#begin('~/.vim/plugged') # 插件存放位置
" Plugin outside ~/.vim/plugged with post-update hook
Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' } # 插件在github上的名称
" Initialize plugin system
call plug#end()
- 执行命令:PlugInstall命令安装插件
IDE一样的目录树结构
- The NERD tree
- Plug ‘scrooloose/nerdtree’
- Plug ‘preservim/nerdtree’ 都是可以的,对应的github路径都是:https://github.com/preservim/nerdtree
- init.vim文件内容
call plug#begin('~/.vim/plugged')
" https://vimawesome.com/plugin/nerdtree-red
" github: https://github.com/preservim/nerdtree
" Plug ‘scrooloose/nerdtree’ is the same
Plug 'scrooloose/nerdtree'
autocmd vimenter
call plug#end()
切换工作台和目录
ctrl + w + h 光标 focus 左侧树形目录
ctrl + w + l 光标 focus 右侧文件显示窗口
ctrl + w + w 光标自动在左右侧窗口切换
ctrl + w + r 移动当前窗口的布局位置
基本操作命令
o 在已有窗口中打开文件、目录或书签,并跳到该窗口
go 在已有窗口 中打开文件、目录或书签,但不跳到该窗口
t 在新 Tab 中打开选中文件/书签,并跳到新 Tab
T 在新 Tab 中打开选中文件/书签,但不跳到新 Tab
i split 一个新窗口打开选中文件,并跳到该窗口
gi split 一个新窗口打开选中文件,但不跳到该窗口
s vsplit 一个新窗口打开选中文件,并跳到该窗口
gs vsplit 一个新 窗口打开选中文件,但不跳到该窗口
! 执行当前文件
O 递归打开选中 结点下的所有目录
x 合拢选中结点的父目录
X 递归 合拢选中结点下的所有目录
e Edit the current dif
D 删除当前书签
P 跳到根结点
p 跳到父结点
K 跳到当前目录下同级的第一个结点
J 跳到当前目录下同级的最后一个结点
k 跳到当前目录下同级的前一个结点
j 跳到当前目录下同级的后一个结点
C 将选中目录或选中文件的父目录设为根结点
u 将当前根结点的父目录设为根目录,并变成合拢原根结点
U 将当前根结点的父目录设为根目录,但保持展开原根结点
r 递归刷新选中目录
R 递归刷新根结点
m 显示文件系统菜单
cd 将 CWD 设为选中目录
I 切换是否显示隐藏文件
f 切换是否使用文件过滤器
F 切换是否显示文件
B 切换是否显示书签
q 关闭 NerdTree 窗口
? 切换是否显示 Quick Help
切换标签页
:tabnew [++opt选项] [+cmd] 文件 建立对指定文件新的tab
:tabc 关闭当前的 tab
:tabo 关闭所有其他的 tab
:tabs 查看所有打开的 tab
:tabp 前一个 tab
:tabn 后一个 tab
normal模式下:
gT 前一个 tab
gt 后一个 tab
##### 创建删除文件/文件夹
ma: 创建文件或者文件夹,文件名称以/结尾就是文件夹了
md: 删除光标所在的文件
自动代码补全
coc.vim
配置
安装扩展插件,如下:
:CocInstall coc-json coc-tsserver
配置go语言LSP,如下:
:CocConfig
{
"languageserver": {
"go": {
"command": "gopls",
"rootPatterns": ["go.mod"],
"trace.server": "verbose",
"filetypes": ["go"]
}
}
}
python语言配置
:CocInstall coc-python
golang语言配置
- 方案一使用go-vim插件,添加如下配置到init.vim中
let g:go_def_mode='gopls'
let g:go_info_mode='gopls'
- 方案二,使用coc.vim中配置lsp到coc-setting.json文件中
{
"languageserver": {
"golang": {
"command": "gopls",
"rootPatterns": ["go.mod", ".vim/", ".git/", ".hg/"],
"filetypes": ["go"],
"initializationOptions": {
"usePlaceholders": true
}
}
}
}
- 添加自动导入import 包,当文件中缺失要导入的包的时候,在init.vim中添加如下信息
autocmd BufWritePre *.go :call CocAction('runCommand', 'editor.action.organizeImport')
配置文件位置如下:
快速代码跳转
easymotion
简单更改符号
vim-surround
golang开发环境
vim-go
let g:go_def_mode='gopls'
let g:go_info_mode='gopls'
参考:https://github.com/fatih/vim-go/wiki
![入门指导]https://github.com/fatih/vim-go/wiki/Tutorial
" autowrite, 执行:make时自动保存
set autowrite
" shortcut for find error
map <C-n> :cnext<CR>
map <C-m> :cprevious<CR>
nnoremap <leader>a :cclose<CR>
" shortcut for go run, go build
autocmd FileType go nmap <leader>b <Plug>(go-build)
autocmd FileType go nmap <leader>r <Plug>(go-run)
map: 递归映射 : 表示回车 : 表示Ctrl+n noremap: 表示非递归调用 nmap
let g:go_list_type = "quickfix"
在当前文件的基础上增加一个对此文件的test文件,可以直接使用edit xxx_test.go的方式,会自动添加此包的package信息
:edit main_test.go
Testing 执行go的Test测试
:GoTest #执行go test命令
:GoTestFunc #执行光标所在Test函数的测试
# init.vim 中可以设置go test超时时间,由于go test并不是异步的,所以需要有超时时间,万一test挂了呢
let g:go_test_timeout = '10s'
进一步简化go build与go test,根据文件的结尾内容和.go的后缀来判断该执行go test or go build
" run :GoBuild or :GoTestCompile based on the go file
function! s:build_go_files()
let l:file = expand('%')
if l:file =~# '^\f\+_test\.go$'
call go#test#Test(0, 1)
elseif l:file =~# '^\f\+\.go$'
call go#cmd#Build(0)
endif
endfunction
autocmd FileType go nmap <leader>b :<C-u>call <SID>build_go_files()<CR>
格式化go文件, 当保存的时候会自动格式化
:GoFmt
# 关闭保存文件时自动格式化
let g:go_fmt_autosave = 0
导入包
:GoImport strings # 导入strings包
:GoImport s # 通过tab键联想出要导入的包
:GoImportAs # 导入包的同时重定义名字
:GoDrop # 卸载包
自动导入缺失的包移除不需要的包,就是工具goimports
:GoImports #多了一个s
# 也可增加配置,在save的时候自动执行goimports
let g:go_fmt_command = "goimports"
if 和 af 快捷方式 if: 当光标所在函数范围时,执行dif/vif/yif,分别表示删除、选中、复制函数内容,但不包括函数标题和函数注释 af: 与if相似但是会包括函数的标题和注释,将函数注释作为函数的doc信息 如果不想将函数的注释作为doc信息可以执行
let g:go_textobj_include_function_doc = 0
gS和gJ:分别用来将结构体表达式拆分成多行和合并成一行,需要安装如下插件
Plug 'AndrewRadev/splitjoin.vim'
Snippets:快速添加代码片段,推荐安装插件 Ultisnips and neosnippet.此处我使用的是 Ultisnips
Plug 'SirVer/ultisnips'
snippets 的tab键与YouComplete的tab键冲突
golang相关的snippets可以参见如下路径
https://github.com/fatih/vim-go/blob/master/gosnippets/UltiSnips/go.snippets
举例:
errp:
if err != nil {
panic( )
^
cursor position
}
type Foo struct {
Name string # 此处输入json,则会自动添加`json:"name"`
}
Q: 发现一个问题就是在输入errp后没有提示信息,即没有一个列表显示可选项。但是直接输入tab确实能够生成代码,非常考验记忆力 A: 将go.snippets移动到~/.config/nvim/UltiSnips/go.snippets 中,好处可以通过维护自己的go.snippets
- 快捷键:tab-j 跳向下一个可修改参数 tab-k 跳向上一个可修改参数
默认情况下json字符串的格式是下划线的形式,如果想要使用驼峰式,则可以进行如下修改:
let g:go_addtags_transform = "camelcase"
高亮type、function、caller等等
let g:go_highlight_types = 1
let g:go_highlight_fields = 1
let g:go_highlight_fields = 1
let g:go_highlight_function_calls = 1
let g:go_highlight_operators = 1
let g:go_highlight_extra_types = 1
let g:go_highlight_build_constraints = 1
let g:go_highlight_generate_tags = 1
tab转成4空格,默认VIM使用的是8个空格的tab
autocmd BufNewFile,BufRead *.go setlocal noexpandtab tabstop=4 shiftwidth=4
设置配色,注意安装之后,需要将colors/molokai 拷贝到 .vim/目录下,否则找不到配色 colorscheme molokai这句话必须放在plug#begin()plug#end()之外,否则提示找不到这个主题
Plug 'fatih/molokai'
Navigate
Alternate file
在foo.go 和foo_test.go 文件之间跳转,即在source file 和 test file之间跳转
:GoAlternate
Go to definition
跳转到函数定义的位置
:GoDef
# shortcut
ctrl+] 或者 gd
返回前一个浏览位置,只包括函数跳转
:GoDefPop
# shortcut
ctrl+t
返回前一个浏览位置,包括移动的过程
ctrl+o # 如果执行了gd后又执行了滚屏等操作,或者move操作,则再执行ctrl+o是不会直接跳转到上一级函数的,而是一层层将之前的移动依次回退
前进到前一个位置即ctrl+o的反方向操作
ctrl+i
显示函数调用栈
:GoDefStack
清除调用栈信息
:GoDefStackClear
Move between functions
当我们不知道要查找的函数或者只知道函数名字的部分信息时,可以使用如下命令:
:GoDecls # 显示当前文件中的函数
:GoDeclsDir #显示文件夹中的函数,但是不包括子文件夹
显示如下信息可以进行查找
安装插件ctrlp.vim,说是GoDecls必要插件,但是不装也可以,还是装上吧,毕竟装上之后显示的内容更多
Plug 'ctrlpvim/ctrlp.vim'
快速的函数移动
]] -> jump to next function
[[ -> jump to previous function
设置快捷键GoAlternate
autocmd Filetype go command! -bang A call go#alternate#Switch(<bang>0, 'edit')
autocmd Filetype go command! -bang AV call go#alternate#Switch(<bang>0, 'vsplit')
autocmd Filetype go command! -bang AS call go#alternate#Switch(<bang>0, 'split')
autocmd Filetype go command! -bang AT call go#alternate#Switch(<bang>0, 'tabe')
Understand it
Documentation lookup
获取函数的comment信息,可以通过如下命令:
:GoDoc
GoDoc只是显示光标所在函数的comment信息,并不是文档管理器,如果想要使用文档管理器可以安装go-explorer插件
Identifier resolution
我们在编码时经常需要知道函数的参数和返回值等信息,可以使用如下命令显示
:GoInfo
# shortcut
autocmd FileType go nmap <Leader>i <Plug>(go-info)
# 自动显示info信息,当光标停留在合法的描述符上后,会自动显示info信息
let g:go_auto_type_info = 1
# 设置停留时间
set updatetime=100
Identifier highlighting
有时候我们需要高亮某个标识符,此时可以使用如下命令:
:GoSameIds
清除高亮
:GoSameIdsClear
自动高亮设置
:GoSameIdsAutoToggle # 临时生效
#或者永久生效配置init.vim
let g:go_auto_sameids = 1
Dependencies and files
:GoFiles
:GoDeps
Guru
Guru是一个导航工具,一般由于查看代码使用。vim-go集成了一部分guru的功能。
显示光标所在标识符的所有引用,包括标识符的定义
:GoReferrers
显示光标所在标识符的详细信息, 与GoInfo相似不过信息更多,如果是个结构体,包括结构体定义的方法等都会显示出来
:GoDescribe
显示一个方法对应的实现了那个接口
:GoImplements
显示err可能的值是哪些,如果是自定义的可能没办法获取,go自带的应该可以
:GoWhicherr
显示channel分配,send、recv的信息
:GoChannelPeer
显示调用者信息以及调用栈信息
:GoCallees
:GoCallers
:GoCallstack
Refactor it
Remane
替换光标所在标识符的名称
:GoRename bar
当函数比较复杂的时候,可以通过GoFreeVars抽出部分代码生成一个函数,GoFreevars会根据你的选择判断哪些变量定义是需要作为入参的
# 先选中一段代码,在执行如下
:GoFreevars
# quickfix中显示的内容就是函数需要的入参定义
Generate it
通过快捷方式,实现快速定义某个接口的方法
# 先定义一个struct, 光标移至此struct执行如下命令
:GoImpl
智能补全功能
通过安装coc.vim插件,并配置coc-setting.json文件
{
"languageserver": {
"golang": {
"command": "gopls",
"rootPatterns": ["go.mod"],
"disableWorkspaceFolders": true,
"filetypes": ["go"]
}
}
}
需要注意的是gopls必须是能够直接被调用的否则coc.vim插件执行gopls命令会失败
显示函数和变量
tagbar
模糊查找工具fzf
fzf
airline 提示文件类型,名称等信息插件
airline
markdown插入剪切板图片
通过nvim编写markdown文章,但是导入图片却是个麻烦事儿,从网上找打vim插件,可以直接一键导入image
"https://github.com/ferrine/md-img-paste.vim
Plug 'ferrine/md-img-paste.vim'
autocmd FileType markdown nmap <buffer><silent> <leader>p :call mdip#MarkdownClipboardImage()<CR>
" there are some defaults for image directory and image name, you can change them
let g:mdip_imgdir = '.'
let g:mdip_imgname = 'image'
let g:mdip_imgdir_absolute = '/{xxx}/Blog/static/images'
let g:mdip_imgdir_intext = '/images'
- mdip_imgname:表示不输入图片时的默认名称
- mdip_imgdir:表示输入名称的前缀
- p:表示插入剪切板的内容到markdown文件中,并提示输入名称
- mdip_imgdir_absolute: 表示图片保存的绝对路径,由于我的图片存储位置与markdown中输入的内容不同,所以使用相对位置等方式或者让mdip_imgdir即表示markdown中内容又表示文件保存位置是不可行的,所以使用绝对路径和markdown中前缀名称
- mdip_imgdir_intext: 表示markdown文本中的前缀名称
- 规则:如果存在absolute,则使用absolute路径代替imgdir路径;如果没有intext路径,则markdown中使用imgdir表示的路径。
参考https://www.cnblogs.com/mazhuang/p/12863702.html
系统剪切板
- neovim 是不支持与系统剪切板互通的,可以通过如下设置开启
set clipboard+=unnamedplus
# 需要安装剪切工具
# Linux sudo pacman -S xsel
# MacOs brew pbcopy