这篇文章上次修改于 305 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

浅谈OIer的NVIM配置

本文因跨平台、软件版本更新等不可控因素,部分内容可能失效,请联系我修改!

懒者专用

不建议直接使用!因为路径产生的 BUG 可能很多!

我的配置文件仓库:Bot-wxt1221-NvChad

前言

某某人在机房配好 Vscode 之后发现卡死了,所以准备用 vim 写代码!

但是网上资料太少了,特别是针对 OIer 刷题的配置,所以我就来了。

上效果图:

软件选择

原版 Vim 其实并不好,主要有几点。

  • 众所周知开屏有些敏感话题

  • 不好配

不过,Vim 的分支多得很,看了一圈决定是 Nvim!

安装

Linux 下的话到你自己发行版的库里面找找就是了。

Windows的话有 qnvim,也就是基于 Qt 的。

配置

Nvim 打开还是和 Vim 差不多,但是真正好用的是网上打包好的配置文件!

隆重推荐 NvChad!(在 github 上有超 1w 的 star)

NvChad/NvChad

安装很简单,在本项目的官网上有详细介绍不同平台的方法

Link

另外还有字体的问题,建议使用带 Nerd 字样的字体,我用的是 JetBrains Mono Nerd Font ,应该是没有问题的不要用这个字体,Nerd Font 不全,FiraCode 和 JetBrains Mono 风格差不多,都有bug!烦死了!,可以先安装 JetBrains Mono 字体,再安装这个:Link,至于怎么换,这个在各个平台上不同,大概率都是你的终端的配置文件里面可以改。

Vim相关

Vim 和普通的文本编辑器有很大不同,Vim 的宗旨之一就是能在不碰鼠标的情况下实现很多功能,为了能够容下更多操作,所以 Vim 其实是有模式区分的。

最常用的是普通模式,在这个模式下可以通过输入冒号进入命令模式。

还有编辑模式,这个模式顾名思义就是可以编辑文件,按 esc 退出到普通模式。

命令模式就是输入命令的,这个是 Vim 单独的一套命令,不是 bash,同样是按 esc 退出到普通模式。

常用快捷键

Neovim的常见快捷键和命令 - 掘金

可以参考这篇。

主要是要记住窗口相关的和 tree 相关的。

继续配置

然而你发现 NvChad 不能编译运行调试,好难受,马上回到 Vscode

其实是可以的,运行和调试是一个东西,所以先说。

调试依赖于 DAP。

Nvim 上最好用的 DAP 就是 nvim-dap ,经过了很久的折腾后,终于找到了方法!

要装一堆插件,进入配置文件夹,Linux在~/.config/nvim ,Windows在$HOME\AppData\Local\nvim ,里面有一个 lua 文件夹打开,进入 plugins 文件夹 ,打开 init.lua 开始编辑。

这个文件是 Nvim 的包管理器,注意到定义了一个 default_plugins 直接在这里面改就行了,加入这些插件:

{"nvim-telescope/telescope.nvim",lazy=false},
{"ravenxrz/DAPInstall.nvim",lazy=false},
{"mfussenegger/nvim-dap",lazy=false},
{"rcarriga/nvim-dap-ui",lazy=false},
{"theHamsta/nvim-dap-virtual-text",lazy=false},

然后退出重进,不出意外就开始下包了。

这里有一个非常 NTR 的事情,就是我们又要用 Vscode 的东西了,这次使用 Vscode 的调试工具!

按冒号进入命令行模式开始安装

:DIInstall ccppr_vsc

就开始跑命令安装了,等到出现了类似于Process exited 的字样就说明成功了。

还没结束,接下来才是真正的极客!

在之前打开过的 plugins 文件夹里面有一个 configs文件夹,建立新文件夹 dap 用于写配置文件

dap/icon.lua

local M={}
function M.setup()
	local dap_breakpoint = {
		breakpoint = {
			text = "",
			texthl = "LspDiagnosticsSignError",
			linehl = "",
			numhl = "",
		},
		rejected = {
			text = "",
			texthl = "LspDiagnosticsSignHint",
			linehl = "",
			numhl = "",
		},
		stopped = {
			text = "",
			texthl = "LspDiagnosticsSignInformation",
			linehl = "DiagnosticUnderlineInfo",
			numhl = "LspDiagnosticsSignInformation",
		},
	}

	vim.fn.sign_define("DapBreakpoint", dap_breakpoint.breakpoint)
	vim.fn.sign_define("DapStopped", dap_breakpoint.stopped)
	vim.fn.sign_define("DapBreakpointRejected", dap_breakpoint.rejected)
end
return M

dap/init.lua

local M = {}

local function configure()
end

local function configure_exts()
end

local function configure_debuggers()
end

function M.setup()
	configure() -- Configuration
	configure_exts() -- Extensions
	configure_debuggers() -- Debugger
  require("plugins.configs.dap.keymap").setup()
  require("plugins.configs.dap.ui").setup()
  require("plugins.configs.dap.icon").setup()
  require("dap.ext.vscode").load_launchjs(nil, { cppdbg = { "c", "cpp", "rust" } })
  local dap = require('dap')
  dap.adapters.cppdbg = {
    id = 'cppdbg',
    type = 'executable',
    command = '/home/wxt/.local/share/nvim/dapinstall/ccppr_vsc/extension/debugAdapters/bin/OpenDebugAD7',
  }
end

configure_debuggers()

return M

dap/keymap.lua

local M = {}

local whichkey = require "which-key"
-- local legendary = require "legendary"

-- local function keymap(lhs, rhs, desc)
--   vim.keymap.set("n", lhs, rhs, { silent = true, desc = desc })
-- end

