neovim 插件管理

起因是使用了很久vscode的插件,但是在前几天看到了一个neovim(以下简称 nvim)的视频。就看自己的vscode不是很顺眼,感觉界面不够简洁,所以尝试使用nvim。这期间尝试了别人的配置和spacevim,但是这会导致两个问题:

  1. 快捷键自己不熟悉,那么就相当于没有
  2. 插件不是自己配的,很多东西报错都不知道为什么。
    基于这些原因,就决定自己去尝试配置,同时由于nvim中文资料不是很多。特别是比较基础的,大多数只有一个操作的步骤,但是并没有原因或者为什么这样。自己通过阅读一下nvim官网,同时还有nvim用的比较多的包管理插件packer 以及拿来实操的一个插件toggletermj就是在nvim中创建内置的终端。

lua

nvim是通过lua来进行插件管理的,nvim实际运行的是Vimscript,通过提供一些api给lua,从而实现插件管理以及按键映射这些。具体可以看国内的菜鸟教程,主要明白函数就行了。

packer

这里主要讲一下packer的原理。
看一下安装语句

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

我主要是用的是mac,这里可以看到使用的是一种比较原始的方法,在start目录下放置了一个插件,这里面的插件会在nvim启动时就运行(提醒一下,nvim是从vim中来的,虽然发展这么久很多不一样了,但是很多操作是兼容的,如果nvim查不到中文的,可以试试看vim的相关内容)。

这个插件会暴露出一个packer这么一个对象,通过对packer进行设置就可以安装插件啦。

那么如何给packer传递该管理哪些插件呢?创建一个~/.config/nvim/lua/plugins.lua然后在里面写上一个返回语句

return require('packer').startup(function(use)
  -- Packer can manage itself
        use 'wbthomason/packer.nvim'
        use {"akinsho/toggleterm.nvim", tag = '*', config = function()
                require("toggleterm").setup()
        end}
end)
~

这里面就是纯粹的lua语法,解析一下,require("<模块名>")就是调用一个模块,但是这个文件并没有关联其他文件呀,怎么调用的呢。原理下面会说。

然后看一下startup:the action or process of setting something in motion,意思就是开启的意思啦。这里返回一个匿名函数,具体使用的方法就是每个 use后面都接一个插件,接的方法有两种

  1. A list of plugin specifications (strings or tables)
  2. A table specifying a single plugin. It must have a plugin location string as its first element, and may additionally have a number of optional keyword elements, shown below:

大概意思就是一个插件的集合和单独一个插件,然后里面具体设定一些东西。然后具体使用就去插件官网看他们的readme就好了,都会有引导。

lua脚本的引入

nvim还是使用~/.config/nvim/init.vim中来管理(如果没有就创建一个),引入的话就是使用vimscript来调用lua脚本。

这里就是在vim运行时引入上面的lua脚本,在整个vim中就有packer这个模块,因为已经在刚才添加在start这个文件夹下了

-- vimscript脚本
-- ~/.config/nvim/init.vim
" 设置一个leader键,相当于一个自定义的键,我这里设置的空格,可以再接其它键一起设置成新的快捷键,以免出现快捷键的冲突。
let g:mapleader = " "

" 加载上面创建的文件,因为加载的路径会包括~/.config/nvim/lua
lua require('plugins')
" 加载指定lua脚本中指定的function
" command! Scratch lua require(tools).makeScratch()
" 设置快捷键,使用lua
lua require('mapkeyboard')


" 设置快捷键,使用vimscript
" insert terminal
" set
autocmd TermEnter term://*toggleterm#*
      \ tnoremap <silent><c-t> <Cmd>exe v:count1 . "ToggleTerm"<CR>
" By applying the mappings this way you can pass a count to your
" mapping to open a specific window.
" For example: 2<C-t> will open terminal 2
nnoremap <silent><c-t> <Cmd>exe v:count1 . "ToggleTerm"<CR>
inoremap <silent><c-t> <Esc><Cmd>exe v:count1 . "ToggleTerm"<CR>

