Masimaro's blog - NeoVim
type: channel
link: https://www.masimaro.top/tag/NeoVim/
items: nvim番外之将配置的插件管理器更新为lazy
items: 从零开始配置vim(32)——最后再说两句
items: 从零开始配置vim(31)——git 配置
items: 从零开始配置vim(30)——DAP的其他配置
items: 从零开始配置vim(29)——DAP 配置
items: 从零开始配置vim(28)——代码的编译、运行与调试
items: 从零开始配置vim(27)——代码片段
items: 从零开始配置vim(26)——LSP UI 美化
items: 从零开始配置vim(25)——关于 c++ python 的配置
items: 从零开始配置vim(24)——自动补全

nvim番外之将配置的插件管理器更新为lazy
type: item
date: 2025-01-06T11:06:00+08:00
description: 在很久以前我写过关于nvim配置的文章，里面推荐使用 packer作为插件管理器。但是在一年多以前，packer的仓库中出现这么一段文字This repository is currently unmaintained. For the time being (as of August, 2023), it is recommended to use one of the following plugin managers instead:lazy.nvim: Most stable and maintained plugin manager for Nvim.pckr.nvim: Spiritual successor of packer.nvim. Functional but not as stable as lazy.nvim.而且nvim相关的开源社区已经出现了 lazyVim 这样的配置。之前曾今考虑过更换自己的配置，但是秉持着代码能跑就不动的传统，一直没有动手。但是这个周末我游戏也不太想玩，学习elisp的动力也没那么足，那就决定来捣鼓一下之前使用的配置把。升级到lazy总的来说升级过程并不复杂，我之前的配置没有什么很深度的定制，基本都是在使用插件的基础功能。根据官方的文档，在升级的时候需要更改的代码在 plugins.lua 这个文件中。这个文件专门记录了我们安装了哪些插件。这个文件中主要做了以下几个修改在安装之前首先要安装 luarocks。在arch下，使用sudo pacman -S luarocks然后在plugins.lua 中添加安装 lazy 的代码-- 自动安装 lazy 插件管理器 local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" if not vim.loop.fs_stat(lazypath) then vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", "--branch=stable", lazypath, }) end vim.opt.rtp:prepend(lazypath)上述代码就是在检测在对应目录下是否存在 lazy.nvim ，没有则通过 git 进行安装。安装完成之后使用 vim.opt.rtp:prepend 来将lazy的路径添加到nvim的运行路径的最前面，保证在查找插件时有限在这个路径中查找。接着修改下面安装插件的代码，主要的修改就是去除 use ，并且将 require 修改为 dependencies 。具体修改的内容可以看这个 commit。这些工作都做完之后，重新打开nvim，可以发现 lazy 已经安装成功，并且它已经在为我们下载安装插件了插件安装成功之后，使用 check_health lazy 来检查插件是否有问题，第一次检查会得到几个错误因为现在 packer 和 lazy 安装的插件都存在，我们要根据提示删除 packer 的相关信息。删除完了之后，再次检查，发现已经不存在上面的错误了本篇就到这里了，后续每个插件是否都能正常工作我还没有测试，如果后续我发现错误，会在错误解决过后更新此文。如果有读者愿意使用我的配置，在使用过程中有错误请联系我，谢谢！