function M.setup()
  local keymap = {
    l = {
      name = "DAP",
      R = { "<cmd>lua require'dap'.run_to_cursor()<cr>", "Run to Cursor" },
      E = { "<cmd>lua require'dapui'.eval(vim.fn.input '[Expression] > ')<cr>", "Evaluate Input" },
      C = { "<cmd>lua require'dap'.set_breakpoint(vim.fn.input '[Condition] > ')<cr>", "Conditional Breakpoint" },
      U = { "<cmd>lua require'dapui'.toggle()<cr>", "Toggle UI" },
      b = { "<cmd>lua require'dap'.step_back()<cr>", "Step Back" },
      c = { "<cmd>lua require'dap'.continue()<cr>", "Continue" },
      d = { "<cmd>lua require'dap'.disconnect()<cr>", "Disconnect" },
      e = { "<cmd>lua require'dapui'.eval()<cr>", "Evaluate" },
      g = { "<cmd>lua require'dap'.session()<cr>", "Get Session" },
      h = { "<cmd>lua require'dap.ui.widgets'.hover()<cr>", "Hover Variables" },
      S = { "<cmd>lua require'dap.ui.widgets'.scopes()<cr>", "Scopes" },
      i = { "<cmd>lua require'dap'.step_into()<cr>", "Step Into" },
      o = { "<cmd>lua require'dap'.step_over()<cr>", "Step Over" },
      p = { "<cmd>lua require'dap'.pause.toggle()<cr>", "Pause" },
      q = { "<cmd>lua require'dap'.close()<cr>", "Quit" },
      r = { "<cmd>lua require'dap'.repl.toggle()<cr>", "Toggle Repl" },
      s = { "<cmd>lua require'dap'.continue()<cr>", "Start" },
      t = { "<cmd>lua require'dap'.toggle_breakpoint()<cr>", "Toggle Breakpoint" },
      x = { "<cmd>lua require'dap'.terminate()<cr>", "Terminate" },
      u = { "<cmd>lua require'dap'.step_out()<cr>", "Step Out" },
    },
  }
  local opts = {
    mode = "n",
    prefix = "<leader>",
    buffer = nil,
    silent = true,
    noremap = true,
    nowait = false,
  }
  whichkey.register(keymap, opts)
  --- require("legendary.integrations.which-key").bind_whichkey(keymap, opts, false)
  vim.api.nvim_create_autocmd("FileType", {
        pattern = "cpp",
        callback = function()
            vim.api.nvim_buf_set_keymap(
                0,
                "n",
                "<F5>",
                ":w<CR>:split<CR>:te g++ % -g -DONLINE_JUDGE -std=c++14 -O2 -o %:t:r -fsanitize=address -fsanitize=undefined<CR>i",
                { silent = true, noremap = true }
            )
        end,
    })
  
  local keymap_v = {
    l = {
      name = "Debug",
      e = { "<cmd>lua require'dapui'.eval()<cr>", "Evaluate" },
    },
  }
  opts = {
    mode = "v",
    prefix = "<leader>",
    buffer = nil,
    silent = true,
    noremap = true,
    nowait = false,
  }
  whichkey.register(keymap_v, opts)
  --- require("legendary.integrations.which-key").bind_whichkey(keymap_v, opts, false)
end

return M

dap/ui.lua

local M={}
function M.setup()
	require("nvim-dap-virtual-text").setup({
		commented = true,
	})

	local dap, dapui = require("dap"), require("dapui")
	dapui.setup({
		expand_lines = true,
		icons = { expanded = "", collapsed = "", circular = "" },
		mappings = {
			-- Use a table to apply multiple mappings
			expand = { "<CR>", "<2-LeftMouse>" },
			open = "o",
			remove = "d",
			edit = "e",
			repl = "r",
			toggle = "t",
		},
		layouts = {
			{
				elements = {
					{ id = "scopes", size = 0.33 },
					{ id = "breakpoints", size = 0.17 },
					{ id = "stacks", size = 0.25 },
					{ id = "watches", size = 0.25 },
				},
				size = 0.33,
				position = "right",
			},
			{
				elements = {
					{ id = "repl", size = 0.45 },
					{ id = "console", size = 0.55 },
				},
				size = 0.27,
				position = "bottom",
			},
		},
		floating = {
			max_height = 0.9,
			max_width = 0.5, -- Floats will be treated as percentage of your screen.
			border = vim.g.border_chars, -- Border style. Can be 'single', 'double' or 'rounded'
			mappings = {
				close = { "q", "<Esc>" },
			},
		},
	}) -- use default
	dap.listeners.after.event_initialized["dapui_config"] = function()
		dapui.open({})
	end
	dap.listeners.before.event_terminated["dapui_config"] = function()
		dapui.close({})
	end
	dap.listeners.before.event_exited["dapui_config"] = function()
		dapui.close({})
	end
end
return M

看得懂的可以自行修改其他地方,

但是你们都要改一个地方就是 dap/init.lua 里面那个路径,改成 OpenDebugAD7 的位置。

另外 keymap里面 有一个 F5 的地方,下面是编译命令,可以自行修改。

再回到configs 下的那个 init.lua 就是加了一堆插件的那个,最下面加上

require("plugins.configs.dap.init").setup()

使用简介

还是建议和 Vscode 一样用一个文件夹,因为我们的 NTR 设置,所以需要和 Vscode 一样建立 .vscode 文件夹,里面之用 launch.json 即可,里面的 launch.json 不能用中文注释,preTasks 那项要删掉,然后就可以开用了。

提供一个 launch.json 模板,直接就能用:Link

打开一个 C++ 文件,普通模式下按下 F5 就可以编译,Space+l 可以查看调试可以用的命令,Space+l+c 开始调试。看得出来和 Vscode 的调试比较像。