这里vimscript没办法高亮,所以md设置的lua。

看上面的代码,具体的用法就已经在上面标注出来了。下面展示一下使用lua设置快捷键的文件。

-- ~/.config/nvim/lua/boardmapping.lua
-- 具体设置的方法
function _G.set_terminal_keymaps()
  local opts = {buffer = 0}
-- t表示的是terminal,也就是在使用终端的时候设置下面的快捷键。
-- <cmd> 和: 是相同的意思,表示的就是一个命令
  vim.keymap.set('t', '<esc>', [[<C-\><C-n>]], opts)
  vim.keymap.set('t', 'jk', [[<C-\><C-n>]], opts)
  vim.keymap.set('t', '<C-h>', [[<Cmd>wincmd h<CR>]], opts)
  vim.keymap.set('t', '<C-j>', [[<Cmd>wincmd j<CR>]], opts)
  vim.keymap.set('t', '<C-k>', [[<Cmd>wincmd k<CR>]], opts)
  vim.keymap.set('t', '<C-l>', [[<Cmd>wincmd l<CR>]], opts)
end

function _G.set_terminal_keymaps_insert()
  vim.keymap.set('n', '<C-h>', [[<Cmd>wincmd h<CR>]], opts)
  vim.keymap.set('n', '<C-j>', [[<Cmd>wincmd j<CR>]], opts)
  vim.keymap.set('n', '<C-k>', [[<Cmd>wincmd k<CR>]], opts)
  vim.keymap.set('n', '<C-l>', [[<Cmd>wincmd l<CR>]], opts)
end
-- 调用设置的方法
-- vim.cmd表示的是执行后面的内容
-- autocmd是表示vim中的自动调用,代表在碰到之后的内容时加载相应的方法.感叹号表示的是避免重复加载
vim.cmd('autocmd! TermOpen term://* lua set_terminal_keymaps()')
vim.cmd('lua set_terminal_keymaps_insert()')

-- 下面表示的是自定义一个terminal运行相应的命令,这里是在内部终端运行lazygit
local Terminal  = require('toggleterm.terminal').Terminal

local lazygit = Terminal:new({
  cmd = "lazygit",
  dir = "git_dir",
  direction = "float",
  float_opts = {
    border = "double",
  },
  -- function to run on opening the terminal
  on_open = function(term)
    vim.cmd("startinsert!")
    vim.api.nvim_buf_set_keymap(term.bufnr, "n", "q", "<cmd>close<CR>", {noremap = true, silent = true})
  end,
  -- function to run on closing the terminal
  on_close = function(term)
    vim.cmd("startinsert!")
  end,
})

function _lazygit_toggle()
  lazygit:toggle()
end

vim.api.nvim_set_keymap("n", "<leader>g", "<cmd>lua _lazygit_toggle()<CR>", {noremap = true, silent = true})

实际例子

这里使用的是toggleterm 来进行举例,首先看他的官网。里面说了
Using packer in lua

-- ~/.config/nvim/lua/mapkeyboard.lua
use {"akinsho/toggleterm.nvim", tag = '*', config = function()
  require("toggleterm").setup()
end}

直接在~/.config/nvim/lua/plugins.lua中加上这句话就可以了。具体怎么加,如果不明白就去看上面的,有这个文件的全部内容。

之后往下翻会有一些介绍,和目标什么的。然后就会有一个设置快捷键,这种设置方法一看就是vimscript,图方便就直接在init.vim中设置了,如果想要简洁,应该可以单独建一个文件夹然后在init.vim中引用就可以了。

-- vimscript脚本
-- ~/.config/nvim/init.vim
" set
" 在某些情况下,自动运行下面的内容。
autocmd TermEnter term://*toggleterm#*
      \ tnoremap <silent><c-t> <Cmd>exe v:count1 . "ToggleTerm"<CR>