从零开始配置vim(32)——最后再说两句
type: item
date: 2023-03-04T09:50:00+08:00
description: 很抱歉我决定结束这个系列的内容了。原本我打算介绍markdown、orgmode相关的配置，甚至还打算介绍如何在vim 中使用 emacs 的 org-agenda 来进行日常的任务管理。但是出于一些原因我打算放弃了。首先如果将markdown 理解为另一种类似于HTML 的标记语言的话，我们在介绍LSP 的时候已经介绍过该如何新增新的编程语言的支持，再另外介绍Markdown 的配置就显得多余了。而且本系列也并不打算事无巨细的带领大家从零开始配置一套完整的配置，我仅仅希望通过这一系列的内容介绍一下vimscript 或者lua 接口以及vim 的一些特性，让大家看完之后又能力自行动手弄出一套属于自己的配置。至于orgmode 的内容，我发现目前还没有任何插件能完美的模拟emacs 的orgmode 功能。vim 上的插件也仅仅能做到渲染样式，语法高亮而已。也就没有必要单独介绍了。如果后续我能掌握 emacs 的话，再来介绍也不迟总之就是本系列到此结束了。一些建议不知道各位小伙伴在跟着我这一系列文章尝试自己配置vim 的时候有什么感觉？我当初在整理这些配置的时候发现它越来越像vs code ，甚至最近几年新推出的LSP以及 DAP 的一些插件几乎都是原生的用于 vscode 上的或者从它上面移植过来的。有些主题也是照搬 vscode 的。我们发现自己费劲心力终于将vim 变成的 vscode 。有没有觉得在做无用功？既然要将它变成 vscode 那为何不直接使用 vscode 呢？可能有人会说， vscode 对于vim的一些模式和 ex 命令的支持并不好。我想这就是我们使用 vim 的理由，也是vim 比其他编辑器强的地方。我们仅仅是在使用工具而已，哪个工具好用，哪个工具能帮助我们快速完成工作，那就用哪个。工具本身没有高低贵贱之分，只有合适与否的差异。作为程序员要拥抱新技术，千万不要抱着某个技术某个工具不放。也不要觉得用vim 的比用 vscode 或者其他编辑器的高级，就高人一等。vim自身也在吸收其他技术不断的成长，例如它从 vscode 那边学来了LSP 和 DAP 。这就有点像武侠小说中的吸功大法，集万物所长为我所用。另外一条建议就是千万不要拿我给出的配置直接来进行使用。这一套配置仅仅是为了教学使用，很多地方没有进行深度定制，并且基本采用白话的写法，完全不考虑封装性和程序设计，另外我也没有考虑通用性，很多小伙伴评论出现了各种各样的问题，最后就是它的效率也不算高。我也不希望自己的文章仅仅给各位小伙伴提供了一套配置。我更希望小伙伴们能通过这一系列文章学到一点东西，从这套配置中衍生出一套适合自己的内容。若干年以后，各位小伙伴在对vim有更深的理解回过头来看到这套配置时可能发出这样的声音：“这是什么破烂配置，连 xxx 的支持都没有；有些功能有时候会报错，我看看把它改好；启动时间咋这么慢，我能把它优化到xx毫秒；现在还在用xx技术早就落伍了，看我把它改成用xx技术”。（我自认为本系列最有价值的是开始配置之前，vim相关特性的介绍）最后的一条建议就是，如果各位小伙伴未来将长时间使用vim 进行代码的编写和日常的开发。那么我推荐使用一些社区比较活跃的第三方通用配置，例如我最近在使用的lunarVim。使用这类的配置有一些好处：不用费力折腾配置，节约时间学习高手的配置，提升自己对编辑器的审美。就像没学习vim之前我一直觉得使用编辑器用鼠标选中文本是天经地义的事，我习惯了它，甚至习惯了用鼠标翻页等操作，完全不知道这样有多么的浪费时间。通过高手配置可能能使你重新审视自己使用编辑器的习惯，从而找到一套真正适合自己的高效的文本操作术。社区活跃的话，除了问题不用自己死磕，可能有人能帮忙解决PS: 如果各位觉得我的教程不好或者有些内容没有提到，各位可以去看看lunarVim作者的另一个项目，Neovim-from-scratch 该项目也是从0开始配置vim，并且在油管上有对应的教学视频。后面的学习通过本系列的学习相信各位小伙伴已经有能力能看懂各种第三方配置的代码，能在此基础之上衍生出一套属于自己的配置。甚至能完全抛弃第三方配置独立弄出一套自己的配置。所以后面我推荐的学习路线就是：不断阅读vim官方手册熟练使用某一个第三方配置在熟练的基础之上根据自己的习惯来定制一些只属于自己的功能形成一套只属于自己的科学的、高效的文本操作习惯根据这套习惯尝试定制自己的配置在其他编辑器中通过一定的配置尝试复刻这一套科学而又高效的操作习惯目前我正在第三部分努力。希望本系列文章能带领大家真正入门vim ，不会再出现因为觉得难而中途放弃。最后祝愿各位小伙伴在vim的使用中能收获快乐，并坚持下去！

