本文总结记录一些neovim的使用技巧。包括根据上下文判断是否扩展tab(expandtab)、在已修改的文件位置之间跳转、将选中的字符作为文件名在新标签页打开。

根据上下文判断是否扩展tab

在下面的例子中,当进入Insert模式前,会判断上下10行中以tab和space开头的行,如果以space开头的行数多余以tab开头的行数,则默认将tab转为space,否则保留tab。

local autocmd = vim.api.nvim_create_autocmd
autocmd("InsertEnter", {
	pattern = "*",
	callback = function()
		local line_num = vim.fn.line(".")
		-- 行数不能超出文件起始和终止位置
		local start_line = math.max(1, line_num - 10)
		local end_line = math.min(vim.fn.line("$"), line_num + 10)
		local tab_count = 0
		local space_count = 0

		for i = start_line, end_line do
			if i ~= line_num then
				local line = vim.fn.getline(i)
				if line:match("^\t") then
					tab_count = tab_count + 1
				elseif line:match("^ ") then
					space_count = space_count + 1
				end
			end
		end

		print("tab_count:"..tostring(tab_count).."space_count:"..tostring(space_count))
		if tab_count > space_count then
			vim.bo.expandtab = false
		else
			vim.bo.expandtab = true
		end
	end,
})

修改位置跳转

g;:跳转到上一个修改的位置

g,:跳转到下一个修改的位置

使用gitsigns.nvim跳转到buf中显示git修改的位置,配置如下:

use({
	"lewis6991/gitsigns.nvim",
	config = function()
		require("gitsigns").setup({
			current_line_blame = true,
			on_attach = function(bufnr)
				local gs = package.loaded.gitsigns
				local function map(mode, l, r, opts)
					opts = opts or {}
					opts.buffer = bufnr
					vim.keymap.set(mode, l, r, opts)
				end
				-- Navigation
				map("n", "]c", function()
					if vim.wo.diff then
						return "]c"
					end
					vim.schedule(function()
						gs.next_hunk()
					end)
					return "<Ignore>"
				end, { expr = true })

				map("n", "[c", function()
					if vim.wo.diff then
						return "[c"
					end
					vim.schedule(function()
						gs.prev_hunk()
					end)
					return "<Ignore>"
				end, { expr = true })
			end,
		})
	end,
})

将选中的字符串作为文件在新tab中打开

  1. 如果文件存在则打开已存在的文件;
  2. 如果文件不存在则创建同名buffer;

注意:选中多行时会视为无效,打开一个匿名buffer

-- 将单行内选中的字符串当作文件打开
local function get_visual_selection()
	-- 获取当前选中的文本
	local start_pos = vim.fn.getpos("'<")
	local end_pos = vim.fn.getpos("'>")
	local line = vim.fn.getline(start_pos[2])
	if start_pos[2] ~= end_pos[2] then
		vim.notify("Selection spans multiple lines, please select within a single line.")
		return nil
	end
	return string.sub(line, start_pos[3], end_pos[3])
end
function open_selected_file()
	local file = get_visual_selection() ~= nil and get_visual_selection() or ""
	vim.cmd("tabnew " .. file)

	-- 检查文件是否存在并可读
	-- if vim.fn.filereadable(file) == 1 then
	-- 	vim.cmd("vnew " .. file)
	-- 	vim.cmd("tabnew " .. file)
	-- else
	-- 	vim.notify("File not found: " .. file)
	-- end
end
-- 将函数映射到快捷键 <leader>gf
map("v", "<leader>of", ":lua open_selected_file() <CR>", { noremap = true, silent = true })