" By applying the mappings this way you can pass a count to your
" mapping to open a specific window.
" For example: 2<C-t> will open terminal 2
nnoremap <silent><c-t> <Cmd>exe v:count1 . "ToggleTerm"<CR>
inoremap <silent><c-t> <Esc><Cmd>exe v:count1 . "ToggleTerm"<CR>

再往下就是一些在~/.config/nvim/lua/plugins.lua中进行设定的内容

require("toggleterm").setup{
  -- size can be a number or function which is passed the current terminal
  size = 20 | function(term)
    if term.direction == "horizontal" then
      return 15
    elseif term.direction == "vertical" then
      return vim.o.columns * 0.4
    end
  end,
  open_mapping = [[<c-\>]],
  on_create = fun(t: Terminal), -- function to run when the terminal is first created
  on_open = fun(t: Terminal), -- function to run when the terminal opens
  on_close = fun(t: Terminal), -- function to run when the terminal closes
  on_stdout = fun(t: Terminal, job: number, data: string[], name: string) -- callback for processing output on stdout
  on_stderr = fun(t: Terminal, job: number, data: string[], name: string) -- callback for processing output on stderr
  on_exit = fun(t: Terminal, job: number, exit_code: number, name: string) -- function to run when terminal process exits
  hide_numbers = true, -- hide the number column in toggleterm buffers
  shade_filetypes = {},
  autochdir = false, -- when neovim changes it current directory the terminal will change it's own when next it's opened
  highlights = {
    -- highlights which map to a highlight group name and a table of it's values
    -- NOTE: this is only a subset of values, any group placed here will be set for the terminal window split
    Normal = {
      guibg = "<VALUE-HERE>",
    },
    NormalFloat = {
      link = 'Normal'
    },
    FloatBorder = {
      guifg = "<VALUE-HERE>",
      guibg = "<VALUE-HERE>",
    },
  },
  shade_terminals = true, -- NOTE: this option takes priority over highlights specified so if you specify Normal highlights you should set this to false
  shading_factor = '<number>', -- 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
  terminal_mappings = true, -- whether or not the open mapping applies in the opened terminals
  persist_size = true,
  persist_mode = true, -- if set to true (default) the previous terminal mode will be remembered
  direction = 'vertical' | 'horizontal' | 'tab' | 'float',
  close_on_exit = true, -- close the terminal window when the process exits
  shell = vim.o.shell, -- change the default shell
  auto_scroll = true, -- automatically scroll to the bottom on terminal output
  -- This field is only relevant if direction is set to 'float'
  float_opts = {
    -- The border key is *almost* the same as 'nvim_open_win'
    -- see :h nvim_open_win for details on borders however
    -- the 'curved' border is a custom border type
    -- not natively supported but implemented in this plugin.
    border = 'single' | 'double' | 'shadow' | 'curved' | ... other options supported by win open
    -- like `size`, width and height can be a number or function which is passed the current terminal
    width = <value>,
    height = <value>,
    winblend = 3,
  },
  winbar = {
    enabled = false,
    name_formatter = function(term) --  term: Terminal
      return term.name
    end
  },
}

可以自己看需要进行设置

之后往下就是提供的方法的一些介绍,主要介绍一下通过lua进行快捷键设定。
这里因为是lua脚本,上面的plugins.lua上来就直接返回了。同时为了保证降低耦合,就没有尝试继续在里面加内容。就新建了一个lua脚本文件。~/.config/nvim/lua/mapkeyboard.lua这个文件,按照它给的内容

这里vim就是暴露出的一个全局变量,通过设置vim就可以对编辑器的特性进行设置

-- ~/.config/nvim/lua/mapkeyboard.lua
function _G.set_terminal_keymaps()
  local opts = {buffer = 0}
  vim.keymap.set('t', '<esc>', [[<C-\><C-n>]], opts)
  vim.keymap.set('t', 'jk', [[<C-\><C-n>]], opts)
  vim.keymap.set('t', '<C-h>', [[<Cmd>wincmd h<CR>]], opts)
  vim.keymap.set('t', '<C-j>', [[<Cmd>wincmd j<CR>]], opts)
  vim.keymap.set('t', '<C-k>', [[<Cmd>wincmd k<CR>]], opts)
  vim.keymap.set('t', '<C-l>', [[<Cmd>wincmd l<CR>]], opts)