从零开始配置vim(31)——git 配置
type: item
date: 2023-02-01T12:14:00+08:00
description: 很抱歉又拖更了这么久了，在这个新公司我想快速度过试用期，所以大部分的精力主要花在日常工作上面。但是这个系列还是得更新下去，平时只能抽有限的业余时间来准备。这就导致我写这些文章就慢了一些。废话不多说，咱们正式开始有关git相关的配置。这些配置都是根据我自身使用习惯来定义的，不一定符合各位的习惯，各位可以根据自身的习惯来调整gitsigns第一个要推荐的插件是 gitsigns。就像它的名字一样，该插件可以将最近的更改以标签的形式展现出来方便我们查看。我们可以使用这样的代码进行安装 use {'lewis6991/gitsigns.nvim' }。需要注意最新的版本需要 neovim 的版本在0.7 以上。安装完成之后我们通过配置 require('gitsigns').setup()来使用它。这样我们就可以通过 Gitsigns toggle_signs来打开或者关闭符号显示了。除了采用最基本的符号显示以外，它还可以对改变位置的行号进行标记以及高亮显示变更的行。这两个功能可以通过 Gitsigns toggle_numl和 Gitsigns toggle_linel来打开，打开之后显示如下：从图中可以看到，更改行行号被用绿色显示了出来并且更改行进行了高亮显示另外它还有其他的显示效果：它主要的一些显示功能主要有下面几个：toggle_signs: 显示变更记录toggle_numl: 显示变更行号toggle_linel：高亮变更的行toggle_delete: 显示被删除的行，以红色背景高亮显示toggle_word_diff: 在两行分别显示修改前和修改后的内容toggle_current_line_blame: 在对应行后面显示提交记录我们将所有的这些功能都打开将得到这么一个效果是不是看着有点乱？这是我修改了一处的，一旦修改多了看着会更混乱。所以我自己的经验告诉我在这个buffer里面最好是只打开 signs、numl、linel、current_line_blame的功能，其他的都关掉。也就是在当前buffer中只显示现在的代码，然后辅助以简单的符号来显示哪行是新加的，哪行被删除了，哪行被修改了，至于修改前是什么样子的，我可以通过其他方式来查阅。所有内容都在一个buffer 中显示会比较乱，不利于阅读代码。我们可以通过配置将我们要显示的内容进行定义，也可以定义使用何种图标来表示修改记录。我们采用如下的配置gitsigns.setup({ signs = { add = {hl = 'GitSignsAdd' , text = '+', numhl='GitSignsAddNr' , linehl='GitSignsAddLn'}, change = {hl = 'GitSignsChange', text = '│', numhl='GitSignsChangeNr', linehl='GitSignsChangeLn'}, delete = {hl = 'GitSignsDelete', text = '-', numhl='GitSignsDeleteNr', linehl='GitSignsDeleteLn'}, topdelete = {hl = 'GitSignsDelete', text = '-', numhl='GitSignsDeleteNr', linehl='GitSignsDeleteLn'}, untracked = {hl = 'GitSignsAdd', text = '+', numhl='GitSignsAddNr' , linehl='GitSignsAddLn'}, changedelete = {hl = 'GitSignsChange', text = '~', numhl='GitSignsChangeNr', linehl='GitSignsChangeLn'}, }, signcolumn = true, -- Toggle with `:Gitsigns toggle_signs` numhl = true, -- Toggle with `:Gitsigns toggle_numhl` linehl = true, -- Toggle with `:Gitsigns toggle_linehl` word_diff = false, -- Toggle with `:Gitsigns toggle_word_diff` watch_gitdir = { interval = 1000, follow_files = true }, attach_to_untracked = true, current_line_blame = false, -- Toggle with …

从零开始配置vim(30)——DAP的其他配置
type: item
date: 2022-12-30T16:57:00+08:00
description: 很抱歉这么久才来更新这一系列，主要是来新公司还在试用期，我希望在试用期干出点事来，所以摸鱼的时间就少了。加上前面自己阳了休息了一段时间。在想起来更新就过去一个多月了。废话不多说了，让我们开始进入正题。在前一章，我们谈论了如何在 neovim 中使用cpptools 这个DAP 的适配器对代码进行调试，目前针对编译型和解释型语言来说我们都有了对应的方法来配置调试器对其进行调试。本节将要介绍关于dap的其他一些功能，主要包括 repl窗口和 gdb的集成repl 窗口什么是 repl 呢？它的全称是 Read Eval Print Loop 中文一般翻译为交互式解析器，可能看到这你还是一脸懵逼，你可以想想 python 或者nodejs，在控制台输入python 就可以进入到它的交互式解析器中，随着我们输入python 的语句，它会实时的给出运行的结果。交互式解析器就是这么一个东西，输入命令，它给你一个实时的结果。在调试中使用交互式解析器还是很有用的，比如我想显示当前某个变量的值，当前执行到哪个语句了等等。nvim-dap已经提供了一个内置的 repl 窗口，我们每次启动调试的时候都会看到它每次都会创建一个新的名为 dap-repl的buffer。之前我们没怎么关注它主要还是因为那个时候的重点在于如何进行调试，现在我们将要来优化这部分的显示和功能。首先我们发现每次调试结束的时候这个buffer 都会被遗留，需要我们手动的进行关闭，除了针对buffer通用的 :q 或者 :bd命令进行关闭，还可以使用 :lua require('dap').repl.close()。当然也可以配套使用 :lua require('dap').repl.open()来打开一个 repl的窗口，既然每次都会自动新建，那么这里我们就不需要进行新建，主要用于想办法关闭就可以了。还记得之前介绍 nvim-dapui 插件的时候介绍的那两个监听函数吗，同样的我们要在监听调试结束的函数中添加代码来关闭repl 窗口，函数的整个代码如下dap.listeners.before.event_terminated["dapui_config"] = function() dapui.close({}) dap.repl.close() end dap.listeners.before.event_exited["dapui_config"] = function() dapui.close({}) dap.repl.close() end再启动调试的时候发现它已经可以在调试结束的时候自动关闭了。还有另外一个问题就是我不太喜欢现在这样在最下角显示 repl。我希望它能够在最下方以整行的形式显示。或者可以方便的不显示，只有在需要的时候显示。要达成这个目的我们需要修改 dapui 的配置。dapui 的配置主要以 element为基础，每个 element 代表一个提供对应功能的窗口。我们先来根据它默认的配置来讲解每部分的含义require("dapui").setup({ icons = { expanded = "", collapsed = "", current_frame = "" }, mappings = { -- Use a table to apply multiple mappings expand = { "<CR>", "<2-LeftMouse>" }, open = "o", remove = "d", edit = "e", repl = "r", toggle = "t", }, -- Use this to override mappings for specific elements element_mappings = { -- Example: -- stacks = { -- open = "<CR>", -- expand = "o", -- } }, -- Expand lines larger than the window -- Requires >= 0.7 expand_lines = vim.fn.has("nvim-0.7") == 1, -- Layouts define sections of the screen to place windows. -- The position can be "left", "right", "top" or "bottom". -- The size specifies the height/width depending on position. It can be an Int -- or a Float. Integer specifies height/wid…

从零开始配置vim(29)——DAP 配置
type: item
date: 2022-11-18T14:17:00+08:00
description: 首先给大家说一声抱歉，前段时间一直在忙换工作的事，包括但不限于交接、背面试题准备面试。好在最终找到了工作，也顺利入职了。期间也有朋友在催更，在这里我对关注本系列的朋友表示感谢。多的就不说了，我们正式进入vim 的配置吧上一节通过配置 python 的调试环境，我们大概了解了配置 dap 的基本步骤。首先需要一个 dap 的客户端负责在编辑器上显示各种调试信息，并且与用户进行交互。然后需要一个服务端，与客户端通信并完成调试的实际步骤。然后需要配置两个东西， dap.adapters 用来配置如何启动调试器，dap.configurations用来配置如何将当前项目加载到调试器上。本篇我们进一步配置 dap。让它变得更好用，并且介绍编译型语言(C/C++)调试的配置。优化界面回顾一下上一篇中在演示图片里面看到的效果。默认界面在断点位置以 B 来标识，当前运行的代码以 -> 来标识。看起来不那么的直观，我们先对它进行优化，我们采用 Visual Code 的调试图标来进行标识我们采用以下代码进行配置local dap_breakpoint_color = { breakpoint = { ctermbg=0, fg='#993939', bg='#31353f', }, logpoing = { ctermbg=0, fg='#61afef', bg='#31353f', }, stopped = { ctermbg=0, fg='#98c379', bg='#31353f' }, } vim.api.nvim_set_hl(0, 'DapBreakpoint', dap_breakpoint_color.breakpoint) vim.api.nvim_set_hl(0, 'DapLogPoint', dap_breakpoint_color.logpoing) vim.api.nvim_set_hl(0, 'DapStopped', dap_breakpoint_color.stopped) local dap_breakpoint = { error = { text = "", texthl = "DapBreakpoint", linehl = "DapBreakpoint", numhl = "DapBreakpoint", }, condition = { text = 'ﳁ', texthl = 'DapBreakpoint', linehl = 'DapBreakpoint', numhl = 'DapBreakpoint', }, rejected = { text = "", texthl = "DapBreakpint", linehl = "DapBreakpoint", numhl = "DapBreakpoint", }, logpoint = { text = '', texthl = 'DapLogPoint', linehl = 'DapLogPoint', numhl = 'DapLogPoint', }, stopped = { text = '', texthl = 'DapStopped', linehl = 'DapStopped', numhl = 'DapStopped', }, } vim.fn.sign_define('DapBreakpoint', dap_breakpoint.error) vim.fn.sign_define('DapBreakpointCondition', dap_breakpoint.condition) vim.fn.sign_define('DapBreakpointRejected', dap_breakpoint.rejected) vim.fn.sign_define('DapLogPoint', dap_breakpoint.logpoint) vim.fn.sign_define('DapStopped', dap_breakpoint.stopped)上面的代码主要配置了显示的颜色和图标。最终调试的效果如下图所示然后我们需要提供一个可用的界面用来显示调试过程中的各种信息，包括变量值和调用栈。完成这个工作的是插件 nvim-dap-ui 。我们使用如下的代码进行安装use { "rcarriga/nvim-dap-ui", requires = {"mfussenegger/nvim-dap"} }这个插件里面包装了很多调试相关的窗口，例如变量监控、调用栈等等。我们可以对他进行配置，让这些窗口元素出现在我们希望它出现的位置。为了加载这个插件我们还是按照之前的惯例，为它准备一个单独的配置文件，并且加载它。local dapui = …

从零开始配置vim(28)——代码的编译、运行与调试
type: item
date: 2022-10-24T11:17:00+08:00
description: 在前面几个章节，我们逐渐为 Vim 配置了语法高亮、代码的跳转和自动补全功能。现在的 Vim 已经可以作为代码编辑器来使用了。但是想将它作为日常发开的主力编辑器来用还需要很长一段路要走，其中一个就是要为它配置代码的一键编译与运行功能。这里我们仍然以 C 和 Python 为例。一个是需要编译运行的一个是直接就可以运行的，这两个语言应该能代表大多数语言的情况。自动运行C 语言的配置在之前 vim 入门的一系列教程中我们介绍过 vim 自带 make 命令的运行机制以及如何进行自定义。对于其他语言要实现这个自动编译运行的效果我们核心的操作就是在修改 make 命令。而 C/C++ 本身采用 make 命令来进行编译和运行，所以这里 C/C++ 我们直接采用 vim 自带的 :make 命令在之前 vim 入门的一系列教程中我们介绍过 vim 自带 make 命令的运行机制以及如何进行自定义。对于其他语言要实现这个自动编译运行的效果我们核心的操作就是在修改 make 命令。而 C/C++ 本身采用 make 命令来进行编译和运行，所以这里 C/C++ 我们直接采用 vim 自带的 :make 命令我们先创建一个 C 的工程。让后使用上一节的生成 hello world 的代码片段生成一个基本的程序。然后提供一个供 :make 命令使用的 Makefile 文件main.out: main.o gcc main.o -o main.out main.o: main.c gcc -c main.c clean: rm -rf *.o *.out run: ./main.out然后我们执行 make 用来编译。如果出错了，可以使用 quickfix 相关命令跳转到对应位置。我们一般的流程是 :make 进行编译，然后使用 :make run 来进行运行。把命令搞清楚了，下面就考虑如何加快这个流程，做到一键编译运行。我们的思路还是绑定快捷键。每种语言虽然定义相同的快捷键但是运行的命令不同，我们需要根据不同的语言类型绑定对应的命令。这个时候最好的办法就是在 filetype 的机制上完成绑定的操作。我们在 lua/lsp/cpp.lua 中绑定快捷键。local on_attach = function(client, bufnr) lsp_set_keymap.set_keymap(bufnr) -- 编译 vim.api.nvim_buf_set_keymap(bufnr, "n", "<F7>", "<cmd>make<CR>", {silent = true, noremap = true}) -- 编译运行 vim.api.nvim_buf_set_keymap(bufnr, "n", "<F5>", "<cmd>make run<CR>", {silent = true, noremap = true}) end到此我们关于 C/C++ 的配置就完成了。可能显的有些简单但是已经初步可用了，小伙伴可以根据自己的需求来进一步修改这个配置。使用这个配置的前提是 C/C++ 的工程中有已经定义好的 Makefile 文件Python的配置之前我们在讲解命令的模式的提到过可以使用 % 来代表当前 buffer 所对应的文件。所以 python 的配置就比较简单了。因为 Python 不需要编译，所以这里直接绑定 <F5> 来运行vim.api.nvim_buf_set_keymap(bufnr, "n", "<F5>", "<cmd>!python %<CR>", {silent = true, noremap = true})dap 配置我们经常看到有人配置 neovim 或者 vim 的时候会介绍到 dap ，那么什么是 dap 呢? dap 的全称是 Debug Adapter Protocol 从名称上看它又是一个协议。它为多种调试器提供了一层统一的适配抽象层。有点类似于前面的介绍的 lsp。只要在适配层提供接口的实现，那么在客户端，也就是代码编辑器这端可以不做任何修改的集成不同调试联想到 lsp 的配置，我们配置dap 首先需要的是有一个 dap 的客户端，用来向调试器发送各种命令，例如下断点、显示变量名等等。另外想要能够调试也需要有具体的调试器，用来接收处理这些命令。现在思路有了，我们 这里先以 Python 为例来介绍 dap 的基本配置。首先是需要一个客户端，用于通过 neovim下发各种调试命令并实时显示调试信息。截止到 0.7 版本 NeoVim 并没有在内部集成 dap 客户端的功能，需要我们单独安装相关插件来实现这部分的功能。这里我们使用的客户端是 nvim-dap 插件。我们先使用 use {'mfussenegg…

从零开始配置vim(27)——代码片段
type: item
date: 2022-10-18T10:42:00+08:00
description: 我们之前介绍过缩写相关的内容，缩写是可以自动帮我们将缩写的单词展开成一段完整的话。但是代码本身是结构话的，仅仅使用缩写来配置是无法完成自动生成代码这个步骤的。好在我们大量的插件来进行配置。本篇我们将要来讨论如何使用相关插件来完成代码片段自动完成的功能vsnip 插件我们之前在配置自动补全的时候已经下载了 vim-vsnip这个插件。vsnip是一个非常强大的插件，它支持我们使用与 VS Code 类似的方式来扩展定义我们自己的代码片段，同时它也内置了不同语言版本的代码片段。在之前的配置中我们还加了另外一个 friendly-snippets 。它提供了丰富的已定义好的可以直接使用的代码片段，加快了我们的编码效率。在前面介绍补全的时候我们已经安装并配置了它们。它们的效果如下图所示:自定义代码片段虽说这些插件预定义了大量的代码片段。但是他们都是通用型的代码片段，总有那么些时候无法满足我们的需求。一个明显的例子就是不同的公司有不同的代码和注释的风格。这个时候就需要我们自定义了。本篇也准备将重点放在如何自定义代码片段上。如果小伙伴们已经有了在 vscode 上自定义代码片段的经历，那么请跳过本篇以节省各位的时间。入门下面我们以 C 为例来说明如何自定义代码片段来满足我们的需求。其他语言只是填入的内容不同，在定义上并没有什么大的差别。这里我采用 C 语言一个原因是静态类型的语言更方便的演示其中的各项功能，另一个原因就是我对C/C++ 比较熟悉首先我们要找到代码片段的配置文件所在位置，这个位置保存在变量 g:vsnip_snippet_dir 中。我们可以通过 :echo g:vsnip_snippets_dir 找到它。当然也有更简单的办法，我们可以执行 :VsnipOpen 来打开该语言对应的配置文件，如果该文件不存在，命令将创建一个以对应语言名称命名的 json 文件，例如这里它会创建一个 c.json 的文件这里我们先来写一个最简单的代码片段——自动生成一个 Hello World 的 C 程序"example": { "prefix": ["hello"], "body": [ "#include <stdio.h>", "int main(int argc, char* argv[])", "{", "\tprintf(\"hello world\");", "\treturn 0;", "}" ], "description": "create a hello world" }我们来试试效果，输入 hello 将自动生成一段代码现在我们来看看这些字段都代表什么含义example：它代表该代码段的名称，也可以认为它是一个id，用于标识一个代码片段prefix：用于触发该代码片段，这里也就是我们输入 hello将会触发补全，当选择对应项的时候会调用该代码片段进行补全body：补全时自动生成的代码。它可以是一个字符串或者字符数组。虽然它本身也支持 \r\n来进行换行。但是我更倾向于使用字符数组的形式，每一行是数组中的一个字符串。description ：描述信息使用占位符如果我们仅仅只能生成像上述 hello world 那样给写死的代码的话，那么它也没什么太大的用处。有时候我们的代码需要生成一个模板，关键地方应该由我们自己进行填充。这个时候可以用到占位符，例如我们使用下面的来生成一个函数"ifunc": { "prefix": ["ifunc"], "body": [ "int $1()", "{", "\treturn 0;", "}" ], "description": "create a function return int" } }占位符内容可选我们现在已经可以生成函数了，但是有一个问题摆在我们的面前。函数的返回类型多种多样，如果我们每一个类型都定义一个片段，例如 返回 int 的定义一个 ifunc，返回 float 的定义一个 ffunc。显得多此一举了，代码的重复度太高了。这个时候我们我们给占位符一些预选项以供我们选择。它的语法格式如下${1|sel1, sel2, sel3,...|}前面的1代表是第一个占位符。如果是后面的占位符需要提供选项，那么就可以依次类推例如我们将上述生成函数的代码片段改为"func": { "prefix": ["func"], "body": [ "${1|int,float,double,char,short,*|} $2()", "{", "\treturn $3;", "}" ], "description": "create a function" } }占位符间跳转生成函数的代码片段中有3个占位符，其中第一个是可以选的，第二个第三个需要我们手动填写。按照习惯，我们一般使用 …

从零开始配置vim(26)——LSP UI 美化
type: item
date: 2022-10-14T10:52:00+08:00
description: 之前我们通过几个实例演示如何配置其他语言的lsp服务，相信各位小伙伴碰到其他的编程语言也能熟练的配置它对应的lsp服务。本篇讲作为一个补充，我们来优化一下LSP 相关的显示配置 UI原始的 lsp 显示有点素，我们使用插件对它进行一些美化，这里使用插件 lspsaga.nvim 。使用如下的代码进行安装use{"glepnir/lspsaga.nvim"}然后我们新建一个 plugin-config/lspsaga.lua 对它进行配置local saga = require('lspsaga') saga.init_lsp_saga()该插件对 NeoVim 原生 LSP 显示做了一些更改，并提供了一些方便的命令来实现LSP 相关的功能。我们将它对应的功能绑定到快捷键上替换原有的 LSP 对应的快捷键lsp_keybinds.set_keymap = function (bufnr) print("set lsp keymap") -- 跳转到声明 vim.api.nvim_buf_set_keymap(bufnr, "n", "gd", "<cmd>Lspsaga peek_definition<CR>", {silent = true, noremap = true}) -- 跳转到定义 vim.api.nvim_buf_set_keymap(bufnr, "n", "gD", "<cmd>lua vim.lsp.buf.definition()<CR>", {silent = true, noremap = true}) -- 显示注释文档 vim.api.nvim_buf_set_keymap(bufnr, "n", "gh", "<cmd>Lspsaga lsp_finder<CR>", {silent = true, noremap = true}) -- 跳转到实现 vim.api.nvim_buf_set_keymap(bufnr, "n", "gi", "<cmd>lua vim.lsp.buf.implementation()<CR>", {silent = true, noremap = true}) -- 跳转到引用位置 vim.api.nvim_buf_set_keymap(bufnr, "n", "gr", "<cmd>Lspsaga rename<CR>", {silent = true, noremap = true}) -- 以浮窗形式显示错误 vim.api.nvim_buf_set_keymap(bufnr, "n", "go", "<cmd>lua vim.diagnostic.open_float()<CR>", {silent = true, noremap = true}) vim.api.nvim_buf_set_keymap(bufnr, "n", "gp", "<cmd>lua vim.diagnostic.goto_prev()<CR>", {silent = true, noremap = true}) vim.api.nvim_buf_set_keymap(bufnr, "n", "gn", "<cmd>lua vim.diagnostic.goto_next()<CR>", {silent = true, noremap = true}) vim.api.nvim_buf_set_keymap(bufnr, "n", "<leader>cd", "<cmd>Lspsaga show_cursor_diagnostics<CR>", {silent = true, noremap = true}) vim.api.nvim_buf_set_keymap(bufnr, "n", "<leader>cd", "<cmd>Lspsaga show_line_diagnostics<CR>", {silent = true, noremap = true}) vim.api.nvim_buf_set_keymap(bufnr, "n", "<leader>ca", "<cmd>Lspsaga code_action<CR>", {silent = true, noremap = true}) vim.api.nvim_buf_set_keymap(bufnr, "v", "<leader>ca", "<cmd>Lspsaga code_action<CR>", {silent = true, noremap = true}) end我们可以对比一下原生的 lsp 界面和 lspsaga 界面，我这里使用 gh 这个命令进行对比我们可以看到它能显示更丰富的信息，而且我们可以根据…

从零开始配置vim(25)——关于 c++ python 的配置
type: item
date: 2022-10-09T12:52:00+08:00
description: 从9月份到国庆这段时间，因为得了女儿，于是回老家帮忙料理家事以及陪伴老婆和女儿。一时之间无暇顾及该系列教程的更新。等我回来的时候发现很多小伙伴私信我催更。在这里向支持本人这一拙劣教程的各位小伙伴表示真诚的感谢。言归正传，让我们开始吧之前我们根据lua语言配置了基于lsp的代码高亮、自动跳转、自动补全等等功能，那个时候我们安装了很多插件，像 nvim-lspconfig、nvim-lsp-installernvim-cmp等等，每个插件都在干嘛，虽然我们配置好了 lua相关的内容，但是可能仍然有小伙伴有疑问，碰到其他语言该如何配置，是不是要重新下载对应的插件呢？为了解答这些问题，这篇文章我们将要来根据 c++和 python的日常习惯来进行配置，给大家演示一下在上述内容都配置完成之后面对其他语言我们该如何进行处理安装配置 c++ 相关的lsp服务关于c++ 的服务，我们根据 nvim-lsp-installer 官方给出的表格中显示它可以使用 ccls 和 clang，这里我们以 ccls 作为示例进行讲解。首先通过命令安装 :LspInstall ccls接着我们新建一个 ftplugin/c.lua 和 ftplugin/cpp.lua 来配置 c/c++ 。不过他们两个采用相同的配置，我们暂时将一份配置复制两遍require("lsp/cpp")他们的作用只有一个，那就是加载 lsp/cpp 这个文件，我们将他们的配置放到一个文件中然后我们再在 lua/lsp/cpp.lua 文件中加入以下内容用于启动 lsp服务端local lspconfig = require('lspconfig') lspconfig.ccls.setup { init_options = { cache = { directory = ".ccls-cache"; }; } }我们进入一个 .c/.cpp 文件发现已经加载了 ccls 了。如果没有加载可以使用 :LspStart 命令手工加载或者使用 LspInfo 查看是否有问题现在我们已经可以看到lsp服务给出的提示了修改之前的配置我们在第22篇文章中给出了基于 lsp 的 lua 的配置，主要是使用 lsp 服务端的配置和对应的跳转之类的快捷键配置，我们将它放到了 lsp/lua.lua 目录下了。但是一想想我们使用 c++、Python 或者其他什么语言的时候，这些快捷键应该是不会修改的，这个时候自然就想到了要重用快捷键了。所以来配置之前的第一件事就是想办法重用这些快捷键。这个时候我们想到的办法就是将之前定义的快捷键封装成函数，然后在 on_attach 的回调函数中调用该函数。我们将那些快捷键定义放到 lua/keybindings.lua 中local lsp_keybinds = {} lsp_keybinds.set_keymap = function (bufnr) -- 跳转到声明 vim.api.nvim_buf_set_keymap(bufnr, "n", "gd", "<cmd>lua vim.lsp.buf.declaration()<CR>", {silent = true, noremap = true}) -- 跳转到定义 vim.api.nvim_buf_set_keymap(bufnr, "n", "gD", "<cmd>lua vim.lsp.buf.definition()<CR>", {silent = true, noremap = true}) -- 显示注释文档 vim.api.nvim_buf_set_keymap(bufnr, "n", "gh", "<cmd>lua vim.lsp.buf.hover()<CR>", {silent = true, noremap = true}) -- 跳转到实现 vim.api.nvim_buf_set_keymap(bufnr, "n", "gi", "<cmd>lua vim.lsp.buf.implementation()<CR>", {silent = true, noremap = true}) -- 跳转到引用位置 vim.api.nvim_buf_set_keymap(bufnr, "n", "gr", "<cmd>lua vim.lsp.buf.references()<CR>", {silent = true, noremap = true}) -- 以浮窗形式显示错误 vim.api.nvim_buf_set_keymap(bufnr, "n", "go", "<cmd>lua vim.diagnostic.open_float()<CR>", {silent = true, no…

从零开始配置vim(24)——自动补全
type: item
date: 2022-09-08T12:52:00+08:00
description: neovim 自带的代码补全的效果并不好，而且它分为好多类，如果需要人为的去判断使用路径补全、使用当前buffer中的单词补全、亦或者使用include 来进行补全，那样使用起来就很不方便了。针对代码的补全我们可以基于 lsp的配置使用插件来完成，这里我推荐使用 nvim-cmp插件安装我们使用下面的代码进行安装-- nvim-cmp use {'hrsh7th/cmp-nvim-lsp'} use {'hrsh7th/cmp-buffer'} use {'hrsh7th/cmp-path'} use {'hrsh7th/cmp-cmdline'} use {'hrsh7th/nvim-cmp'} -- vsnip use {'hrsh7th/cmp-vsnip'} use {'hrsh7th/vim-vsnip'} use {'rafamadriz/friendly-snippets'} -- lspkind use {'onsails/lspkind-nvim'}看着好像要安装好多插件，但是真正重要的就只有 nvim-cmp 剩下的以 cmp- 开头的都是在指定补全的来源，就像 neovim 自带补全功能可以来源于当前buffer、路径、引用一样，该插件的补全项也来源于各个地方。例如 cmp-nvim-lsp来源于语言的 lsp 服务端、cmp-buffer来源于当前 buffer 、cmd-path来源于路径配置我们还是按照原来的惯例进行配置，新增一个 plugin-config/cmp.lua 的配置文件，并且加载它require('plugin-config/cmp')在该配置文件中我们加入如下内容local cmp = require("cmp") local lspkind = require("lspkind") cmp.setup({ -- 设置代码片段引擎，用于根据代码片段补全 snippet = { expand = function(args) vim.fn["vsnip#anonymous"](args.body) end, }, window = { }, mapping = { -- 选择上一个 ['<C-p>'] = cmp.mapping.select_prev_item(), -- 选择下一个 ['<C-n>'] = cmp.mapping.select_next_item(), -- 出现补全 ['<A-.>'] = cmp.mapping(cmp.mapping.complete(), {'i', 'c'}), -- 取消补全 ['<A-,>'] = cmp.mapping({ i = cmp.mapping.abort(), c = cmp.mapping.close(), }), -- 确认使用某个补全项 ['<CR>'] = cmp.mapping.confirm({ select = true, behavior = cmp.ConfirmBehavior.Replace }), -- 向上翻页 ['<C-u>'] = cmp.mapping(cmp.mapping.scroll_docs(-4), {'i', 'c'}), -- 向下翻页 ['<C-d>'] = cmp.mapping(cmp.mapping.scroll_docs(4), {'i', 'c'}), }, -- 补全来源 sources = cmp.config.sources({ {name = 'nvim_lsp'}, {name = 'vsnip'}, {name = 'buffer'}, {name = 'path'} }), --根据文件类型来选择补全来源 cmp.setup.filetype('gitcommit', { sources = cmp.config.sources({ {name = 'buffer'} }) }), -- 命令模式下输入 `/` 启用补全 cmp.setup.cmdline('/', { mapping = cmp.mapping.preset.cmdline(), sources = { { name = 'buffer' } } }), -- 命令模式下输入 `:` 启用补全 cmp.setup.cmdline(':', { mapping = cmp.mapping.preset.cmdline(), sources = cmp.config.sources({ { name = 'path' } }, { { name = 'cmdline' } }) }), -- 设置补全显示的格式 formatting = { format = lspkind.cmp_f…