# nvim_1 **Repository Path**: lion-yie/nvim_1 ## Basic Information - **Project Name**: nvim_1 - **Description**: nvim配置 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2022-06-23 - **Last Updated**: 2022-06-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # NVIM 配置 ## NVIM 安装 ```python # 安装 NVIM brew install nvim brew install ranger # 需要有 python3 支持 brew install python3 brew install node # 对 nvim 添加 python 支持 pip3 install neovim pynvim # 输入 nvim 检测 :checkhealth ``` ![image-20220106235325902](https://gitee.com/SR-Program/blog-image/raw/master/images/202201062353099.png) ## NVIM 配置 ### init.vim ```shell mkdir -p ~/.config/nvim nvim ~/.config/nvim/init.vim " 配置文件导入 "{{{ " --------------------------------------------------------------------- " 基础使用习惯配置 runtime ./vimrc.vim " 插件管理 "./lua/plugins.lua lua require('plugins') " 按键映射 runtime ./maps.vim ``` ### vimrc.vim ```shell nvim ~/.config/nvim/vimrc.vim "----vim 个人使用习惯配置start------ set encoding=UTF-8 " leader设置成空格 let mapleader=" " " 使用鼠标 set mouse=c " 显示行号 set nu " 相对行号 set relativenumber " tab=4个空格 set tabstop=4 set shiftwidth=4 " 改变 vim中光标的形状 let g:db_ui_use_nerd_fonts=1 let &t_SI.="\e[5 q" "SI = INSERT mode let &t_SR.="\e[4 q" "SR = REPLACE mode let &t_EI.="\e[1 q" "EI = NORMAL mode (ELSE) " 高度光标所在行 "set cursorline " 设置不换行 "set nowrap set wrap " 显示按下的按键 set showcmd " 按tab显示菜单 set wildmenu " 不需要备份文件 set nobackup "----vim 个人使用习惯配置end------ "ssh 远程粘贴板 if executable('clipboard-provider') let g:clipboard = { \ 'name': 'myClipboard', \ 'copy': { \ '+': 'clipboard-provider copy', \ '*': 'env COPY_PROVIDERS=tmux clipboard-provider copy', \ }, \ 'paste': { \ '+': 'clipboard-provider paste', \ '*': 'env COPY_PROVIDERS=tmux clipboard-provider paste', \ }, \ } endif "随机选一个颜色风格 function RandomColorScheme() let mycolors = split(globpath(&rtp,"**/colors/*.vim"),"\n") exe 'so ' . mycolors[localtime() % len(mycolors)] unlet mycolors endfunction "call RandomColorScheme() :command NewColor call RandomColorScheme() " 文件类型设置 "{{{ " --------------------------------------------------------------------- " JSX 语法高亮 " set filetypes as typescriptreact autocmd BufNewFile,BufRead *.tsx,*.jsx,*.js set filetype=typescriptreact " 添加头部文件 function HeaderPython() call setline(1, "#!/usr/bin/env python") call append(1, "# -*- coding: utf-8 -*-") call append(2, "# SR @ " . strftime('%Y-%m-%d %T', localtime())) normal G normal o normal o endf autocmd bufnewfile *.py call HeaderPython() ``` ### maps.vim ```shell nvim ~/.config/nvim/maps.vim "------------------------------------------------------------------------------- " window "------------------------------------------------------------------------------- " Split window nmap ss :splitw nmap sv :vsplitw " Move window "nmap w "map s h "map s k "map s j "map s l map sh h map sk k map sj j map sl l " Resize window " 在mac/linux中使用Alt键,在webssh " 中alt没用,就使用Ctrl,WEBSSH主要的WINDOWS中使用 nmap < nmap < nmap s < nmap > nmap > nmap s > nmap + nmap + nmap s + nmap - nmap - nmap s - " 插入模式移动光标 inoremap inoremap inoremap inoremap inoremap " hh在我用的单词里出现的频率极低,其实感觉home用的没有end多,统一风格都用大写的吧 "inoremap HH " 单词中包含ll的太多了,所以用大写LL "inoremap LL " jk inoremap jk " 插入模式鼠标滚轮抵消,不然会出现滚动鼠标录入了一堆5j5k inoremap 5k inoremap 5j inoremap 9 a " 快速跳转行首与行尾 nnoremap L $ nnoremap H ^ " 向下5行 noremap 5j " 向上5行 noremap 5k " 保 存 noremap :w noremap s :w " Coc智能处理,使用IDEA Alt+Enter 同样按键 "noremap :CocAction inoremap :w " 代码格式化 noremap f :Format noremap r :luafile ~/.wp/lua/run.lua " 强制退出 map Q :q "map qq :q " 重新加载设置 map R :source $MYVIMRC "自动关闭标签 inoremap yiwiea>hpF>i set iskeyword+=<,> iab

h1> /h1>5ha " 全选 nmap ggG " 加/减数字1 nnoremap + nnoremap - "------------------------------------------------------------------------------- " Buffers "------------------------------------------------------------------------------- " Open current directory " 插入模式移动光标 inoremap inoremap inoremap inoremap inoremap " hh在我用的单词里出现的频率极低,其实感觉home用的没有end多,统一风格都用大写的吧 "inoremap HH " 单词中包含ll的太多了,所以用大写LL "inoremap LL " jk inoremap jk " 插入模式鼠标滚轮抵消,不然会出现滚动鼠标录入了一堆5j5k inoremap 5k inoremap 5j inoremap 9 a " 快速跳转行首与行尾 nnoremap L $ nnoremap H ^ " 向下5行 noremap 5j " 向上5行 noremap 5k " 保存 noremap :w " Coc智能处理,使用IDEA Alt+Enter 同样按键 noremap :CocAction inoremap :w " 代码格式化 "noremap f :Format " 强制退出 map Q :q " 重新加载设置 map R :source $MYVIMRC "自动关闭标签 inoremap yiwiea>hpF>i set iskeyword+=<,> iab