end

-- if you only want these mappings for toggle term use term://*toggleterm#* instead
vim.cmd('autocmd! TermOpen term://* lua set_terminal_keymaps()')

创建好后再再init.vim这个文件中加上对这个文件的引用。

lua require('mapkeyboard')

这个同样也在上面init.vim中展示了全部的设置。

这个快捷键的大致意思就是:通过control加上h,j,k,l实现在terminal(内置终端)情况下也能跳文档编辑继续进行编辑。我觉得跳回文档编辑后不能再跳回去,就不太舒服又加了几个在normal(vim的编辑模式)中能运行的快捷键,其实实际含义就是输入:wincmd k/j/h/l 进行跳转。
所以最后就是下面这个样子

-- ~/.config/nvim/lua/boardmapping.lua
-- 具体设置的方法
function _G.set_terminal_keymaps()
  local opts = {buffer = 0}
-- t表示的是terminal,也就是在使用终端的时候设置下面的快捷键。
-- <cmd> 和: 是相同的意思,表示的就是一个命令
  vim.keymap.set('t', '<esc>', [[<C-\><C-n>]], opts)
  vim.keymap.set('t', 'jk', [[<C-\><C-n>]], opts)
  vim.keymap.set('t', '<C-h>', [[<Cmd>wincmd h<CR>]], opts)
  vim.keymap.set('t', '<C-j>', [[<Cmd>wincmd j<CR>]], opts)
  vim.keymap.set('t', '<C-k>', [[<Cmd>wincmd k<CR>]], opts)
  vim.keymap.set('t', '<C-l>', [[<Cmd>wincmd l<CR>]], opts)
end

function _G.set_terminal_keymaps_insert()
  vim.keymap.set('n', '<C-h>', [[<Cmd>wincmd h<CR>]], opts)
  vim.keymap.set('n', '<C-j>', [[<Cmd>wincmd j<CR>]], opts)
  vim.keymap.set('n', '<C-k>', [[<Cmd>wincmd k<CR>]], opts)
  vim.keymap.set('n', '<C-l>', [[<Cmd>wincmd l<CR>]], opts)
end
-- 调用设置的方法
-- vim.cmd表示的是执行后面的内容
-- autocmd是表示vim中的自动调用,代表在碰到之后的内容时加载相应的方法.感叹号表示的是避免重复加载
vim.cmd('autocmd! TermOpen term://* lua set_terminal_keymaps()')
vim.cmd('lua set_terminal_keymaps_insert()')

总结

原理

主要就是串了一下nvim的插件管理。

  1. nvim使用的还是vimscript脚本,只是兼容了lua。
  2. 可以通过在 ~/.local/share/nvim/site/pack/packer/start/中安装插件直接在运行时就导入插件
  3. ~/.config/nvim/init.vim是一个vimscript脚本,里面可以设置要执行的lua脚本,和对vim/nvim进行配置等
    基于上面的原理,首先通过在start中安装packer直接导入packer这个插件进行插件管理,之后通过init.vim给packer提供需要管理插件的各种信息,从而实现插件的管理。

实际操作步骤

  1. 去对应插件官网看如何在plugins.lua中加载包,复制粘贴过来
  2. 在对应插件官网看可以设置哪些,如果是直接对插件操作一般就是在plugins.lua包中对应插件的set()中进行设置
  3. 如果是快捷键
    1. 在init.vim中直接使用vimscript脚本进行设置
    2. 通过lua进行设置,然后在init.vim中导入lua脚本

问题

  1. 对于packer具体实现和vimscript的了解还是不深入,后面随着具体的使用再慢慢学习。
posted @   yych0745  阅读(1184)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示