h1> /h1>5ha " 全选 nmap ggG " 加/减数字1 nnoremap + nnoremap - "------------------------------------------------------------------------------- " Buffers "------------------------------------------------------------------------------- " Open current directory "nmap te :tabedit "nmap :tabprev nmap :bprev "nmap :tabnext nmap :bnext " 窗口管理器 " invoke with '-' nmap - (choosewin) "nmap sw (choosewin) "nmap w (choosewin) ``` > PS:一些插件的快捷键在末尾 当所有插件都配置完毕的时候将快捷键加入该文件中 ### packer 插件管理器 ```shell mkdir -p ~/.config/nvim/lua nvim ~/.config/nvim/plugins.lua ---@diagnostic disable: undefined-global --在没有安装packer的电脑上,自动安装packer插件 local fn = vim.fn local install_path = fn.stdpath('data')..'/site/pack/packer/start/packer.nvim' if fn.empty(fn.glob(install_path)) > 0 then --fn.system({'git', 'clone', '--depth', '1', 'https://github.com/wbthomason/packer.nvim', install_path}) --默认地址 fn.system({'git', 'clone', '--depth', '1', 'https://codechina.csdn.net/mirrors/wbthomason/packer.nvim.git', install_path}) --csdn加速镜像 vim.cmd 'packadd packer.nvim' end -- Only required if you have packer configured as `opt` vim.cmd [[packadd packer.nvim]] return require('packer').startup({ function() use 'wbthomason/packer.nvim'-- Packer can manage itself end, config = { max_jobs = 16, git = { default_url_format = "https://github.com.cnpmjs.org/%s" }, display = { open_fn = function() return require('packer.util').float({ border = 'single' }) end } } }) # 插件安装方式 PackerInstall ``` ## 插件配置 ### 字体配置 ```shell # 终端安装该字体并且选择该字体防止乱码 brew tap homebrew/cask-fonts brew install font-hack-nerd-font --cask ``` ### zephyr-nvim主题配置 #### 安装 ```shell use "glepnir/zephyr-nvim" ``` > PS:该主题基于nvim-treesitter后期做配置 #### 配置 ```shell nvim ~/.config/nvim/after/plugin/zephyr-nvim.lua require('zephyr') ``` ### lualine标签栏美化 #### 安装 ```shell nvim ~/.config/nvim/lua/plugins.lua --状态栏插件 use { "nvim-lualine/lualine.nvim", requires = {"kyazdani42/nvim-web-devicons", opt = true} } ``` #### 配置 ```shell nvim ~/.config/nvim/after/plugin/lualine.lua local status, lualine = pcall(require, "lualine") if (not status) then return end lualine.setup { options = { icons_enabled = true, theme = "auto", component_separators = {left = "", right = ""}, section_separators = {left = "", right = ""}, disabled_filetypes = {}, always_divide_middle = true }, sections = { lualine_a = {"mode"}, lualine_b = { "branch", "diff" --{"diagnostics", sources = {"nvim_lsp"}} }, lualine_c = {"filename"}, lualine_x = { {"diagnostics", sources = {"nvim_lsp"}, symbols = {error = " ", warn = " ", info = " ", hint = " "}}, "encoding", "fileformat", "filetype" }, lualine_y = {"progress"}, lualine_z = {"location"} }, inactive_sections = { lualine_a = {}, lualine_b = {}, lualine_c = {"filename"}, lualine_x = {"location"}, lualine_y = {}, lualine_z = {} }, tabline = {}, extensions = {} } ``` ![image-20220107013051893](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070130975.png) ### bufferline状态栏 #### 安装 ```python -- bufferline 显示标签页,与lualine配合使用 use "akinsho/bufferline.nvim" ``` #### 配置 ```python nvim ~/.config/nvim/after/plugin/bufferline.lua local status, bufferline = pcall(require, "bufferline") if (not status) then return end vim.opt.termguicolors = true bufferline.setup { options = { --numbers = "ordinal" | "buffer_id" | "both" | function({ ordinal, id, lower, raise }): string, --numbers = "both", --- @deprecated, please specify numbers as a function to customize the styling --number_style = "superscript" | "subscript" | "" | { "none", "subscript" }, -- buffer_id at index 1, ordinal at index 2 --number_style = "none", close_command = "bdelete! %d", -- can be a string | function, see "Mouse actions" right_mouse_command = "bdelete! %d", -- can be a string | function, see "Mouse actions" left_mouse_command = "buffer %d", -- can be a string | function, see "Mouse actions" middle_mouse_command = nil, -- can be a string | function, see "Mouse actions" -- NOTE: this plugin is designed with this icon in mind, -- and so changing this is NOT recommended, this is intended -- as an escape hatch for people who cannot bear it for whatever reason indicator_icon = "", buffer_close_icon = "", modified_icon = "●", close_icon = "", left_trunc_marker = "", right_trunc_marker = "", --- name_formatter can be used to change the buffer's label in the bufferline. --- Please note some names can/will break the --- bufferline so use this at your discretion knowing that it has --- some limitations that will *NOT* be fixed. name_formatter = function(buf) -- buf contains a "name", "path" and "bufnr" -- remove extension from markdown files for example if buf.name:match("%.md") then return vim.fn.fnamemodify(buf.name, ":t:r") end end, max_name_length = 15, max_prefix_length = 12, -- prefix used when a buffer is de-duplicated tab_size = 15, --diagnostics = false | "nvim_lsp" | "coc", diagnostics = "nvim_lsp", diagnostics_update_in_insert = false, --[[diagnostics_indicator = function(count, level, diagnostics_dict, context) return "(" .. count .. ")" end,]] -- rest of config ... --- count is an integer representing total count of errors --- level is a string "error" | "warning" --- diagnostics_dict is a dictionary from error level ("error", "warning" or "info")to number of errors for each level. --- this should return a string --- Don't get too fancy as this function will be executed a lot diagnostics_indicator = function(count, level, diagnostics_dict, context) local icon = level:match("error") and " " or " " return " " .. icon .. count end, -- NOTE: this will be called a lot so don't do any heavy processing here custom_filter = function(buf_number) --如果是defx则隐藏 local finded, _ = string.find(vim.bo[buf_number].filetype, "defx") if finded ~= nil then return false end return true end, --offsets = {{filetype = "NvimTree", text = "File Explorer" | function , text_align = "left" | "center" | "right"}}, --show_buffer_icons = true | false, -- disable filetype icons for buffers show_buffer_icons = true, -- disable filetype icons for buffers --show_buffer_close_icons = true | false, show_buffer_close_icons = false, --show_close_icon = true | false, show_close_icon = false, --show_tab_indicators = true | false, show_tab_indicators = true, persist_buffer_sort = true, -- whether or not custom sorted buffers should persist -- can also be a table containing 2 custom separators -- [focused and unfocused]. eg: { '|', '|' } --separator_style = "slant" | "thick" | "thin" | {"any", "any"}, separator_style = "thin", --enforce_regular_tabs = false | true, enforce_regular_tabs = false, --always_show_bufferline = true | false, always_show_bufferline = true --[[sort_by = "id" | "extension" | "relative_directory" | "directory" | "tabs" | function(buffer_a, buffer_b) -- add custom logic return buffer_a.modified > buffer_b.modified end]] } } --按键映射 --nnoremap gb :BufferLinePick vim.api.nvim_set_keymap("n", "gb", "BufferLinePick", {noremap = true, silent = true}) vim.api.nvim_set_keymap("n", "1", "BufferLineGoToBuffer 1", {noremap = true, silent = true}) vim.api.nvim_set_keymap("n", "2", "BufferLineGoToBuffer 2", {noremap = true, silent = true}) vim.api.nvim_set_keymap("n", "3", "BufferLineGoToBuffer 3", {noremap = true, silent = true}) vim.api.nvim_set_keymap("n", "4", "BufferLineGoToBuffer 4", {noremap = true, silent = true}) vim.api.nvim_set_keymap("n", "5", "BufferLineGoToBuffer 5", {noremap = true, silent = true}) vim.api.nvim_set_keymap("n", "6", "BufferLineGoToBuffer 6", {noremap = true, silent = true}) vim.api.nvim_set_keymap("n", "7", "BufferLineGoToBuffer 7", {noremap = true, silent = true}) vim.api.nvim_set_keymap("n", "8", "BufferLineGoToBuffer 8", {noremap = true, silent = true}) vim.api.nvim_set_keymap("n", "9", "BufferLineGoToBuffer 9", {noremap = true, silent = true}) ``` ![image-20220107013221086](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070132211.png) ### dashboard开屏插件 #### 安装 ```python use {"glepnir/dashboard-nvim"} ``` #### 配置 ```shell nvim ~/.config/nvim/after/plugin/dashboard.lua local vim = vim vim.g.dashboard_custom_header = { "", " ⠀⠀⠀⠀⠀⠀⠀⠀⠀⡴⠞⠉⢉⣭⣿⣿⠿⣳⣤⠴⠖⠛⣛⣿⣿⡷⠖⣶⣤⡀⠀⠀⠀ ", " ⠀⠀⠀⠀⠀⠀⠀⣼⠁⢀⣶⢻⡟⠿⠋⣴⠿⢻⣧⡴⠟⠋⠿⠛⠠⠾⢛⣵⣿⠀⠀⠀⠀ ", " ⣼⣿⡿⢶⣄⠀⢀⡇⢀⡿⠁⠈⠀⠀⣀⣉⣀⠘⣿⠀⠀⣀⣀⠀⠀⠀⠛⡹⠋⠀⠀⠀⠀ ", " ⣭⣤⡈⢑⣼⣻⣿⣧⡌⠁⠀⢀⣴⠟⠋⠉⠉⠛⣿⣴⠟⠋⠙⠻⣦⡰⣞⠁⢀⣤⣦⣤⠀ ", " ⠀⠀⣰⢫⣾⠋⣽⠟⠑⠛⢠⡟⠁⠀⠀⠀⠀⠀⠈⢻⡄⠀⠀⠀⠘⣷⡈⠻⣍⠤⢤⣌⣀ ", " ⢀⡞⣡⡌⠁⠀⠀⠀⠀⢀⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⢿⡀⠀⠀⠀⠸⣇⠀⢾⣷⢤⣬⣉ ", " ⡞⣼⣿⣤⣄⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⣿⠀⠸⣿⣇⠈⠻ ", " ⢰⣿⡿⢹⠃⠀⣠⠤⠶⣼⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⣿⠀⠀⣿⠛⡄⠀ ", " ⠈⠉⠁⠀⠀⠀⡟⡀⠀⠈⡗⠲⠶⠦⢤⣤⣤⣄⣀⣀⣸⣧⣤⣤⠤⠤⣿⣀⡀⠉⣼⡇⠀ ", " ⣿⣴⣴⡆⠀⠀⠻⣄⠀⠀⠡⠀⠀⠀⠈⠛⠋⠀⠀⠀⡈⠀⠻⠟⠀⢀⠋⠉⠙⢷⡿⡇⠀ ", " ⣻⡿⠏⠁⠀⠀⢠⡟⠀⠀⠀⠣⡀⠀⠀⠀⠀⠀⢀⣄⠀⠀⠀⠀⢀⠈⠀⢀⣀⡾⣴⠃⠀ ", " ⢿⠛⠀⠀⠀⠀⢸⠁⠀⠀⠀⠀⠈⠢⠄⣀⠠⠼⣁⠀⡱⠤⠤⠐⠁⠀⠀⣸⠋⢻⡟⠀⠀ ", " ⠈⢧⣀⣤⣶⡄⠘⣆⠀⠀⠀⠀⠀⠀⠀⢀⣤⠖⠛⠻⣄⠀⠀⠀⢀⣠⡾⠋⢀⡞⠀⠀⠀ ", " ⠀⠀⠻⣿⣿⡇⠀⠈⠓⢦⣤⣤⣤⡤⠞⠉⠀⠀⠀⠀⠈⠛⠒⠚⢩⡅⣠⡴⠋⠀⠀⠀⠀ ", " ⠀⠀⠀⠈⠻⢧⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⣻⠿⠋⠀⠀⠀⠀⠀⠀ ", " ⠀⠀⠀⠀⠀⠀⠉⠓⠶⣤⣄⣀⡀⠀⠀⠀⠀⠀⢀⣀⣠⡴⠖⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀ ", " ", "", } vim.g.dashboard_custom_section = { a = { description = { "  新 文 件 SPC fo" }, command = "DashboardNewFile", }, b = { description = { "  查找文件 SPC ff" }, -- command = "Telescope fd", command = "Telescope fd find_command=fd,--hidden", }, c = { description = { "  已用文件 SPC fh" }, command = "Telescope oldfiles", }, d = { description = { "  跳转标记 SPC fm" }, command = "Telescope marks", }, e = { description = { "  查看内容 SPC fw" }, command = "Telescope live_grep", }, f = { description = { "  查看主题 SPC tc" }, command = "Telescope colorscheme", }, g = { description = { " ∂ 查看命令 SPC fc" }, command = "Telescope commands", }, h = { description = { "  查看帮助 SPC fa" }, command = "Telescope man_pages", }, } vim.g.dashboard_disable_at_vimenter = 0 vim.g.dashboard_footer_icon = " 🐬 " vim.g.dashboard_preview_command = "bat" -- vim.g.dashboard_preview_pipeline = "lolcat -F 0.3" vim.g.dashboard_session_directory = "~/.config/nvim/.sessions" vim.g.dashboard_preview_file_height = 12 vim.g.dashboard_preview_file_width = 80 vim.g.dashboard_default_executive = "Telescope" ``` ![image-20220107014239249](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070142355.png) ### defx文件插件 #### 安装 ```shell # 安装 -- 文件管理插件,类似与ranger。 use { "Shougo/defx.nvim", requires = { "kristijanhusak/defx-icons", -- dexf文件管理图标支持 "t9md/vim-choosewin" -- 窗口选择器,可以让defx使用i打开文件 } } ``` #### 配置 ```shell mkdir -p ~/.config/nvim/after/plugin nvim ~/.config/nvim/after/plugin/defx.rc.vim # 配置如下 if !exists('g:loaded_defx') | finish | endif " Define mappings "cnoreabbrev sf Defx -listed -new " \ -columns=indent:mark:icon:icons:filename:git:size " \ -buffer-name=tab`tabpagenr()` nnoremap sf :Defx -listed -resume \ -columns=indent:mark:icon:icons:filename:git:size \ -buffer-name=tab`tabpagenr()` \ `expand('%:p:h')` -search=`expand('%:p')` "nnoremap fi :Defx -new `expand('%:p:h')` -search=`expand('%:p')` autocmd FileType defx call s:defx_my_settings() function! s:defx_my_settings() abort " Define mappings nnoremap \ defx#do_action('open') nnoremap yy \ defx#do_action('copy') nnoremap dd \ defx#do_action('move') nnoremap pp \ defx#do_action('paste') nnoremap l \ defx#do_action('open') nnoremap \ defx#do_action('open') nnoremap E \ defx#do_action('open', 'vsplit') nnoremap n \ defx#do_action('open', 'pedit') nnoremap i \ defx#do_action('open', 'choose') nnoremap o \ defx#do_action('open_or_close_tree') nnoremap K \ defx#do_action('new_directory') nnoremap N \ defx#do_action('new_file') nnoremap M \ defx#do_action('new_multiple_files') nnoremap C \ defx#do_action('toggle_columns', \ 'mark:indent:icon:filename:type:size:time') nnoremap S \ defx#do_action('toggle_sort', 'time') nnoremap dD \ defx#do_action('remove') nnoremap a \ defx#do_action('rename') nnoremap ! \ defx#do_action('execute_command') nnoremap x \ defx#do_action('execute_system') nnoremap YY \ defx#do_action('yank_path') nnoremap . \ defx#do_action('toggle_ignored_files') nnoremap \ defx#do_action('toggle_ignored_files') nnoremap ; \ defx#do_action('repeat') nnoremap h \ defx#do_action('cd', ['..']) nnoremap \ defx#do_action('cd', ['..']) nnoremap ~ \ defx#do_action('cd') nnoremap gh \ defx#do_action('cd') nnoremap gn \ defx#do_action('cd',['~/.config/nvim']) nnoremap q \ defx#do_action('quit') nnoremap \ defx#do_action('toggle_select') . 'j' nnoremap m \ defx#do_action('toggle_select') . 'j' nnoremap vv \ defx#do_action('toggle_select_all') nnoremap * \ defx#do_action('toggle_select_all') nnoremap j \ line('.') == line('$') ? 'gg' : 'j' nnoremap k \ line('.') == 1 ? 'G' : 'k' nnoremap \ defx#do_action('redraw') nnoremap \ defx#do_action('print') nnoremap cd \ defx#do_action('change_vim_cwd') endfunction call defx#custom#column('icon', { \ 'directory_icon': '▸', \ 'opened_icon': '▾', \ 'root_icon': ' ', \ }) call defx#custom#column('git', 'indicators', { \ 'Modified' : 'M', \ 'Staged' : '✚', \ 'Untracked' : '✭', \ 'Renamed' : '➜', \ 'Unmerged' : '═', \ 'Ignored' : '☒', \ 'Deleted' : '✖', \ 'Unknown' : '?' \ }) ``` #### defx-icons配置 ```shell nvim ~/.config/nvim/after/plugin/defx-icons.rc.vim " 增加图标的宽度,来解决图标 与文件名重叠的问题 let g:defx_icons_column_length = 2 " 因为图标配置需要优化级比较高,所以要在init.vim中增加如下一行: nvim ~/.config/nvim/init.vim source ~/.config/nvim/after/plugin/defx-icons.rc.vim ``` #### vim-choosewin配置 ```shell " 这是一个窗口选择插件. nvim ~/.config/nvim/after/plugin/vim-choosewin.rc.vim "window选择器 " if you want to use overlay feature let g:choosewin_overlay_enable = 1 ``` #### 快捷键 >sf 启动文件管理器 ![image-20220107002128223](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070021276.png) > l进入下一层目录 ![image-20220107002301742](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070023792.png) > h 返回上一层目录 ![image-20220107002344062](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070023105.png) > K(大写)创建目录 ![image-20220107002503152](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070025199.png) > N 创建新的文件 ![image-20220107002641179](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070026227.png) > 空格/m 文件选择 ![image-20220107003047227](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070030269.png) | 快捷键 | 操作 | | :----: | :------: | | j | 向下一行 | | k | 向上一行 | | yy | 复制 | | pp | 粘贴 | | dd | 剪切 | | dD | 删除 | | vv | 文件全选 | | a | 文件重命名 | ### LSP 代码补全插件 #### 安装 ```shell --Nvim LSP 客户端的快速入门配置 use "neovim/nvim-lspconfig" use { "hrsh7th/nvim-cmp", requires = { "hrsh7th/cmp-nvim-lsp", --neovim 内置 LSP 客户端的 nvim-cmp 源 --以下插件可选,可以根据个人喜好删减 "onsails/lspkind-nvim", --美化自动完成提示信息 "hrsh7th/cmp-buffer", --从buffer中智能提示 "hrsh7th/cmp-nvim-lua", --nvim-cmp source for neovim Lua API. "octaltree/cmp-look", --用于完成英语单词 "hrsh7th/cmp-path", --自动提示硬盘上的文件 "hrsh7th/cmp-calc", --输入数学算式(如1+1=)自动计算 "f3fora/cmp-spell", --nvim-cmp 的拼写源基于 vim 的拼写建议 "hrsh7th/cmp-emoji", --输入: 可以显示表情 } } -- 代码段提示 use { "L3MON4D3/LuaSnip", requires = { "saadparwaiz1/cmp_luasnip", -- Snippets source for nvim-cmp "rafamadriz/friendly-snippets" --代码段合集 } } ``` #### 配置 ```shell nvim ~/.config/nvim/after/plugin/lspconfig.rc.vim if !exists('g:lspconfig') finish endif lua << EOF --提示信息自定义图标 -- icon vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with( vim.lsp.diagnostic.on_publish_diagnostics, { underline = true, -- This sets the spacing and the prefix, obviously. virtual_text = { spacing = 4, prefix = '' } } ) EOF ``` #### nvim-cmp配置 ```shell nvim ~/.config/nvim/after/plugin/nvim-cmp.lua local status, nvim_lsp = pcall(require, "lspconfig") if (not status) then return end --local nvim_lsp = require('lspconfig') --typescript支持 require("lspconf.typescript") --json支持 --require("lspconf.json") --lua --require("lspconf.lua") --普通的语言支持 --require("lspconf.common") -- Set completeopt to have a better completion experience vim.o.completeopt = "menuone,noselect" -- luasnip setup local luasnip = require "luasnip" local lspkind = require("lspkind") -- nvim-cmp setup local cmp = require "cmp" -- 自动提示1 详情信息 local cmpFormat1 = function(entry, vim_item) -- fancy icons and a name of kind vim_item.kind = require("lspkind").presets.default[vim_item.kind] .. " " .. vim_item.kind -- set a name for each source vim_item.menu = ({ buffer = "[Buffer]", nvim_lsp = "[LSP]", ultisnips = "[UltiSnips]", nvim_lua = "[Lua]", cmp_tabnine = "[TabNine]", look = "[Look]", path = "[Path]", spell = "[Spell]", calc = "[Calc]", emoji = "[Emoji]" })[entry.source.name] return vim_item end -- 自动提示2 简洁信息 local cmpFormat2 = function(entry, vim_item) vim_item.kind = lspkind.presets.default[vim_item.kind] return vim_item end -- 自动提示3 详情信息 local cmpFormat3 = function(entry, vim_item) -- fancy icons and a name of kind vim_item.kind = require("lspkind").presets.default[vim_item.kind] .. "" -- set a name for each source vim_item.menu = ({ buffer = "[Buffer]", nvim_lsp = "", ultisnips = "[UltiSnips]", nvim_lua = "[Lua]", cmp_tabnine = "[TabNine]", look = "[Look]", path = "[Path]", spell = "[Spell]", calc = "[Calc]", emoji = "[Emoji]" })[entry.source.name] return vim_item end ------修复2021年10月12日 nvim-cmp.luaattempt to index field 'menu' (a nil value)--------- --重写插件方法,为了实现function 后,自动追加() local keymap = require("cmp.utils.keymap") cmp.confirm = function(option) option = option or {} local e = cmp.core.view:get_selected_entry() or (option.select and cmp.core.view:get_first_entry() or nil) if e then cmp.core:confirm( e, { behavior = option.behavior }, function() local myContext = cmp.core:get_context({reason = cmp.ContextReason.TriggerOnly}) cmp.core:complete(myContext) --function() 自动增加() if e and e.resolved_completion_item and (e.resolved_completion_item.kind == 3 or e.resolved_completion_item.kind == 2) then vim.api.nvim_feedkeys(keymap.t("()"), "n", true) end end ) return true else if vim.fn.complete_info({"selected"}).selected ~= -1 then keymap.feedkeys(keymap.t(""), "n") return true end return false end end --------------- cmp.setup { formatting = { format = cmpFormat1 }, snippet = { expand = function(args) require("luasnip").lsp_expand(args.body) end }, mapping = { [""] = cmp.mapping.select_prev_item(), [""] = cmp.mapping.select_next_item(), [""] = cmp.mapping.scroll_docs(-4), [""] = cmp.mapping.scroll_docs(4), [""] = cmp.mapping.complete(), [""] = cmp.mapping.close(), [""] = cmp.mapping.confirm { behavior = cmp.ConfirmBehavior.Replace, select = false }, [''] = function(fallback) if cmp.visible() then cmp.select_next_item() elseif luasnip.expand_or_jumpable() then vim.fn.feedkeys(vim.api.nvim_replace_termcodes('luasnip-expand-or-jump', true, true, true), '') else fallback() end end, [''] = function(fallback) if cmp.visible() then cmp.select_prev_item() elseif luasnip.jumpable(-1) then vim.fn.feedkeys(vim.api.nvim_replace_termcodes('luasnip-jump-prev', true, true, true), '') else fallback() end end }, sources = { {name = "nvim_lsp"}, {name = "luasnip"}, --{name = "nvim_lua"}, { name = "buffer", options = { get_bufnrs = function() return vim.api.nvim_list_bufs() end } }, --{name = "look"}, {name = "path"} --{name = "cmp_tabnine"}, --{name = "calc"}, --{name = "spell"}, --{name = "emoji"} } } ``` #### LuaSnip配置 ```shell nvim ~/.config/nvim/after/plugin/snippets.lua local ls = require("luasnip") -- some shorthands... local s = ls.snippet local sn = ls.snippet_node local t = ls.text_node local i = ls.insert_node local f = ls.function_node local c = ls.choice_node local d = ls.dynamic_node local l = require("luasnip.extras").lambda local r = require("luasnip.extras").rep local p = require("luasnip.extras").partial local m = require("luasnip.extras").match local n = require("luasnip.extras").nonempty local dl = require("luasnip.extras").dynamic_lambda local fmt = require("luasnip.extras.fmt").fmt local fmta = require("luasnip.extras.fmt").fmta local types = require("luasnip.util.types") local conds = require("luasnip.extras.expand_conditions") -- Every unspecified option will be set to the default. ls.config.set_config({ history = true, -- Update more often, :h events for more info. updateevents = "TextChanged,TextChangedI", ext_opts = { [types.choiceNode] = { active = { virt_text = { { "choiceNode", "Comment" } }, }, }, }, -- treesitter-hl has 100, use something higher (default is 200). ext_base_prio = 300, -- minimal increase in priority. ext_prio_increase = 1, enable_autosnippets = true, }) -- args is a table, where 1 is the text in Placeholder 1, 2 the text in -- placeholder 2,... local function copy(args) return args[1] end -- 'recursive' dynamic snippet. Expands to some text followed by itself. local rec_ls rec_ls = function() return sn( nil, c(1, { -- Order is important, sn(...) first would cause infinite loop of expansion. t(""), sn(nil, { t({ "", "\t\\item " }), i(1), d(2, rec_ls, {}) }), }) ) end -- complicated function for dynamicNode. local function jdocsnip(args, _, old_state) local nodes = { t({ "/**", " * " }), i(1, "A short Description"), t({ "", "" }), } -- These will be merged with the snippet; that way, should the snippet be updated, -- some user input eg. text can be referred to in the new snippet. local param_nodes = {} if old_state then nodes[2] = i(1, old_state.descr:get_text()) end param_nodes.descr = nodes[2] -- At least one param. if string.find(args[2][1], ", ") then vim.list_extend(nodes, { t({ " * ", "" }) }) end local insert = 2 for indx, arg in ipairs(vim.split(args[2][1], ", ", true)) do -- Get actual name parameter. arg = vim.split(arg, " ", true)[2] if arg then local inode -- if there was some text in this parameter, use it as static_text for this new snippet. if old_state and old_state[arg] then inode = i(insert, old_state["arg" .. arg]:get_text()) else inode = i(insert) end vim.list_extend( nodes, { t({ " * @param " .. arg .. " " }), inode, t({ "", "" }) } ) param_nodes["arg" .. arg] = inode insert = insert + 1 end end if args[1][1] ~= "void" then local inode if old_state and old_state.ret then inode = i(insert, old_state.ret:get_text()) else inode = i(insert) end vim.list_extend( nodes, { t({ " * ", " * @return " }), inode, t({ "", "" }) } ) param_nodes.ret = inode insert = insert + 1 end if vim.tbl_count(args[3]) ~= 1 then local exc = string.gsub(args[3][2], " throws ", "") local ins if old_state and old_state.ex then ins = i(insert, old_state.ex:get_text()) else ins = i(insert) end vim.list_extend( nodes, { t({ " * ", " * @throws " .. exc .. " " }), ins, t({ "", "" }) } ) param_nodes.ex = ins insert = insert + 1 end vim.list_extend(nodes, { t({ " */" }) }) local snip = sn(nil, nodes) -- Error on attempting overwrite. snip.old_state = param_nodes return snip end -- Make sure to not pass an invalid command, as io.popen() may write over nvim-text. local function bash(_, _, command) local file = io.popen(command, "r") local res = {} for line in file:lines() do table.insert(res, line) end return res end -- Returns a snippet_node wrapped around an insert_node whose initial -- text value is set to the current date in the desired format. local date_input = function(args, state, fmt) local fmt = fmt or "%Y-%m-%d" return sn(nil, i(1, os.date(fmt))) end ls.snippets = { -- When trying to expand a snippet, luasnip first searches the tables for -- each filetype specified in 'filetype' followed by 'all'. -- If ie. the filetype is 'lua.c' -- - luasnip.lua -- - luasnip.c -- - luasnip.all -- are searched in that order. all = { -- trigger is fn. s("fn", { -- Simple static text. t("//Parameters: "), -- function, first parameter is the function, second the Placeholders -- whose text it gets as input. f(copy, 2), t({ "", "function " }), -- Placeholder/Insert. i(1), t("("), -- Placeholder with initial text. i(2, "int foo"), -- Linebreak t({ ") {", "\t" }), -- Last Placeholder, exit Point of the snippet. EVERY 'outer' SNIPPET NEEDS Placeholder 0. i(0), t({ "", "}" }), }), s("class", { -- Choice: Switch between two different Nodes, first parameter is its position, second a list of nodes. c(1, { t("public "), t("private "), }), t("class "), i(2), t(" "), c(3, { t("{"), -- sn: Nested Snippet. Instead of a trigger, it has a position, just like insert-nodes. !!! These don't expect a 0-node!!!! -- Inside Choices, Nodes don't need a position as the choice node is the one being jumped to. sn(nil, { t("extends "), i(1), t(" {"), }), sn(nil, { t("implements "), i(1), t(" {"), }), }), t({ "", "\t" }), i(0), t({ "", "}" }), }), -- Use a dynamic_node to interpolate the output of a -- function (see date_input above) into the initial -- value of an insert_node. s("novel", { t("It was a dark and stormy night on "), d(1, date_input, {}, "%A, %B %d of %Y"), t(" and the clocks were striking thirteen."), }), -- Parsing snippets: First parameter: Snippet-Trigger, Second: Snippet body. -- Placeholders are parsed into choices with 1. the placeholder text(as a snippet) and 2. an empty string. -- This means they are not SELECTed like in other editors/Snippet engines. ls.parser.parse_snippet( "lspsyn", "Wow! This ${1:Stuff} really ${2:works. ${3:Well, a bit.}}" ), -- When wordTrig is set to false, snippets may also expand inside other words. ls.parser.parse_snippet( { trig = "te", wordTrig = false }, "${1:cond} ? ${2:true} : ${3:false}" ), -- When regTrig is set, trig is treated like a pattern, this snippet will expand after any number. ls.parser.parse_snippet({ trig = "%d", regTrig = true }, "A Number!!"), -- Using the condition, it's possible to allow expansion only in specific cases. s("cond", { t("will only expand in c-style comments"), }, { condition = function(line_to_cursor, matched_trigger, captures) -- optional whitespace followed by // return line_to_cursor:match("%s*//") end, }), -- there's some built-in conditions in "luasnip.extras.expand_conditions". s("cond2", { t("will only expand at the beginning of the line"), }, { condition = conds.line_begin, }), -- The last entry of args passed to the user-function is the surrounding snippet. s( { trig = "a%d", regTrig = true }, f(function(_, snip) return "Triggered with " .. snip.trigger .. "." end, {}) ), -- It's possible to use capture-groups inside regex-triggers. s( { trig = "b(%d)", regTrig = true }, f(function(_, snip) return "Captured Text: " .. snip.captures[1] .. "." end, {}) ), s({ trig = "c(%d+)", regTrig = true }, { t("will only expand for even numbers"), }, { condition = function(line_to_cursor, matched_trigger, captures) return tonumber(captures[1]) % 2 == 0 end, }), -- Use a function to execute any shell command and print its text. s("bash", f(bash, {}, "ls")), -- Short version for applying String transformations using function nodes. s("transform", { i(1, "initial text"), t({ "", "" }), -- lambda nodes accept an l._1,2,3,4,5, which in turn accept any string transformations. -- This list will be applied in order to the first node given in the second argument. l(l._1:match("[^i]*$"):gsub("i", "o"):gsub(" ", "_"):upper(), 1), }), s("transform2", { i(1, "initial text"), t("::"), i(2, "replacement for e"), t({ "", "" }), -- Lambdas can also apply transforms USING the text of other nodes: l(l._1:gsub("e", l._2), { 1, 2 }), }), s({ trig = "trafo(%d+)", regTrig = true }, { -- env-variables and captures can also be used: l(l.CAPTURE1:gsub("1", l.TM_FILENAME), {}), }), -- Set store_selection_keys = "" (for example) in your -- luasnip.config.setup() call to access TM_SELECTED_TEXT. In -- this case, select a URL, hit Tab, then expand this snippet. s("link_url", { t(''), i(1), t(""), i(0), }), -- Shorthand for repeating the text in a given node. s("repeat", { i(1, "text"), t({ "", "" }), r(1) }), -- Directly insert the ouput from a function evaluated at runtime. s("part", p(os.date, "%Y")), -- use matchNodes to insert text based on a pattern/function/lambda-evaluation. s("mat", { i(1, { "sample_text" }), t(": "), m(1, "%d", "contains a number", "no number :("), }), -- The inserted text defaults to the first capture group/the entire -- match if there are none s("mat2", { i(1, { "sample_text" }), t(": "), m(1, "[abc][abc][abc]"), }), -- It is even possible to apply gsubs' or other transformations -- before matching. s("mat3", { i(1, { "sample_text" }), t(": "), m( 1, l._1:gsub("[123]", ""):match("%d"), "contains a number that isn't 1, 2 or 3!" ), }), -- `match` also accepts a function, which in turn accepts a string -- (text in node, \n-concatted) and returns any non-nil value to match. -- If that value is a string, it is used for the default-inserted text. s("mat4", { i(1, { "sample_text" }), t(": "), m(1, function(text) return (#text % 2 == 0 and text) or nil end), }), -- The nonempty-node inserts text depending on whether the arg-node is -- empty. s("nempty", { i(1, "sample_text"), n(1, "i(1) is not empty!"), }), -- dynamic lambdas work exactly like regular lambdas, except that they -- don't return a textNode, but a dynamicNode containing one insertNode. -- This makes it easier to dynamically set preset-text for insertNodes. s("dl1", { i(1, "sample_text"), t({ ":", "" }), dl(2, l._1, 1), }), -- Obviously, it's also possible to apply transformations, just like lambdas. s("dl2", { i(1, "sample_text"), i(2, "sample_text_2"), t({ "", "" }), dl(3, l._1:gsub("\n", " linebreak ") .. l._2, { 1, 2 }), }), -- Alternative printf-like notation for defining snippets. It uses format -- string with placeholders similar to the ones used with Python's .format(). s( "fmt1", fmt("To {title} {} {}.", { i(2, "Name"), i(3, "Surname"), title = c(1, { t("Mr."), t("Ms.") }), }) ), -- To escape delimiters use double them, e.g. `{}` -> `{{}}`. -- Multi-line format strings by default have empty first/last line removed. -- Indent common to all lines is also removed. Use the third `opts` argument -- to control this behaviour. s( "fmt2", fmt( [[ foo({1}, {3}) {{ return {2} * {4} }} ]], { i(1, "x"), r(1), i(2, "y"), r(2), } ) ), -- Empty placeholders are numbered automatically starting from 1 or the last -- value of a numbered placeholder. Named placeholders do not affect numbering. s( "fmt3", fmt("{} {a} {} {1} {}", { t("1"), t("2"), a = t("A"), }) ), -- The delimiters can be changed from the default `{}` to something else. s("fmt4", fmt("foo() { return []; }", i(1, "x"), { delimiters = "[]" })), -- `fmta` is a convenient wrapper that uses `<>` instead of `{}`. s("fmt5", fmta("foo() { return <>; }", i(1, "x"))), -- By default all args must be used. Use strict=false to disable the check s( "fmt6", fmt("use {} only", { t("this"), t("not this") }, { strict = false }) ), }, java = { -- Very long example for a java class. s("fn", { d(6, jdocsnip, { 2, 4, 5 }), t({ "", "" }), c(1, { t("public "), t("private "), }), c(2, { t("void"), t("String"), t("char"), t("int"), t("double"), t("boolean"), i(nil, ""), }), t(" "), i(3, "myFunc"), t("("), i(4), t(")"), c(5, { t(""), sn(nil, { t({ "", " throws " }), i(1), }), }), t({ " {", "\t" }), i(0), t({ "", "}" }), }), }, tex = { -- rec_ls is self-referencing. That makes this snippet 'infinite' eg. have as many -- \item as necessary by utilizing a choiceNode. s("ls", { t({ "\\begin{itemize}", "\t\\item " }), i(1), d(2, rec_ls, {}), t({ "", "\\end{itemize}" }), }), }, } -- autotriggered snippets have to be defined in a separate table, luasnip.autosnippets. ls.autosnippets = { all = { s("autotrigger", { t("autosnippet"), }), }, } -- in a lua file: search lua-, then c-, then all-snippets. ls.filetype_extend("lua", { "c" }) -- in a cpp file: search c-snippets, then all-snippets only (no cpp-snippets!!). ls.filetype_set("cpp", { "c" }) --[[ -- 除了定义你自己的代码片段,你还可以从“类似 vscode”的包中加载代码片段 -- 在 json 文件中公开片段,例如 . -- 请注意,这将扩展 `ls.snippets`,因此您需要在您自己的代码片段之后执行此操作,或者您 -- 需要自己扩展表格而不是设置一个新表格。 ]] --require("luasnip/loaders/from_vscode").load({ include = { "javascript" } }) -- Load only python snippets require("luasnip/loaders/from_vscode").load() -- Load only python snippets -- The directories will have to be structured like eg. (include -- a similar `package.json`) --require("luasnip/loaders/from_vscode").load({ paths = { "./my-snippets" } }) -- Load snippets from my-snippets folder --require("luasnip/loaders/from_vscode").load({ paths = { "/Users/itkey/Documents/my-snippets/" } }) -- Load snippets from my-snippets folder -- You can also use lazy loading so you only get in memory snippets of languages you use --require("luasnip/loaders/from_vscode").lazy_load() -- You can pass { paths = "./my-snippets/"} as well ``` ### nvim-lsp-installer打造 python IDE #### 安装 ```shell use 'kabouzeid/nvim-lspinstall' ``` #### 配置 ```shell nvim ~/.config/nvim/after/plugin/nvim-lspinstall.lua require'lspinstall'.setup() -- important local servers = require'lspinstall'.installed_servers() for _, server in pairs(servers) do require'lspconfig'[server].setup{} end ``` #### 使用方式 - LspInstall to install/update the language server for (e.g. :LspInstall python). - LspUninstall to uninstall the language server for . - require'lspinstall'.setup() to make configs of installed servers available for require’lspconfig’..setup{}. - :LspInstall python > 关键字提示 ![image-20220107005144835](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070051933.png) > 代码提示 ![image-20220107005238858](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070052947.png) > 语法检查 ![image-20220107005339113](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070053215.png) ### Lsp UI美化 #### 安装 ```shell -- 自动为尚不支持 Neovim 0.5 内置 lsp 客户端的配色方案创建缺少的 LSP 诊断突出显示组。 use "folke/lsp-colors.nvim" -- 基于neovim 内置lsp 的轻量级lsp 插件,具有高性能UI。非常酷 use 'rinx/lspsaga.nvim' ``` #### 配置 ``` nvim ~/.config/nvim/after/plugin/lsp-colors.rc.vim if !exists('#LspColors') | finish | endif lua << EOF require("lsp-colors").setup({ Error = "#db4b4b", Warning = "#e0af68", Information = "#0db9d7", Hint = "#10B981" }) EOF ``` #### lsp-colors.nvim配置 ```shell nvim ~/.config/nvim/after/plugin/lspsaga.rc.vim if !exists('g:loaded_lspsaga') | finish | endif lua << EOF local saga = require 'lspsaga' --[[ saga.init_lsp_saga { error_sign = '', warn_sign = '', hint_sign = '', infor_sign = '', border_style = "round", } ]]-- saga.init_lsp_saga { error_sign = ' ', warn_sign = ' ', hint_sign = '', infor_sign = ' ', border_style = "round", } EOF "nnoremap Lspsaga diagnostic_jump_next nnoremap j Lspsaga diagnostic_jump_next nnoremap Lspsaga diagnostic_jump_next nnoremap K Lspsaga hover_doc nnoremap lua require('lspsaga.action').smart_scroll_with_saga(1) " scroll up hover doc nnoremap lua require('lspsaga.action').smart_scroll_with_saga(-1) "inoremap Lspsaga signature_help nnoremap k Lspsaga signature_help nnoremap gh Lspsaga lsp_finder " code action " 智能处理,使用IDEA Alt+Enter 同样按键 nnoremap lua require('lspsaga.codeaction').code_action() nnoremap ca lua require('lspsaga.codeaction').code_action() vnoremap ca :lua require('lspsaga.codeaction').range_code_action() " 重命名 感觉没有lsp自带的功能好用,因为名称要从头输入 nnoremap rn lua require('lspsaga.rename').rename() "预览定义 nnoremap gd lua require'lspsaga.provider'.preview_definition() "Jump Diagnostic and Show Diagnostics nnoremap cd lua require'lspsaga.diagnostic'.show_line_diagnostics() " 打开终端 nnoremap :Lspsaga open_floaterm " 关闭终端 tnoremap :Lspsaga close_floaterm ``` ### autopairs自动闭合 ```shell -- 显示css的颜色代码的颜色 use "ap/vim-css-color" -- 符号自动匹配,比如:输入(自动闭合) use "windwp/nvim-autopairs" -- 需要加第三方支持 brew install ripgrep ``` #### 配置 ```lua nvim ~/.config/nvim/after/plugin/autopairs.rc.lua local status, autopairs = pcall(require, "nvim-autopairs") if (not status) then return end autopairs.setup({ disable_filetype = { "TelescopePrompt" , "vim" }, }) ``` ![image-20220107005843752](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070058857.png) ### telescope文件搜索 #### 安装 ```shell -- 文件搜索 预览 等 use { "nvim-telescope/telescope.nvim", requires = { "nvim-lua/plenary.nvim", "kyazdani42/nvim-web-devicons" } } -- 加速文件搜索速度,如果安装失败需要到插件目录执行make命令手动编译 -- 用了这个插件以后,貌似更快了(感觉输入更跟手了,可能是心理作用)。但是对于我的小项目感受不是很明显 use {"nvim-telescope/telescope-fzf-native.nvim", run = "make"} ``` #### 配置 ```lua nvim ~/.config/nvim/after/plugin/telescope.lua local status, actions = pcall(require, "telescope.actions") if (not status) then return end --local actions = require('telescope.actions') -- Global remapping ------------------------------ require("telescope").setup { defaults = { mappings = { n = { ["q"] = actions.close, ["l"] = actions.file_edit } }, file_ignore_patterns = {"./node_modules"} }, extensions = { fzf = { fuzzy = true, -- false will only do exact matching override_generic_sorter = true, -- override the generic sorter override_file_sorter = true, -- override the file sorter case_mode = "smart_case" -- or "ignore_case" or "respect_case" -- the default case_mode is "smart_case" } } } -- To get fzf loaded and working with telescope, you need to call -- load_extension, somewhere after setup function: require("telescope").load_extension("fzf") --按键设置 vim.api.nvim_set_keymap("n", "ff", [[lua require('telescope.builtin').find_files()]], {}) vim.api.nvim_set_keymap("n", "fg", [[lua require('telescope.builtin').live_grep()]], {}) vim.api.nvim_set_keymap("n", "fb", [[lua require('telescope.builtin').buffers()]], {}) vim.api.nvim_set_keymap("n", "fh", [[lua require('telescope.builtin').help_tags()]], {}) vim.api.nvim_set_keymap("n", "sf", [[lua require('telescope.builtin').file_browser()]], {}) vim.api.nvim_set_keymap("n", "/", [[lua require'telescope.builtin'.current_buffer_fuzzy_find{}]], {}) ``` #### 使用方式 > 使用快捷键 ts ![image-20220107010224184](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070102281.png) ### nvim-treesitter语法高亮 #### 安装 ```lua --语法高亮 use { 'nvim-treesitter/nvim-treesitter', run = ':TSUpdate' } ``` #### 配置 ```lua nvim ~/.config/nvim/after/plugin/nvim-treesitter.lua local status, treesitter = pcall(require, "nvim-treesitter.configs") if (not status) then return end treesitter.setup { highlight = { enable = true, disable = {} }, indent = { enable = false, disable = {} }, ensure_installed = { "tsx", "toml", "fish", "php", "json", "yaml", "swift", "html", "scss" } } local parser_config = require "nvim-treesitter.parsers".get_parser_configs() parser_config.tsx.used_by = {"javascript", "typescript.tsx"} ``` #### 使用 ```python :TSInstall ``` ### rainbow彩虹括号 #### 安装 ```lua --彩虹括号 use 'luochen1990/rainbow' ``` #### 配置 ```shell nvim ~/.config/nvim/after/plugin/rainbow.rc.vim let g:rainbow_active = 1 "0 if you want to enable it later via :RainbowToggle let g:rainbow_conf = { \ 'guifgs': ['royalblue3', 'darkorange3', 'seagreen3', 'firebrick'], \ 'ctermfgs': ['lightblue', 'lightyellow', 'lightcyan', 'lightmagenta'], \ 'operators': '_,_', \ 'parentheses': ['start=/(/ end=/)/ fold', 'start=/\[/ end=/\]/ fold', 'start=/{/ end=/}/ fold'], \ 'separately': { \ '*': {}, \ 'tex': { \ 'parentheses': ['start=/(/ end=/)/', 'start=/\[/ end=/\]/'], \ }, \ 'lisp': { \ 'guifgs': ['royalblue3', 'darkorange3', 'seagreen3', 'firebrick', 'darkorchid3'], \ }, \ 'vim': { \ 'parentheses': ['start=/(/ end=/)/', 'start=/\[/ end=/\]/', 'start=/{/ end=/}/ fold', 'start=/(/ end=/)/ containedin=vimFuncBody', 'start=/\[/ end=/\]/ containedin=vimFuncBody', 'start=/{/ end=/}/ fold containedin=vimFuncBody'], \ }, \ 'html': { \ 'parentheses': ['start=/\v\<((area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)[ >])@!\z([-_:a-zA-Z0-9]+)(\s+[-_:a-zA-Z0-9]+(\=("[^"]*"|'."'".'[^'."'".']*'."'".'|[^ '."'".'"><=`]*))?)*\>/ end=## fold'], \ }, \ 'css': 0, \ } \} ``` #### 加载优先级 ```python # 因为这个插件的配置需要比较高的加载级别,所以在init.vim文件中增加下面一行: vim ~/.config/nvim/init.vim source ~/.config/nvim/after/plugin/rainbow.rc.vim ``` ![image-20220107010902615](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070109736.png) ### kommentary注释插件 #### 安装 ```python --注释插件 use "b3nj5m1n/kommentary" ``` #### 配置 ```shell nvim ~/.config/nvim/after/plugin/kommentary.lua treesitter.setup { context_commentstring = { enable = true, enable_autocmd = false, context_commentstring = { enable = true, config = { javascript = { __default = "// %s", jsx_element = "{/* %s */}", jsx_fragment = "{/* %s */}", jsx_attribute = "// %s", comment = "// %s" } } } } } ``` #### 使用方式 > gcc 快速注释一行 ![image-20220107012724165](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070127285.png) >gc + 数字(注释几行) + 方向(向上/向下注释) ![image-20220107012809728](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070128842.png) ### indent缩进线插件 #### 安装 ```python -- indent缩进线 use "lukas-reineke/indent-blankline.nvim" ``` #### 配置 ```lua nvim ~/.config/nvim/after/plugin/indent-blakline.lua -- vim.g.indent_blankline_char = '│' vim.wo.colorcolumn = "99999" vim.g.indent_blankline_char = "┊" vim.g.indent_blankline_show_first_indent_level = true vim.g.indent_blankline_filetype_exclude = { -- 'startify', "dashboard", -- 'dotooagenda', -- 'log', -- 'fugitive', -- 'gitcommit', -- 'packer', -- 'vimwiki', -- 'markdown', -- 'json', -- 'txt', -- 'vista', -- 'help', -- 'todoist', -- 'NvimTree', -- 'peekaboo', -- 'git', -- 'TelescopePrompt', -- 'undotree', -- 'flutterToolsOutline', "" -- for all buffers without a file type } vim.g.indent_blankline_buftype_exclude = {"terminal", "nofile"} vim.g.indent_blankline_show_trailing_blankline_indent = false vim.g.indent_blankline_show_current_context = true vim.g.indent_blankline_context_patterns = { "class", "function", "method", "block", "list_literal", "selector", "^if", "^table", "if_statement", "while", "for" } -- because lazy load indent-blankline so need readd this autocmd vim.cmd("autocmd CursorMoved * IndentBlanklineRefresh") ``` ![image-20220107013807587](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070138714.png) ### nvim-tre文件目录树 #### 安装 ```shell -- 文件管理树 use { 'kyazdani42/nvim-tree.lua', requires = { 'kyazdani42/nvim-web-devicons', -- optional, for file icon }, config = function() require'nvim-tree'.setup {} end } ``` #### 配置 ```shell nvim ~/.config/nvim/after/plugin/tree.lua vim.g.nvim_tree_indent_markers = 1 vim.g.nvim_tree_allow_resize = 1 vim.g.nvim_tree_icons = { default = "", symlink = "" } vim.g.nvim_tree_show_icons = { git = 0, folders = 1, files = 1 } vim.g.nvim_tree_gitignore = 0 vim.g.nvim_tree_git_gl = 0 local tree_cb = require("nvim-tree.config").nvim_tree_callback require("nvim-tree").setup { auto_close = true, update_focused_file = { update_cwd = true }, view = { mappings = { list = { {key = "l", cb = tree_cb("edit")} } } } } ``` ![image-20220107015049637](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070150765.png) #### 快捷键 | 快捷键 | 操作 | | :--------------------: | :----------------: | | 回车键/o(两者作用相同) | 打开文件/目录 | | Ctrl - ] | 切换到光标所在目录 | | a | 新建文件 | | r | 重命名文件 | | x | 剪切文件 | | c | 复制文件 | | p | 粘贴文件 | | d | 删除文件 | | H | 是否显示隐藏文件 | | Tab | 预览文件 | | Ctrk-v | 垂直拆分中打开文件 | | Ctrl-x | 水平拆分中打开文件 | ### undotree 历史修改记录 #### 安装 ``` -- 显示文件修改记录 use "mbbill/undotree" ``` #### 配置 ```shell mkdir -p ~/.config/nvim/.undodir nvim ~/.config/nvim/after/plugin/undotree.vim if has("persistent_undo") let target_path = expand('~/.config/nvim/.undodir') " create the directory and any parent directories " if the location does not exist. if !isdirectory(target_path) call mkdir(target_path, "p", 0700) endif let &undodir=target_path set undofile endif ``` #### 使用方式 > 进入需要恢复的序号中输入回车或者 u 即可恢复 ![image-20220107020708910](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070207048.png) ### vimspector代码调试 #### 安装 ```shell use "puremourning/vimspector" ``` #### 配置 ```shell vim ~/.config/nvim/after/plugin/vimspector.vim let g:vimspector_enable_mappings = 'HUMAN' function! s:read_template_into_buffer(template) " has to be a function to avoid the extra space fzf#run insers otherwise execute '0r ~/.config/nvim/sample_vimspector_json/'.a:template endfunction command! -bang -nargs=* LoadVimSpectorJsonTemplate call fzf#run({ \ 'source': 'ls -1 ~/.config/nvim/sample_vimspector_json', \ 'down': 20, \ 'sink': function('read_template_into_buffer') \ }) noremap vs :tabe .vimspector.json:LoadVimSpectorJsonTemplate sign define vimspectorBP text=🛑 texthl=Normal sign define vimspectorBPDisabled text=🚫 texthl=Normal sign define vimspectorPC text=👉 texthl=SpellBad mkdir ~/.config/nvim/sample_vimspector_json nvim ~/.config/nvim/sample_vimspector_json/python.json { "adapters": { "debugpy": { "command": [ "python", "-m", "debugpy.adapter" ], "name": "debugpy", "configuration": { "python": "python" } } }, "configurations": { "run - debugpy": { "adapter": "debugpy", "configuration": { "request": "launch", "type": "python", "cwd": "${workspaceRoot}", "program": "${file}", "stopOnEntry": true, "console": "integratedTerminal" }, "breakpoints": { "exception": { "raised": "N", "uncaught": "" } } } } } ``` #### 使用方式 > 第一步使用快捷键 空格 + vs 选择配置文件并保存 > > 每次只需要第一次进行调试需要选择保存文件之后无需再次选择了 ![image-20220107021311391](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070213536.png) > 第二步使用 F9 打断点 ![image-20220107021721902](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070217009.png) > 使用 F5启动调试 ![image-20220107021759977](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070218127.png) > F10 进行下一步调试 ![image-20220107021906931](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070219064.png) > F4 重启调试 ![image-20220107022049526](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070220659.png) ### pydocstring函数参数注释 #### 安装 ```python -- 代码函数注释插件 use "heavenshell/vim-pydocstring" # 需要第三方支持 pip3 install doq ``` #### 配置 ```python nvim ~/.config/nvim/after/plugin/pydocstring.vim let g:pydocstring_templates_path = '~/.config/nvim/doc' # 选择 doq 路径 let g:pydocstring_doq_path = "/opt/homebrew/bin/doq" mkdir -p ~/.config/nvim/doc vim ~/.config/nvim/doc/def.txt """ Description of {{ name }}: {% if params %} {%- for p in params %} param {{ p.argument }}{% if p.annotation %}({{ p.annotation }}): {% endif -%}{% if p.default %} default to {{ p.default }}{% endif -%} {% endfor %} {% endif -%} {% if return_type %} return {{ return_type }}: {% endif -%} {% if yields %} Yields: {%- for y in yields %} {{ y }}: {%- endfor %} {% endif -%} {% if exceptions %} Raises: {%- for e in exceptions %} {{ e }}: {%- endfor %} {% endif -%} """ ``` #### 使用方式 > 光标位于函数上使用快捷键 ctrl + _ ![image-20220107022901706](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070229854.png) ### SimpylFold代码折叠 #### 安装 ```python -- 代码折叠插件 use "tmhedberg/SimpylFold" use "Konfekt/FastFold" use "zhimsel/vim-stay" ``` #### 配置 ```shell vim ~/.config/nvim/vimrc.vim set foldmethod=indent set foldlevel=99 set foldenable set viewoptions=cursor,folds,slash,unix let g:fastfold_savehook = 0 let g:SimpylFold_docstring_preview=1 ``` #### 使用方式 > 使用 za 即可快速进行折叠以及展开 ![image-20220107023208045](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070232196.png) ### formatter代码格式化 #### 安装 ```shell use "mhartington/formatter.nvim" ``` #### 配置 ```lua nvim ~/.config/nvim/after/plugin/formatter.lua local status, formatter = pcall(require, "formatter") if (not status) then return end formatter.setup( { filetype = { lua = { -- luafmt function() return { exe = "luafmt", args = {"--indent-count", 2, "--stdin"}, stdin = true } end }, python = { function() return { exe = "python3 -m autopep8", args = { "--in-place --aggressive --aggressive", vim.fn.fnameescape(vim.api.nvim_buf_get_name(0)) }, stdin = false } end }, sql = { -- sqlformat -- 安装方法:pip3 install --upgrade sqlparse function() return { exe = "sqlformat", -- upper|lower args = {"-k", "lower", "-i", "lower", "-r", "-"}, stdin = true } end } } } ) --配置保存文件自动格式化代码 vim.api.nvim_exec( [[ augroup FormatAutogroup autocmd! autocmd BufWritePost *.rs,*.lua,*.py FormatWrite augroup END ]], true ) ``` #### 使用方式 > 使用快捷键 ctrl + s 即可 ### vista 函数展示 #### 安装 ```shell use "liuchengxu/vista.vim" # 安装第三方依赖 brew install universal-ctags ``` #### 配置 ```shell nvim ~/.config/nvim/after/plugin/vista.vim function! NearestMethodOrFunction() abort return get(b:, 'vista_nearest_method_or_function', '') endfunction set statusline+=%{NearestMethodOrFunction()} " By default vista.vim never run if you don't call it explicitly. " " If you want to show the nearest function in your statusline automatically, " you can add the following line to your vimrc autocmd VimEnter * call vista#RunForNearestMethodOrFunction() " How each level is indented and what to prepend. " This could make the display more compact or more spacious. " e.g., more compact: ["▸ ", ""] " Note: this option only works for the kind renderer, not the tree renderer. let g:vista_icon_indent = ["╰─▸ ", "├─▸ "] " Executive used when opening vista sidebar without specifying it. " See all the avaliable executives via `:echo g:vista#executives`. let g:vista_default_executive = 'ctags' " Set the executive for some filetypes explicitly. Use the explicit executive " instead of the default one for these filetypes when using `:Vista` without " specifying the executive. let g:vista_executive_for = { \ 'cpp': 'vim_lsp', \ 'php': 'vim_lsp', \ } " Declare the command including the executable and options used to generate ctags output " for some certain filetypes.The file path will be appened to your custom command. " For example: let g:vista_ctags_cmd = { \ 'haskell': 'hasktags -x -o - -c', \ } " To enable fzf's preview window set g:vista_fzf_preview. " The elements of g:vista_fzf_preview will be passed as arguments to fzf#vim#with_preview() " For example: let g:vista_fzf_preview = ['right:50%'] " Ensure you have installed some decent font to show these pretty symbols, then you can enable icon for the kind. let g:vista#renderer#enable_icon = 1 " The default icons can't be suitable for all the filetypes, you can extend it as you wish. let g:vista#renderer#icons = { \ "function": "\uf794", \ "variable": "\uf71b", \ } ``` ![image-20220107024208603](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070242751.png) ### jedi源码跳转 #### 安装 ```python -- 代码跳转 use "davidhalter/jedi-vim" # 安装第三方插件 pip3 install jedi ``` #### 配置 ```shell nvim ~/.config/nvim/after/plugin/jedi.vim " 代码跳转 " disable autocompletion, cause we use deoplete for completion let g:jedi#completions_enabled = 0 " open the go-to function in split, not another buffer let g:jedi#use_splits_not_buffers = "right" ``` #### 使用方式 > 使用空格+d 跳转到源码内部 ![image-20220107032357509](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070323684.png) > 空格 + r 修改函数名称 ![image-20220107032459239](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070324370.png) > K (大写)查看函数使用文档 ![image-20220107032612893](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070326017.png) ### symbols-outline展示函数变量 #### 安装 ```shell use "simrat39/symbols-outline.nvim" ``` #### **![image-20220107024605604](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070246770.png)** ### nvim-repl代码 repl #### 安装 ``` -- 代码 repl 插件 use "tpope/vim-repeat" use "pappasam/nvim-repl" ``` #### 配置 ```shell nvim ~/.config/nvim/after/plugin/nvim-repl.vim let g:repl_filetype_commands = { \ 'python': 'python3', \ } let g:repl_split = 'right' ``` #### 使用方式 > 使用快捷键 re 开启 repl ![image-20220107025053542](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070250690.png) > 使用空格 + e 发送代码进入右边区域 ![image-20220107025128233](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070251391.png) > 代码块发送先选中代码块在使用空格+ e ![image-20220107025305179](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070253332.png) ### toggleterm开启终端 #### 安装 ```shell -- 终端调用插件 use "akinsho/nvim-toggleterm.lua" ``` #### 配置 ```python nvim ~/.config/nvim/after/plugin/terminal.lua require("toggleterm").setup { -- size can be a number or function which is passed the current terminal size = 15, open_mapping = [[]], hide_numbers = true, -- hide the number column in toggleterm buffers shade_filetypes = {}, shade_terminals = true, shading_factor = "", -- the degree by which to darken to terminal colour, default: 1 for dark backgrounds, 3 for light start_in_insert = true, insert_mappings = true, -- whether or not the open mapping applies in insert mode persist_size = true, direction = "horizontal", close_on_exit = true, -- close the terminal window when the process exits shell = "/bin/zsh", -- change the default shell -- This field is only relevant if direction is set to 'float' float_opts = { -- The border key is *almost* the same as 'nvim_win_open' -- see :h nvim_win_open for details on borders however -- the 'curved' border is a custom border type -- not natively supported but implemented in this plugin. border = "single", height = 100, winblend = 3, highlights = { border = "Normal", background = "Normal" } } } function _G.set_terminal_keymaps() local opts = {noremap = true} vim.api.nvim_buf_set_keymap(0, "t", "", [[]], opts) vim.api.nvim_buf_set_keymap(0, "t", "jk", [[]], opts) vim.api.nvim_buf_set_keymap(0, "t", "", [[h]], opts) vim.api.nvim_buf_set_keymap(0, "t", "", [[j]], opts) vim.api.nvim_buf_set_keymap(0, "t", "", [[k]], opts) vim.api.nvim_buf_set_keymap(0, "t", "", [[l]], opts) end -- if you only want these mappings for toggle term use term://*toggleterm#* instead vim.cmd("autocmd! TermOpen term://* lua set_terminal_keymaps()") ``` #### 使用方式 > 使用快捷键 ctrl + t 调用终端 ![image-20220107030310782](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070303945.png) ### vim-surround符号匹配 #### 安装 ```shell -- 符号匹配 use "tpope/vim-surround" -- 快速选中 use "gcmt/wildfire.vim" ``` #### 使用方式 > 使用回车快速选中 ![image-20220107030615346](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070306514.png) > 大写 S 加上需要添加的符号 ![image-20220107030649255](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070306414.png) > cs 进行修改 光标放在需要修改的符号上使用 cs当前符号+修改符号 ![image-20220107030749323](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070307490.png) ### switch快速转换 #### 安装 ```shell use "AndrewRadev/switch.vim" ``` #### 使用方式 > 光标放在当前需要修改的变量使用 gs ![image-20220107031123532](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070311695.png) ### snippets代码片段 #### 安装 ```python -- 代码块引擎 use "SirVer/ultisnips" -- 代码块片段 use "honza/vim-snippets" ``` #### 配置 ```shell nvim ~/.config/nvim/after/plugin/ultiSnip.vim let g:UltiSnipsExpandTrigger="" let g:UltiSnipsJumpForwardTrigger="" let g:UltiSnipsJumpBackwardTrigger="" ``` #### 使用方式 > 使用快捷键ctrl + e 进行代码片段补全 ![image-20220107031412063](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070314223.png) > 使用tab跳转到需要修改的地方 即上图光标闪烁处 ![image-20220107031707685](https://gitee.com/SR-Program/blog-image/raw/master/images/202201070317848.png) ### markdown预览 ``` -- markdwon预览插件 use "suan/vim-instant-markdown" ``` ## 函数快捷键映射 ```shell nvim ~/.config/nvim/maps.vim " 执行vistar函数展示功能 nnoremap tb :Vista!! " 查看文件修改历史 nnoremap ub :UndotreeToggle " 开启终端 nnoremap :ToggleTerm " 快速查看函数变量 nnoremap so :SymbolsOutline " 开启文件搜索功能 nmap ts :Telescope " 目录树 nnoremap nt :NvimTreeToggle nnoremap nr :NvimTreeRefresh nnoremap nf :NvimTreeFindFile " 快速定位错误代码 " use and for next/prev. nnoremap hn QNext nnoremap hp QPrev " toggle the quickfix open/closed without jumping to it nnoremap q QFToggle! nnoremap l LLToggle! " repl 进行调试 " neoremae e :ReplToggle nnoremap re :ReplToggle nmap e ReplSendLine vmap e ReplSendVisual " 执行python代码 autocmd FileType python map :w:exec '!python3.9' shellescape(@%, 1) autocmd FileType python imap :w:exec '!python3.9' shellescape(@%, 1) " 代码进行注释 nmap (pydocstring) ``` ### 快捷键说明 | 快捷键 | 操作 | | :------------------: | :--------------------: | | ss | 水平分割 | | sv | 垂直分割 | | s + h/j/k/l | 多窗口进行移动 | | Alt + 上下左右方向键 | 调节窗口大小 | | Ctrl + h/j/k/l | 插入模式进行方向移动 | | L | 快速到行尾 | | H | 快速到行首 | | Ctrl + j/k | 普通模式一次性跳转五行 | | Ctrl + s | 保存 | | Ctrl + a | 全选 | | R | 加载配置 | | tab | 进入下一个标签r栏 | | Shitf+tab | 进入上一个标签栏 | | Ctrl + r | 一键执行 python 代码 | ## init 初始化配置 ```python " 配置文件导入 "{{{ " --------------------------------------------------------------------- " 基础使用习惯配置 runtime ./vimrc.vim " 插件管理 "./lua/plugins.lua lua require('plugins') " 按键映射 runtime ./maps.vim " 加载配置文件 source ~/.config/nvim/after/plugin/vimspector.vim source ~/.config/nvim/after/plugin/defx-icons.rc.vim source ~/.config/nvim/after/plugin/rainbow.rc.vim source ~/.config/nvim/after/plugin/ultiSnip.vim ``` > PS:最终配置 [参考文章](https://jdhao.github.io/2018/09/05/centos_nvim_install_use_guide/)