Reorganize config modules into lua/plugins/ and add comprehensive docs
- Move lsp.lua, pick.lua, treesitter.lua, git.lua to lua/plugins/ - Update all require() paths in pack.lua and init.lua - Unify code style: tab indentation, line length control, empty braces - Add detailed Chinese module documentation to all config files - Add grug-far.nvim plugin with <leader>sr binding - Enable vim._core.ui2 for Neovim 0.12+ UI enhancements - Disable additional built-in plugins to reduce startup overhead Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
79af59f4f2
commit
9c8deeafc8
@ -1,5 +1,7 @@
|
|||||||
vim.o.termguicolors = true
|
vim.o.termguicolors = true
|
||||||
if vim.g.colors_name then vim.cmd("hi clear") end
|
if vim.g.colors_name then
|
||||||
|
vim.cmd("hi clear")
|
||||||
|
end
|
||||||
vim.g.colors_name = "mytheme-frappe"
|
vim.g.colors_name = "mytheme-frappe"
|
||||||
local h = vim.api.nvim_set_hl
|
local h = vim.api.nvim_set_hl
|
||||||
h(0, "DashboardFooter", { fg = "#e5c890", italic = true })
|
h(0, "DashboardFooter", { fg = "#e5c890", italic = true })
|
||||||
@ -346,7 +348,7 @@ h(0, "MiniPickPreviewRegion", { link = "IncSearch" })
|
|||||||
h(0, "MiniPickPrompt", { fg = "#c6d0f5", bg = "#292c3c" })
|
h(0, "MiniPickPrompt", { fg = "#c6d0f5", bg = "#292c3c" })
|
||||||
h(0, "MiniPickPromptCaret", { fg = "#eebebe", bg = "#292c3c" })
|
h(0, "MiniPickPromptCaret", { fg = "#eebebe", bg = "#292c3c" })
|
||||||
h(0, "MiniPickPromptPrefix", { fg = "#eebebe", bg = "#292c3c" })
|
h(0, "MiniPickPromptPrefix", { fg = "#eebebe", bg = "#292c3c" })
|
||||||
h(0, "MiniStarterCurrent", { })
|
h(0, "MiniStarterCurrent", {})
|
||||||
h(0, "MiniStarterFooter", { fg = "#e5c890", italic = true })
|
h(0, "MiniStarterFooter", { fg = "#e5c890", italic = true })
|
||||||
h(0, "MiniStarterHeader", { fg = "#8caaee" })
|
h(0, "MiniStarterHeader", { fg = "#8caaee" })
|
||||||
h(0, "MiniStarterInactive", { fg = "#626880", italic = true })
|
h(0, "MiniStarterInactive", { fg = "#626880", italic = true })
|
||||||
@ -366,7 +368,11 @@ h(0, "MiniStatuslineModeOther", { fg = "#303446", bold = true, bg = "#81c8be" })
|
|||||||
h(0, "MiniStatuslineModeReplace", { fg = "#303446", bold = true, bg = "#e78284" })
|
h(0, "MiniStatuslineModeReplace", { fg = "#303446", bold = true, bg = "#e78284" })
|
||||||
h(0, "MiniStatuslineModeVisual", { fg = "#303446", bold = true, bg = "#ca9ee6" })
|
h(0, "MiniStatuslineModeVisual", { fg = "#303446", bold = true, bg = "#ca9ee6" })
|
||||||
h(0, "MiniSurround", { fg = "#51576d", bg = "#f4b8e4" })
|
h(0, "MiniSurround", { fg = "#51576d", bg = "#f4b8e4" })
|
||||||
h(0, "MiniTablineCurrent", { italic = true, sp = "#e78284", fg = "#c6d0f5", bold = true, underline = true, bg = "#303446" })
|
h(
|
||||||
|
0,
|
||||||
|
"MiniTablineCurrent",
|
||||||
|
{ italic = true, sp = "#e78284", fg = "#c6d0f5", bold = true, underline = true, bg = "#303446" }
|
||||||
|
)
|
||||||
h(0, "MiniTablineFill", { bg = "NONE" })
|
h(0, "MiniTablineFill", { bg = "NONE" })
|
||||||
h(0, "MiniTablineHidden", { fg = "#c6d0f5", bg = "NONE" })
|
h(0, "MiniTablineHidden", { fg = "#c6d0f5", bg = "NONE" })
|
||||||
h(0, "MiniTablineModifiedCurrent", { italic = true, bg = "NONE", fg = "#e78284", bold = true })
|
h(0, "MiniTablineModifiedCurrent", { italic = true, bg = "NONE", fg = "#e78284", bold = true })
|
||||||
@ -800,7 +806,7 @@ h(0, "@markup.heading", { fg = "#8caaee" })
|
|||||||
h(0, "@markup.underline", { link = "Underlined" })
|
h(0, "@markup.underline", { link = "Underlined" })
|
||||||
h(0, "@function.builtin", { fg = "#ef9f76" })
|
h(0, "@function.builtin", { fg = "#ef9f76" })
|
||||||
h(0, "@lsp.typemod.function.defaultLibrary", { link = "@function.builtin" })
|
h(0, "@lsp.typemod.function.defaultLibrary", { link = "@function.builtin" })
|
||||||
h(0, "@lsp.type.variable", { })
|
h(0, "@lsp.type.variable", {})
|
||||||
h(0, "@lsp.type.enumMember", { fg = "#81c8be" })
|
h(0, "@lsp.type.enumMember", { fg = "#81c8be" })
|
||||||
h(0, "diffIndexLine", { fg = "#81c8be" })
|
h(0, "diffIndexLine", { fg = "#81c8be" })
|
||||||
h(0, "diffLine", { fg = "#737994" })
|
h(0, "diffLine", { fg = "#737994" })
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
vim.o.termguicolors = true
|
vim.o.termguicolors = true
|
||||||
if vim.g.colors_name then vim.cmd("hi clear") end
|
if vim.g.colors_name then
|
||||||
|
vim.cmd("hi clear")
|
||||||
|
end
|
||||||
vim.g.colors_name = "mytheme-latte"
|
vim.g.colors_name = "mytheme-latte"
|
||||||
local h = vim.api.nvim_set_hl
|
local h = vim.api.nvim_set_hl
|
||||||
h(0, "DashboardFooter", { fg = "#df8e1d", italic = true })
|
h(0, "DashboardFooter", { fg = "#df8e1d", italic = true })
|
||||||
@ -346,7 +348,7 @@ h(0, "MiniPickPreviewRegion", { link = "IncSearch" })
|
|||||||
h(0, "MiniPickPrompt", { fg = "#4c4f69", bg = "#e6e9ef" })
|
h(0, "MiniPickPrompt", { fg = "#4c4f69", bg = "#e6e9ef" })
|
||||||
h(0, "MiniPickPromptCaret", { fg = "#dd7878", bg = "#e6e9ef" })
|
h(0, "MiniPickPromptCaret", { fg = "#dd7878", bg = "#e6e9ef" })
|
||||||
h(0, "MiniPickPromptPrefix", { fg = "#dd7878", bg = "#e6e9ef" })
|
h(0, "MiniPickPromptPrefix", { fg = "#dd7878", bg = "#e6e9ef" })
|
||||||
h(0, "MiniStarterCurrent", { })
|
h(0, "MiniStarterCurrent", {})
|
||||||
h(0, "MiniStarterFooter", { fg = "#df8e1d", italic = true })
|
h(0, "MiniStarterFooter", { fg = "#df8e1d", italic = true })
|
||||||
h(0, "MiniStarterHeader", { fg = "#1e66f5" })
|
h(0, "MiniStarterHeader", { fg = "#1e66f5" })
|
||||||
h(0, "MiniStarterInactive", { fg = "#acb0be", italic = true })
|
h(0, "MiniStarterInactive", { fg = "#acb0be", italic = true })
|
||||||
@ -366,7 +368,11 @@ h(0, "MiniStatuslineModeOther", { fg = "#eff1f5", bold = true, bg = "#179299" })
|
|||||||
h(0, "MiniStatuslineModeReplace", { fg = "#eff1f5", bold = true, bg = "#d20f39" })
|
h(0, "MiniStatuslineModeReplace", { fg = "#eff1f5", bold = true, bg = "#d20f39" })
|
||||||
h(0, "MiniStatuslineModeVisual", { fg = "#eff1f5", bold = true, bg = "#8839ef" })
|
h(0, "MiniStatuslineModeVisual", { fg = "#eff1f5", bold = true, bg = "#8839ef" })
|
||||||
h(0, "MiniSurround", { fg = "#bcc0cc", bg = "#ea76cb" })
|
h(0, "MiniSurround", { fg = "#bcc0cc", bg = "#ea76cb" })
|
||||||
h(0, "MiniTablineCurrent", { italic = true, sp = "#d20f39", fg = "#4c4f69", bold = true, underline = true, bg = "#eff1f5" })
|
h(
|
||||||
|
0,
|
||||||
|
"MiniTablineCurrent",
|
||||||
|
{ italic = true, sp = "#d20f39", fg = "#4c4f69", bold = true, underline = true, bg = "#eff1f5" }
|
||||||
|
)
|
||||||
h(0, "MiniTablineFill", { bg = "NONE" })
|
h(0, "MiniTablineFill", { bg = "NONE" })
|
||||||
h(0, "MiniTablineHidden", { fg = "#4c4f69", bg = "NONE" })
|
h(0, "MiniTablineHidden", { fg = "#4c4f69", bg = "NONE" })
|
||||||
h(0, "MiniTablineModifiedCurrent", { italic = true, bg = "NONE", fg = "#d20f39", bold = true })
|
h(0, "MiniTablineModifiedCurrent", { italic = true, bg = "NONE", fg = "#d20f39", bold = true })
|
||||||
@ -800,7 +806,7 @@ h(0, "@markup.heading", { fg = "#1e66f5" })
|
|||||||
h(0, "@markup.underline", { link = "Underlined" })
|
h(0, "@markup.underline", { link = "Underlined" })
|
||||||
h(0, "@function.builtin", { fg = "#fe640b" })
|
h(0, "@function.builtin", { fg = "#fe640b" })
|
||||||
h(0, "@lsp.typemod.function.defaultLibrary", { link = "@function.builtin" })
|
h(0, "@lsp.typemod.function.defaultLibrary", { link = "@function.builtin" })
|
||||||
h(0, "@lsp.type.variable", { })
|
h(0, "@lsp.type.variable", {})
|
||||||
h(0, "@lsp.type.enumMember", { fg = "#179299" })
|
h(0, "@lsp.type.enumMember", { fg = "#179299" })
|
||||||
h(0, "diffIndexLine", { fg = "#179299" })
|
h(0, "diffIndexLine", { fg = "#179299" })
|
||||||
h(0, "diffLine", { fg = "#9ca0b0" })
|
h(0, "diffLine", { fg = "#9ca0b0" })
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
vim.o.termguicolors = true
|
vim.o.termguicolors = true
|
||||||
if vim.g.colors_name then vim.cmd("hi clear") end
|
if vim.g.colors_name then
|
||||||
|
vim.cmd("hi clear")
|
||||||
|
end
|
||||||
vim.g.colors_name = "mytheme-macchiato"
|
vim.g.colors_name = "mytheme-macchiato"
|
||||||
local h = vim.api.nvim_set_hl
|
local h = vim.api.nvim_set_hl
|
||||||
h(0, "DashboardFooter", { fg = "#eed49f", italic = true })
|
h(0, "DashboardFooter", { fg = "#eed49f", italic = true })
|
||||||
@ -346,7 +348,7 @@ h(0, "MiniPickPreviewRegion", { link = "IncSearch" })
|
|||||||
h(0, "MiniPickPrompt", { fg = "#cad3f5", bg = "#1e2030" })
|
h(0, "MiniPickPrompt", { fg = "#cad3f5", bg = "#1e2030" })
|
||||||
h(0, "MiniPickPromptCaret", { fg = "#f0c6c6", bg = "#1e2030" })
|
h(0, "MiniPickPromptCaret", { fg = "#f0c6c6", bg = "#1e2030" })
|
||||||
h(0, "MiniPickPromptPrefix", { fg = "#f0c6c6", bg = "#1e2030" })
|
h(0, "MiniPickPromptPrefix", { fg = "#f0c6c6", bg = "#1e2030" })
|
||||||
h(0, "MiniStarterCurrent", { })
|
h(0, "MiniStarterCurrent", {})
|
||||||
h(0, "MiniStarterFooter", { fg = "#eed49f", italic = true })
|
h(0, "MiniStarterFooter", { fg = "#eed49f", italic = true })
|
||||||
h(0, "MiniStarterHeader", { fg = "#8aadf4" })
|
h(0, "MiniStarterHeader", { fg = "#8aadf4" })
|
||||||
h(0, "MiniStarterInactive", { fg = "#5b6078", italic = true })
|
h(0, "MiniStarterInactive", { fg = "#5b6078", italic = true })
|
||||||
@ -366,7 +368,11 @@ h(0, "MiniStatuslineModeOther", { fg = "#24273a", bold = true, bg = "#8bd5ca" })
|
|||||||
h(0, "MiniStatuslineModeReplace", { fg = "#24273a", bold = true, bg = "#ed8796" })
|
h(0, "MiniStatuslineModeReplace", { fg = "#24273a", bold = true, bg = "#ed8796" })
|
||||||
h(0, "MiniStatuslineModeVisual", { fg = "#24273a", bold = true, bg = "#c6a0f6" })
|
h(0, "MiniStatuslineModeVisual", { fg = "#24273a", bold = true, bg = "#c6a0f6" })
|
||||||
h(0, "MiniSurround", { fg = "#494d64", bg = "#f5bde6" })
|
h(0, "MiniSurround", { fg = "#494d64", bg = "#f5bde6" })
|
||||||
h(0, "MiniTablineCurrent", { italic = true, sp = "#ed8796", fg = "#cad3f5", bold = true, underline = true, bg = "#24273a" })
|
h(
|
||||||
|
0,
|
||||||
|
"MiniTablineCurrent",
|
||||||
|
{ italic = true, sp = "#ed8796", fg = "#cad3f5", bold = true, underline = true, bg = "#24273a" }
|
||||||
|
)
|
||||||
h(0, "MiniTablineFill", { bg = "NONE" })
|
h(0, "MiniTablineFill", { bg = "NONE" })
|
||||||
h(0, "MiniTablineHidden", { fg = "#cad3f5", bg = "NONE" })
|
h(0, "MiniTablineHidden", { fg = "#cad3f5", bg = "NONE" })
|
||||||
h(0, "MiniTablineModifiedCurrent", { italic = true, bg = "NONE", fg = "#ed8796", bold = true })
|
h(0, "MiniTablineModifiedCurrent", { italic = true, bg = "NONE", fg = "#ed8796", bold = true })
|
||||||
@ -800,7 +806,7 @@ h(0, "@markup.heading", { fg = "#8aadf4" })
|
|||||||
h(0, "@markup.underline", { link = "Underlined" })
|
h(0, "@markup.underline", { link = "Underlined" })
|
||||||
h(0, "@function.builtin", { fg = "#f5a97f" })
|
h(0, "@function.builtin", { fg = "#f5a97f" })
|
||||||
h(0, "@lsp.typemod.function.defaultLibrary", { link = "@function.builtin" })
|
h(0, "@lsp.typemod.function.defaultLibrary", { link = "@function.builtin" })
|
||||||
h(0, "@lsp.type.variable", { })
|
h(0, "@lsp.type.variable", {})
|
||||||
h(0, "@lsp.type.enumMember", { fg = "#8bd5ca" })
|
h(0, "@lsp.type.enumMember", { fg = "#8bd5ca" })
|
||||||
h(0, "diffIndexLine", { fg = "#8bd5ca" })
|
h(0, "diffIndexLine", { fg = "#8bd5ca" })
|
||||||
h(0, "diffLine", { fg = "#6e738d" })
|
h(0, "diffLine", { fg = "#6e738d" })
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
vim.o.termguicolors = true
|
vim.o.termguicolors = true
|
||||||
if vim.g.colors_name then vim.cmd("hi clear") end
|
if vim.g.colors_name then
|
||||||
|
vim.cmd("hi clear")
|
||||||
|
end
|
||||||
vim.g.colors_name = "mytheme-mocha"
|
vim.g.colors_name = "mytheme-mocha"
|
||||||
local h = vim.api.nvim_set_hl
|
local h = vim.api.nvim_set_hl
|
||||||
h(0, "DashboardFooter", { fg = "#f9e2af", italic = true })
|
h(0, "DashboardFooter", { fg = "#f9e2af", italic = true })
|
||||||
@ -350,7 +352,7 @@ h(0, "MiniPickPreviewRegion", { link = "IncSearch" })
|
|||||||
h(0, "MiniPickPrompt", { fg = "#cdd6f4", bg = "#181825" })
|
h(0, "MiniPickPrompt", { fg = "#cdd6f4", bg = "#181825" })
|
||||||
h(0, "MiniPickPromptCaret", { fg = "#f2cdcd", bg = "#181825" })
|
h(0, "MiniPickPromptCaret", { fg = "#f2cdcd", bg = "#181825" })
|
||||||
h(0, "MiniPickPromptPrefix", { fg = "#f2cdcd", bg = "#181825" })
|
h(0, "MiniPickPromptPrefix", { fg = "#f2cdcd", bg = "#181825" })
|
||||||
h(0, "MiniStarterCurrent", { })
|
h(0, "MiniStarterCurrent", {})
|
||||||
h(0, "MiniStarterFooter", { fg = "#f9e2af", italic = true })
|
h(0, "MiniStarterFooter", { fg = "#f9e2af", italic = true })
|
||||||
h(0, "MiniStarterHeader", { fg = "#89b4fa" })
|
h(0, "MiniStarterHeader", { fg = "#89b4fa" })
|
||||||
h(0, "MiniStarterInactive", { fg = "#585b70", italic = true })
|
h(0, "MiniStarterInactive", { fg = "#585b70", italic = true })
|
||||||
@ -370,7 +372,11 @@ h(0, "MiniStatuslineModeOther", { fg = "#1e1e2e", bold = true, bg = "#94e2d5" })
|
|||||||
h(0, "MiniStatuslineModeReplace", { fg = "#1e1e2e", bold = true, bg = "#f38ba8" })
|
h(0, "MiniStatuslineModeReplace", { fg = "#1e1e2e", bold = true, bg = "#f38ba8" })
|
||||||
h(0, "MiniStatuslineModeVisual", { fg = "#1e1e2e", bold = true, bg = "#cba6f7" })
|
h(0, "MiniStatuslineModeVisual", { fg = "#1e1e2e", bold = true, bg = "#cba6f7" })
|
||||||
h(0, "MiniSurround", { fg = "#45475a", bg = "#f5c2e7" })
|
h(0, "MiniSurround", { fg = "#45475a", bg = "#f5c2e7" })
|
||||||
h(0, "MiniTablineCurrent", { italic = true, sp = "#f38ba8", fg = "#cdd6f4", bold = true, underline = true, bg = "#1e1e2e" })
|
h(
|
||||||
|
0,
|
||||||
|
"MiniTablineCurrent",
|
||||||
|
{ italic = true, sp = "#f38ba8", fg = "#cdd6f4", bold = true, underline = true, bg = "#1e1e2e" }
|
||||||
|
)
|
||||||
h(0, "MiniTablineFill", { bg = "NONE" })
|
h(0, "MiniTablineFill", { bg = "NONE" })
|
||||||
h(0, "MiniTablineHidden", { fg = "#cdd6f4", bg = "NONE" })
|
h(0, "MiniTablineHidden", { fg = "#cdd6f4", bg = "NONE" })
|
||||||
h(0, "MiniTablineModifiedCurrent", { italic = true, bg = "NONE", fg = "#f38ba8", bold = true })
|
h(0, "MiniTablineModifiedCurrent", { italic = true, bg = "NONE", fg = "#f38ba8", bold = true })
|
||||||
@ -804,7 +810,7 @@ h(0, "@markup.heading", { fg = "#89b4fa" })
|
|||||||
h(0, "@markup.underline", { link = "Underlined" })
|
h(0, "@markup.underline", { link = "Underlined" })
|
||||||
h(0, "@function.builtin", { fg = "#fab387" })
|
h(0, "@function.builtin", { fg = "#fab387" })
|
||||||
h(0, "@lsp.typemod.function.defaultLibrary", { link = "@function.builtin" })
|
h(0, "@lsp.typemod.function.defaultLibrary", { link = "@function.builtin" })
|
||||||
h(0, "@lsp.type.variable", { })
|
h(0, "@lsp.type.variable", {})
|
||||||
h(0, "@lsp.type.enumMember", { fg = "#94e2d5" })
|
h(0, "@lsp.type.enumMember", { fg = "#94e2d5" })
|
||||||
h(0, "diffIndexLine", { fg = "#94e2d5" })
|
h(0, "diffIndexLine", { fg = "#94e2d5" })
|
||||||
h(0, "diffLine", { fg = "#6c7086" })
|
h(0, "diffLine", { fg = "#6c7086" })
|
||||||
|
|||||||
68
init.lua
68
init.lua
@ -27,35 +27,34 @@ _G.nvim_start_time = (vim.uv or vim.loop).hrtime()
|
|||||||
--
|
--
|
||||||
-- 注意:loaded_syntax 设为 1 是为了避免旧版 Vim 兼容的 syntax 加载路径;
|
-- 注意:loaded_syntax 设为 1 是为了避免旧版 Vim 兼容的 syntax 加载路径;
|
||||||
-- 实际语法高亮由 treesitter 接管,不受影响。
|
-- 实际语法高亮由 treesitter 接管,不受影响。
|
||||||
|
vim.g.loaded_2html_plugin = 1 -- :TOhtml 命令(将 buffer 导出为 HTML)
|
||||||
vim.g.loaded_2html_plugin = 1 -- :TOhtml 命令(将 buffer 导出为 HTML)
|
vim.g.loaded_getscript = 1 -- GetScript 插件(自动下载脚本)
|
||||||
vim.g.loaded_getscript = 1 -- GetScript 插件(自动下载脚本)
|
vim.g.loaded_getscriptPlugin = 1 -- GetScript 插件主体
|
||||||
vim.g.loaded_getscriptPlugin = 1 -- GetScript 插件主体
|
vim.g.loaded_gzip = 1 -- Gzip 压缩文件读写支持
|
||||||
vim.g.loaded_gzip = 1 -- Gzip 压缩文件读写支持
|
vim.g.loaded_logipat = 1 -- LogiPat 逻辑模式匹配
|
||||||
vim.g.loaded_logipat = 1 -- LogiPat 逻辑模式匹配
|
vim.g.loaded_matchit = 1 -- % 匹配扩展(由 treesitter 或 mini.pairs 替代)
|
||||||
vim.g.loaded_matchit = 1 -- % 匹配扩展(由 treesitter 或 mini.pairs 替代)
|
vim.g.loaded_matchparen = 1 -- 括号匹配高亮(由 treesitter 替代)
|
||||||
vim.g.loaded_matchparen = 1 -- 括号匹配高亮(由 treesitter 替代)
|
vim.g.loaded_netrw = 1 -- Netrw 文件浏览器(由 mini.files 替代)
|
||||||
vim.g.loaded_netrw = 1 -- Netrw 文件浏览器(由 mini.files 替代)
|
vim.g.loaded_netrwFileHandlers = 1 -- Netrw 文件处理器
|
||||||
vim.g.loaded_netrwFileHandlers = 1 -- Netrw 文件处理器
|
vim.g.loaded_netrwPlugin = 1 -- Netrw 插件主体
|
||||||
vim.g.loaded_netrwPlugin = 1 -- Netrw 插件主体
|
vim.g.loaded_netrwSettings = 1 -- Netrw 设置
|
||||||
vim.g.loaded_netrwSettings = 1 -- Netrw 设置
|
vim.g.loaded_rrhelper = 1 -- RRHelper(R 语言相关)
|
||||||
vim.g.loaded_rrhelper = 1 -- RRHelper(R 语言相关)
|
vim.g.loaded_spellfile_plugin = 1 -- 拼写文件自动下载
|
||||||
vim.g.loaded_spellfile_plugin = 1 -- 拼写文件自动下载
|
vim.g.loaded_tar = 1 -- Tar 归档支持
|
||||||
vim.g.loaded_tar = 1 -- Tar 归档支持
|
vim.g.loaded_tarPlugin = 1 -- Tar 插件主体
|
||||||
vim.g.loaded_tarPlugin = 1 -- Tar 插件主体
|
vim.g.loaded_tutor_mode_plugin = 1 -- Vim Tutor 教程模式
|
||||||
vim.g.loaded_tutor_mode_plugin = 1 -- Vim Tutor 教程模式
|
vim.g.loaded_vimball = 1 -- Vimball 归档格式
|
||||||
vim.g.loaded_vimball = 1 -- Vimball 归档格式
|
vim.g.loaded_vimballPlugin = 1 -- Vimball 插件主体
|
||||||
vim.g.loaded_vimballPlugin = 1 -- Vimball 插件主体
|
vim.g.loaded_zip = 1 -- Zip 归档支持
|
||||||
vim.g.loaded_zip = 1 -- Zip 归档支持
|
vim.g.loaded_zipPlugin = 1 -- Zip 插件主体
|
||||||
vim.g.loaded_zipPlugin = 1 -- Zip 插件主体
|
vim.g.loaded_rplugin = 1 -- 远程插件框架
|
||||||
vim.g.loaded_rplugin = 1 -- 远程插件框架
|
vim.g.loaded_tohtml = 1 -- :TOhtml 的另一入口
|
||||||
vim.g.loaded_tohtml = 1 -- :TOhtml 的另一入口
|
vim.g.loaded_syntax = 1 -- 旧版 syntax 自动加载
|
||||||
vim.g.loaded_syntax = 1 -- 旧版 syntax 自动加载
|
vim.g.loaded_synmenu = 1 -- Syntax 菜单
|
||||||
vim.g.loaded_synmenu = 1 -- Syntax 菜单
|
vim.g.loaded_optwin = 1 -- 选项窗口 (:options)
|
||||||
vim.g.loaded_optwin = 1 -- 选项窗口 (:options)
|
vim.g.loaded_compiler = 1 -- 编译器插件自动加载
|
||||||
vim.g.loaded_compiler = 1 -- 编译器插件自动加载
|
vim.g.loaded_bugreport = 1 -- Bug 报告生成
|
||||||
vim.g.loaded_bugreport = 1 -- Bug 报告生成
|
vim.g.loaded_ftplugin = 1 -- 文件类型插件(手动管理)
|
||||||
vim.g.loaded_ftplugin = 1 -- 文件类型插件(手动管理)
|
|
||||||
|
|
||||||
-- =============================================================================
|
-- =============================================================================
|
||||||
-- 启用 Neovim 0.12+ 内置 UI 增强
|
-- 启用 Neovim 0.12+ 内置 UI 增强
|
||||||
@ -69,12 +68,11 @@ require("vim._core.ui2").enable({})
|
|||||||
-- =============================================================================
|
-- =============================================================================
|
||||||
-- 这些模块按顺序加载,后续模块可以依赖前面模块的设置。
|
-- 这些模块按顺序加载,后续模块可以依赖前面模块的设置。
|
||||||
-- 例如 pack.lua 中使用的键位映射依赖于 keymaps.lua 中设置的 leader 键。
|
-- 例如 pack.lua 中使用的键位映射依赖于 keymaps.lua 中设置的 leader 键。
|
||||||
|
require("options") -- 全局 vim 选项设置
|
||||||
require("options") -- 全局 vim 选项设置
|
require("keymaps") -- 键位映射定义
|
||||||
require("keymaps") -- 键位映射定义
|
require("autocmds") -- 自动命令(autocmd)
|
||||||
require("autocmds") -- 自动命令(autocmd)
|
require("usercmds") -- 用户自定义命令
|
||||||
require("usercmds") -- 用户自定义命令
|
require("pack") -- 插件管理与懒加载配置
|
||||||
require("pack") -- 插件管理与懒加载配置
|
|
||||||
|
|
||||||
-- =============================================================================
|
-- =============================================================================
|
||||||
-- Colorscheme 设置
|
-- Colorscheme 设置
|
||||||
|
|||||||
@ -23,23 +23,22 @@ local group = vim.api.nvim_create_augroup("UserAutocmds", { clear = true })
|
|||||||
-- - commit / gitcommit:Git 提交消息文件,总是从头开始编辑
|
-- - commit / gitcommit:Git 提交消息文件,总是从头开始编辑
|
||||||
-- - xxd:十六进制编辑模式
|
-- - xxd:十六进制编辑模式
|
||||||
-- - gitrebase:Git rebase 交互式编辑
|
-- - gitrebase:Git rebase 交互式编辑
|
||||||
|
|
||||||
vim.api.nvim_create_autocmd("BufReadPost", {
|
vim.api.nvim_create_autocmd("BufReadPost", {
|
||||||
group = group,
|
group = group,
|
||||||
callback = function()
|
callback = function()
|
||||||
-- 获取 `"` 标记的位置(行, 列)
|
-- 获取 `"` 标记的位置(行, 列)
|
||||||
local mark = vim.api.nvim_buf_get_mark(0, '"')
|
local mark = vim.api.nvim_buf_get_mark(0, '"')
|
||||||
local row = mark[1] -- 行号(1-based)
|
local row = mark[1] -- 行号(1-based)
|
||||||
local ft = vim.bo.filetype
|
local ft = vim.bo.filetype
|
||||||
|
|
||||||
-- 仅当标记有效(行号 > 1 且在文件范围内)时恢复光标
|
-- 仅当标记有效(行号 > 1 且在文件范围内)时恢复光标
|
||||||
if row > 1 and row <= vim.fn.line("$") then
|
if row > 1 and row <= vim.fn.line("$") then
|
||||||
-- 排除特定文件类型
|
-- 排除特定文件类型
|
||||||
if ft ~= "commit" and ft ~= "gitcommit" and not ft:match("xxd") and not ft:match("gitrebase") then
|
if ft ~= "commit" and ft ~= "gitcommit" and not ft:match("xxd") and not ft:match("gitrebase") then
|
||||||
vim.api.nvim_win_set_cursor(0, mark)
|
vim.api.nvim_win_set_cursor(0, mark)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -52,15 +51,14 @@ vim.api.nvim_create_autocmd("BufReadPost", {
|
|||||||
-- r - 按回车时延续注释(保留,insert 模式下回车延续注释符)
|
-- r - 按回车时延续注释(保留,insert 模式下回车延续注释符)
|
||||||
--
|
--
|
||||||
-- 注意:此设置对自动格式化(conform.nvim)的行为也有影响。
|
-- 注意:此设置对自动格式化(conform.nvim)的行为也有影响。
|
||||||
|
|
||||||
vim.api.nvim_create_autocmd("FileType", {
|
vim.api.nvim_create_autocmd("FileType", {
|
||||||
group = group,
|
group = group,
|
||||||
callback = function()
|
callback = function()
|
||||||
-- 移除 'o':按 o/O 时不自动插入注释符号
|
-- 移除 'o':按 o/O 时不自动插入注释符号
|
||||||
vim.opt_local.formatoptions:remove("o")
|
vim.opt_local.formatoptions:remove("o")
|
||||||
-- 追加 'r':按回车时自动插入注释符号
|
-- 追加 'r':按回车时自动插入注释符号
|
||||||
vim.opt_local.formatoptions:append("r")
|
vim.opt_local.formatoptions:append("r")
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -73,12 +71,11 @@ vim.api.nvim_create_autocmd("FileType", {
|
|||||||
-- foldmethod = "expr" 表示使用表达式(foldexpr)计算折叠范围。
|
-- foldmethod = "expr" 表示使用表达式(foldexpr)计算折叠范围。
|
||||||
-- foldexpr = "v:lua.vim.treesitter.foldexpr()" 是 Neovim 0.10+ 的内置函数,
|
-- foldexpr = "v:lua.vim.treesitter.foldexpr()" 是 Neovim 0.10+ 的内置函数,
|
||||||
-- 基于 treesitter 语法树计算折叠边界。
|
-- 基于 treesitter 语法树计算折叠边界。
|
||||||
|
|
||||||
vim.api.nvim_create_autocmd("BufEnter", {
|
vim.api.nvim_create_autocmd("BufEnter", {
|
||||||
group = group,
|
group = group,
|
||||||
once = true,
|
once = true,
|
||||||
callback = function()
|
callback = function()
|
||||||
vim.o.foldmethod = "expr"
|
vim.o.foldmethod = "expr"
|
||||||
vim.o.foldexpr = "v:lua.vim.treesitter.foldexpr()"
|
vim.o.foldexpr = "v:lua.vim.treesitter.foldexpr()"
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|||||||
202
lua/git.lua
202
lua/git.lua
@ -1,202 +0,0 @@
|
|||||||
-- =============================================================================
|
|
||||||
-- Git 工具封装 (lua/git.lua)
|
|
||||||
-- =============================================================================
|
|
||||||
-- 本模块提供基于 mini.diff 和原生 git 命令的 Git 相关功能。
|
|
||||||
--
|
|
||||||
-- 功能列表:
|
|
||||||
-- 1. Hunk Preview(<leader>ghp)— 预览当前光标处 git diff hunk
|
|
||||||
-- 2. Blame Line(<leader>ghb)— 查看当前行的 git blame 信息
|
|
||||||
-- 3. Blame Buffer(<leader>gB)— 整文件 blame(via fugitive)
|
|
||||||
-- 4. File History(<leader>gD)— 查看当前文件的 git log
|
|
||||||
--
|
|
||||||
-- 依赖:
|
|
||||||
-- - mini.diff(已在 pack.lua 中通过 BufReadPost 懒加载)
|
|
||||||
-- - vim-fugitive(已在 pack.lua 中通过按键触发懒加载)
|
|
||||||
-- =============================================================================
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- 辅助函数:获取光标所在行的 hunk
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- 遍历当前 buffer 的所有 hunks,找到包含光标所在行的那个。
|
|
||||||
--
|
|
||||||
-- 返回值:
|
|
||||||
-- hunk - hunk 对象 { type, buf_start, buf_count, ref_start, ref_count }
|
|
||||||
-- ref_text - 参考文本(HEAD 版本的内容)
|
|
||||||
-- nil - 光标不在任何 hunk 上
|
|
||||||
|
|
||||||
local function get_cursor_hunk()
|
|
||||||
local buf = vim.api.nvim_get_current_buf()
|
|
||||||
-- 从 mini.diff 获取当前 buffer 的 diff 数据
|
|
||||||
local data = require("mini.diff").get_buf_data(buf)
|
|
||||||
if not data or not data.hunks or #data.hunks == 0 then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local cursor_line = vim.api.nvim_win_get_cursor(0)[1]
|
|
||||||
|
|
||||||
for _, h in ipairs(data.hunks) do
|
|
||||||
-- hunk 在 buffer 中的起始行(1-based)
|
|
||||||
local start_line = math.max(h.buf_start, 1)
|
|
||||||
-- hunk 在 buffer 中的结束行
|
|
||||||
local end_line = h.buf_start + h.buf_count - 1
|
|
||||||
-- 空删除(0 行)时特殊处理
|
|
||||||
if h.buf_count == 0 then
|
|
||||||
end_line = start_line
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 检查光标是否在此 hunk 范围内
|
|
||||||
if cursor_line >= start_line and cursor_line <= end_line then
|
|
||||||
return h, data.ref_text
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- Hunk Preview — 浮动窗口预览当前 hunk
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- 创建一个居中的浮动窗口,显示光标所在 hunk 的详细 diff 信息。
|
|
||||||
-- 支持三种 hunk 类型:
|
|
||||||
-- add — 显示新增的行
|
|
||||||
-- delete — 显示被删除的行(从参考文本中恢复)
|
|
||||||
-- change — 并排显示修改前后的内容
|
|
||||||
|
|
||||||
local function preview_hunk()
|
|
||||||
local hunk, ref_text = get_cursor_hunk()
|
|
||||||
if not hunk then
|
|
||||||
vim.notify("光标不在变更区域", vim.log.levels.WARN)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 构建预览内容
|
|
||||||
local lines = {}
|
|
||||||
table.insert(lines, "Hunk 类型: " .. hunk.type)
|
|
||||||
table.insert(lines, string.format("Buffer 行: %d-%d", hunk.buf_start, hunk.buf_start + hunk.buf_count - 1))
|
|
||||||
table.insert(lines, string.format("参考行: %d-%d", hunk.ref_start, hunk.ref_start + hunk.ref_count - 1))
|
|
||||||
table.insert(lines, "---")
|
|
||||||
|
|
||||||
local buf = vim.api.nvim_get_current_buf()
|
|
||||||
local ref_lines = vim.split(ref_text or "", "\n")
|
|
||||||
|
|
||||||
if hunk.type == "delete" then
|
|
||||||
-- 删除型 hunk:显示被删除的内容(来自参考文本)
|
|
||||||
table.insert(lines, "被删除的行(来自参考版本):")
|
|
||||||
for i = hunk.ref_start, hunk.ref_start + hunk.ref_count - 1 do
|
|
||||||
table.insert(lines, "- " .. (ref_lines[i] or ""))
|
|
||||||
end
|
|
||||||
elseif hunk.type == "add" then
|
|
||||||
-- 新增型 hunk:显示 buffer 中新增的内容
|
|
||||||
table.insert(lines, "新增的行:")
|
|
||||||
for i = hunk.buf_start, hunk.buf_start + hunk.buf_count - 1 do
|
|
||||||
table.insert(lines, "+ " .. (vim.api.nvim_buf_get_lines(buf, i - 1, i, false)[1] or ""))
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- 修改型 hunk:显示修改前后的对比
|
|
||||||
table.insert(lines, "修改前(参考版本):")
|
|
||||||
for i = hunk.ref_start, hunk.ref_start + hunk.ref_count - 1 do
|
|
||||||
table.insert(lines, "- " .. (ref_lines[i] or ""))
|
|
||||||
end
|
|
||||||
table.insert(lines, "修改后(当前版本):")
|
|
||||||
for i = hunk.buf_start, hunk.buf_start + hunk.buf_count - 1 do
|
|
||||||
table.insert(lines, "+ " .. (vim.api.nvim_buf_get_lines(buf, i - 1, i, false)[1] or ""))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 计算浮动窗口尺寸
|
|
||||||
local width = math.min(80, vim.o.columns - 4)
|
|
||||||
local height = math.min(#lines + 2, vim.o.lines - 4)
|
|
||||||
|
|
||||||
-- 创建预览 buffer
|
|
||||||
local preview_buf = vim.api.nvim_create_buf(false, true) -- 无文件、可编辑
|
|
||||||
vim.api.nvim_buf_set_lines(preview_buf, 0, -1, false, lines)
|
|
||||||
vim.api.nvim_set_option_value("modifiable", false, { buf = preview_buf })
|
|
||||||
vim.api.nvim_set_option_value("filetype", "diff", { buf = preview_buf }) -- diff 语法高亮
|
|
||||||
|
|
||||||
-- 打开浮动窗口
|
|
||||||
local win = vim.api.nvim_open_win(preview_buf, true, {
|
|
||||||
relative = "editor",
|
|
||||||
row = math.floor((vim.o.lines - height) / 2),
|
|
||||||
col = math.floor((vim.o.columns - width) / 2),
|
|
||||||
width = width,
|
|
||||||
height = height,
|
|
||||||
style = "minimal",
|
|
||||||
border = "rounded",
|
|
||||||
title = " Hunk Preview ",
|
|
||||||
title_pos = "center",
|
|
||||||
})
|
|
||||||
|
|
||||||
-- q / Esc 关闭窗口
|
|
||||||
vim.keymap.set("n", "q", function()
|
|
||||||
vim.api.nvim_win_close(win, true)
|
|
||||||
end, { buffer = preview_buf })
|
|
||||||
vim.keymap.set("n", "<Esc>", function()
|
|
||||||
vim.api.nvim_win_close(win, true)
|
|
||||||
end, { buffer = preview_buf })
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- Blame Line — 查看当前行的 Git blame 信息
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- 执行 git blame --porcelain 获取当前行的详细提交信息,
|
|
||||||
-- 以通知消息的形式展示提交哈希、作者、时间和提交摘要。
|
|
||||||
--
|
|
||||||
-- --porcelain 格式是机器可读的 blame 输出,包含以下字段:
|
|
||||||
-- <hash> <orig-line> <final-line> [<num-lines>]
|
|
||||||
-- author <name>
|
|
||||||
-- author-mail <email>
|
|
||||||
-- author-time <timestamp>
|
|
||||||
-- author-tz <timezone>
|
|
||||||
-- summary <commit-message>
|
|
||||||
-- ...
|
|
||||||
|
|
||||||
local function blame_line()
|
|
||||||
local file = vim.api.nvim_buf_get_name(0)
|
|
||||||
if file == "" then
|
|
||||||
vim.notify("当前 buffer 无文件名", vim.log.levels.WARN)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local line = vim.api.nvim_win_get_cursor(0)[1]
|
|
||||||
-- -L 限制 blame 范围为单行,提升性能
|
|
||||||
local cmd = { "git", "blame", "-L", line .. "," .. line, "--porcelain", file }
|
|
||||||
local output = vim.fn.system(cmd)
|
|
||||||
|
|
||||||
if vim.v.shell_error ~= 0 then
|
|
||||||
vim.notify("git blame 执行失败", vim.log.levels.ERROR)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 解析 --porcelain 输出
|
|
||||||
local hash = output:match("^(%x+)%s") or "?"
|
|
||||||
local author = output:match("author ([^\n]+)") or "?"
|
|
||||||
local email = output:match("author%-mail ([^\n]+)") or "?"
|
|
||||||
local time = output:match("author%-time (%d+)")
|
|
||||||
local summary = output:match("summary ([^\n]+)") or "?"
|
|
||||||
local time_str = time and os.date("%Y-%m-%d %H:%M", tonumber(time)) or "?"
|
|
||||||
|
|
||||||
vim.notify(
|
|
||||||
string.format("%s | %s %s | %s\n%s", hash:sub(1, 8), author, email, time_str, summary),
|
|
||||||
vim.log.levels.INFO
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- 键位映射
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-- <leader>ghp — 预览当前 hunk
|
|
||||||
vim.keymap.set("n", "<leader>ghp", preview_hunk, { desc = "预览 hunk" })
|
|
||||||
|
|
||||||
-- <leader>ghb — 查看当前行 blame
|
|
||||||
vim.keymap.set("n", "<leader>ghb", blame_line, { desc = "Blame 当前行" })
|
|
||||||
|
|
||||||
-- <leader>gB — 整文件 blame(使用 fugitive 的 :Git blame)
|
|
||||||
vim.keymap.set("n", "<leader>gB", function()
|
|
||||||
vim.cmd("Git blame")
|
|
||||||
end, { desc = "Blame 整个文件" })
|
|
||||||
|
|
||||||
-- <leader>gD — 查看当前文件的 git 历史
|
|
||||||
vim.keymap.set("n", "<leader>gD", function()
|
|
||||||
vim.cmd("Git log -p -- %")
|
|
||||||
end, { desc = "查看文件 Git 历史" })
|
|
||||||
@ -76,7 +76,6 @@ map("v", "<", "<gv")
|
|||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- Neovim 0.12+ 内置了 undotree 插件(nvim.undotree)。
|
-- Neovim 0.12+ 内置了 undotree 插件(nvim.undotree)。
|
||||||
-- 这里通过 packadd 按需加载并打开。
|
-- 这里通过 packadd 按需加载并打开。
|
||||||
|
|
||||||
vim.keymap.set("n", "<leader>u", function()
|
vim.keymap.set("n", "<leader>u", function()
|
||||||
vim.cmd.packadd("nvim.undotree")
|
vim.cmd.packadd("nvim.undotree")
|
||||||
require("undotree").open()
|
require("undotree").open()
|
||||||
@ -107,7 +106,6 @@ map("n", "<leader>tt", ":term<CR>", { desc = "打开新终端" })
|
|||||||
-- 窗口导航
|
-- 窗口导航
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 使用 <C-h/j/k/l> 在窗口间快速跳转,替代 <C-w> h/j/k/l 的繁琐操作。
|
-- 使用 <C-h/j/k/l> 在窗口间快速跳转,替代 <C-w> h/j/k/l 的繁琐操作。
|
||||||
|
|
||||||
map("n", "<C-h>", "<C-w>h", { desc = "切换到左侧窗口" })
|
map("n", "<C-h>", "<C-w>h", { desc = "切换到左侧窗口" })
|
||||||
map("n", "<C-j>", "<C-w>j", { desc = "切换到下方窗口" })
|
map("n", "<C-j>", "<C-w>j", { desc = "切换到下方窗口" })
|
||||||
map("n", "<C-k>", "<C-w>k", { desc = "切换到上方窗口" })
|
map("n", "<C-k>", "<C-w>k", { desc = "切换到上方窗口" })
|
||||||
@ -116,7 +114,6 @@ map("n", "<C-l>", "<C-w>l", { desc = "切换到右侧窗口" })
|
|||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- Tab 管理
|
-- Tab 管理
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
map("n", "<leader>tc", ":tabclose<CR>", { desc = "关闭当前标签页" })
|
map("n", "<leader>tc", ":tabclose<CR>", { desc = "关闭当前标签页" })
|
||||||
map("n", "<leader>tn", ":tabnew<CR>", { desc = "新建标签页" })
|
map("n", "<leader>tn", ":tabnew<CR>", { desc = "新建标签页" })
|
||||||
map("n", "<leader>]", ":tabnext<CR>", { desc = "下一个标签页" })
|
map("n", "<leader>]", ":tabnext<CR>", { desc = "下一个标签页" })
|
||||||
@ -125,7 +122,6 @@ map("n", "<leader>[", ":tabprevious<CR>", { desc = "上一个标签页" })
|
|||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 复制文件路径
|
-- 复制文件路径
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
-- 复制当前文件的相对路径到系统剪贴板
|
-- 复制当前文件的相对路径到系统剪贴板
|
||||||
map("n", "<leader>yp", function()
|
map("n", "<leader>yp", function()
|
||||||
local path = vim.fn.expand("%")
|
local path = vim.fn.expand("%")
|
||||||
@ -143,7 +139,6 @@ end, { desc = "复制绝对文件路径" })
|
|||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- Buffer 管理
|
-- Buffer 管理
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
-- 关闭当前 Buffer,有未保存更改时提示确认。
|
-- 关闭当前 Buffer,有未保存更改时提示确认。
|
||||||
-- 使用 vim.ui.select 提供交互式选择对话框。
|
-- 使用 vim.ui.select 提供交互式选择对话框。
|
||||||
map("n", "<leader>x", function()
|
map("n", "<leader>x", function()
|
||||||
|
|||||||
46
lua/lazy.lua
46
lua/lazy.lua
@ -34,18 +34,18 @@ M._loaded = {}
|
|||||||
-- 使用场景:
|
-- 使用场景:
|
||||||
-- 在按键回调中手动触发加载,或在 on_event 回调中延迟初始化。
|
-- 在按键回调中手动触发加载,或在 on_event 回调中延迟初始化。
|
||||||
M.load = function(name, fn)
|
M.load = function(name, fn)
|
||||||
if M._loaded[name] then
|
if M._loaded[name] then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
M._loaded[name] = true
|
M._loaded[name] = true
|
||||||
if fn then
|
if fn then
|
||||||
fn()
|
fn()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- 仅标记模块为已加载,不执行 setup(用于直接加载的插件)。
|
-- 仅标记模块为已加载,不执行 setup(用于直接加载的插件)。
|
||||||
M.track = function(name)
|
M.track = function(name)
|
||||||
M._loaded[name] = true
|
M._loaded[name] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -67,13 +67,13 @@ end
|
|||||||
-- require("mini.completion").setup({ ... })
|
-- require("mini.completion").setup({ ... })
|
||||||
-- end)
|
-- end)
|
||||||
M.on_event = function(name, event, pattern, fn)
|
M.on_event = function(name, event, pattern, fn)
|
||||||
vim.api.nvim_create_autocmd(event, {
|
vim.api.nvim_create_autocmd(event, {
|
||||||
pattern = pattern or "*",
|
pattern = pattern or "*",
|
||||||
once = true,
|
once = true,
|
||||||
callback = function()
|
callback = function()
|
||||||
M.load(name, fn)
|
M.load(name, fn)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -97,14 +97,14 @@ end
|
|||||||
-- 此设计使得首次按键稍慢(需要 setup),后续按键与直接映射无异。
|
-- 此设计使得首次按键稍慢(需要 setup),后续按键与直接映射无异。
|
||||||
-- 适合重型插件如 mini.pick、vim-fugitive。
|
-- 适合重型插件如 mini.pick、vim-fugitive。
|
||||||
M.on_keys = function(name, keys, mode, fn, action, opts)
|
M.on_keys = function(name, keys, mode, fn, action, opts)
|
||||||
mode = mode or "n"
|
mode = mode or "n"
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
vim.keymap.set(mode, keys, function()
|
vim.keymap.set(mode, keys, function()
|
||||||
M.load(name, fn)
|
M.load(name, fn)
|
||||||
if action then
|
if action then
|
||||||
action()
|
action()
|
||||||
end
|
end
|
||||||
end, { desc = opts.desc, buffer = opts.buffer })
|
end, { desc = opts.desc, buffer = opts.buffer })
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
@ -19,64 +19,57 @@ vim.g.netrw_banner = 0
|
|||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 1. 界面显示
|
-- 1. 界面显示
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
vim.opt.nu = true -- 显示绝对行号
|
||||||
vim.opt.nu = true -- 显示绝对行号
|
vim.opt.relativenumber = true -- 显示相对行号(便于配合数字 + j/k 跳转)
|
||||||
vim.opt.relativenumber = true -- 显示相对行号(便于配合数字 + j/k 跳转)
|
vim.opt.cursorline = true -- 高亮当前行
|
||||||
vim.opt.cursorline = true -- 高亮当前行
|
vim.opt.cursorlineopt = "both" -- 高亮当前行的行号和文本行(number + line)
|
||||||
vim.opt.cursorlineopt = "both" -- 高亮当前行的行号和文本行(number + line)
|
vim.opt.autoread = true -- 当文件被外部修改时自动重新读取
|
||||||
vim.opt.autoread = true -- 当文件被外部修改时自动重新读取
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 2. 缩进与格式化
|
-- 2. 缩进与格式化
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 使用 4 空格缩进,适用于大多数语言。
|
-- 使用 4 空格缩进,适用于大多数语言。
|
||||||
-- 特定语言的缩进设置(如 JS/TS 的 2 空格)应在 ftplugin 中覆盖。
|
-- 特定语言的缩进设置(如 JS/TS 的 2 空格)应在 ftplugin 中覆盖。
|
||||||
|
vim.opt.tabstop = 4 -- Tab 键显示的宽度(字符数)
|
||||||
|
vim.opt.softtabstop = 4 -- 插入模式下 Tab/BS 的行为宽度
|
||||||
|
vim.opt.shiftwidth = 4 -- 自动缩进和 >/< 操作的宽度
|
||||||
|
vim.opt.expandtab = true -- 将 Tab 键转换为空格
|
||||||
|
|
||||||
vim.opt.tabstop = 4 -- Tab 键显示的宽度(字符数)
|
vim.opt.smartindent = true -- 基于语法的智能缩进(C-style 语言效果最佳)
|
||||||
vim.opt.softtabstop = 4 -- 插入模式下 Tab/BS 的行为宽度
|
vim.opt.inccommand = "split" -- 实时预览替换效果(:s 命令在分屏中显示预览)
|
||||||
vim.opt.shiftwidth = 4 -- 自动缩进和 >/< 操作的宽度
|
|
||||||
vim.opt.expandtab = true -- 将 Tab 键转换为空格
|
|
||||||
|
|
||||||
vim.opt.smartindent = true -- 基于语法的智能缩进(C-style 语言效果最佳)
|
|
||||||
vim.opt.inccommand = "split" -- 实时预览替换效果(:s 命令在分屏中显示预览)
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 3. 窗口与分割
|
-- 3. 窗口与分割
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
vim.opt.splitbelow = true -- 水平分割时新窗口在下方
|
||||||
vim.opt.splitbelow = true -- 水平分割时新窗口在下方
|
vim.opt.splitright = true -- 垂直分割时新窗口在右侧
|
||||||
vim.opt.splitright = true -- 垂直分割时新窗口在右侧
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 4. 搜索行为
|
-- 4. 搜索行为
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
vim.opt.ignorecase = true -- 搜索时忽略大小写
|
||||||
vim.opt.ignorecase = true -- 搜索时忽略大小写
|
vim.opt.smartcase = true -- 如果搜索包含大写字母,则区分大小写
|
||||||
vim.opt.smartcase = true -- 如果搜索包含大写字母,则区分大小写
|
-- 与 ignorecase 配合:全小写时忽略大小写,
|
||||||
-- 与 ignorecase 配合:全小写时忽略大小写,
|
-- 包含大写时精确匹配
|
||||||
-- 包含大写时精确匹配
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 5. 状态栏
|
-- 5. 状态栏
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
vim.opt.laststatus = 3 -- 全局状态栏(所有窗口共享一个状态栏)
|
||||||
vim.opt.laststatus = 3 -- 全局状态栏(所有窗口共享一个状态栏)
|
-- 值为 2 时每个窗口有独立状态栏
|
||||||
-- 值为 2 时每个窗口有独立状态栏
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 6. 文件持久化
|
-- 6. 文件持久化
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 禁用 swap 和 backup 文件,使用 undofile 实现跨会话的撤销历史。
|
-- 禁用 swap 和 backup 文件,使用 undofile 实现跨会话的撤销历史。
|
||||||
|
vim.opt.swapfile = false -- 禁用交换文件(.swp)
|
||||||
vim.opt.swapfile = false -- 禁用交换文件(.swp)
|
vim.opt.backup = false -- 禁用备份文件(~ 后缀)
|
||||||
vim.opt.backup = false -- 禁用备份文件(~ 后缀)
|
vim.opt.undodir = vim.fn.stdpath("data") .. "/undodir" -- 撤销历史存放目录
|
||||||
vim.opt.undodir = vim.fn.stdpath("data") .. "/undodir" -- 撤销历史存放目录
|
vim.opt.undofile = true -- 启用持久化撤销(关闭文件后仍能撤销)
|
||||||
vim.opt.undofile = true -- 启用持久化撤销(关闭文件后仍能撤销)
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 7. 补全与消息
|
-- 7. 补全与消息
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
-- 补全选项:
|
-- 补全选项:
|
||||||
-- menuone - 即使只有一个匹配项也显示菜单
|
-- menuone - 即使只有一个匹配项也显示菜单
|
||||||
-- noselect - 不自动选择第一项(需手动选择)
|
-- noselect - 不自动选择第一项(需手动选择)
|
||||||
@ -96,13 +89,12 @@ vim.opt.shortmess:append("c")
|
|||||||
-- 通过 vim.schedule() 将剪贴板设置推迟到启动事件循环之后,
|
-- 通过 vim.schedule() 将剪贴板设置推迟到启动事件循环之后,
|
||||||
-- 避免阻塞 startup 的关键路径。
|
-- 避免阻塞 startup 的关键路径。
|
||||||
vim.schedule(function()
|
vim.schedule(function()
|
||||||
vim.opt.clipboard:append("unnamedplus")
|
vim.opt.clipboard:append("unnamedplus")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 9. 其他杂项
|
-- 9. 其他杂项
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
-- 将 @ 和 - 视为文件名的一部分(用于 gf/gx 等命令)
|
-- 将 @ 和 - 视为文件名的一部分(用于 gf/gx 等命令)
|
||||||
vim.opt.isfname:append("@-@")
|
vim.opt.isfname:append("@-@")
|
||||||
|
|
||||||
@ -123,8 +115,7 @@ vim.opt.termguicolors = true
|
|||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 将 mini.diff 的符号高亮组链接到标准 diff 高亮组,
|
-- 将 mini.diff 的符号高亮组链接到标准 diff 高亮组,
|
||||||
-- 使 git diff 的添加/修改/删除标记使用 colorscheme 定义的配色。
|
-- 使 git diff 的添加/修改/删除标记使用 colorscheme 定义的配色。
|
||||||
|
vim.api.nvim_set_hl(0, "MiniDiffSignAdd", { link = "DiffAdd" }) -- 添加的行
|
||||||
vim.api.nvim_set_hl(0, "MiniDiffSignAdd", { link = "DiffAdd" }) -- 添加的行
|
|
||||||
vim.api.nvim_set_hl(0, "MiniDiffSignChange", { link = "DiffChange" }) -- 修改的行
|
vim.api.nvim_set_hl(0, "MiniDiffSignChange", { link = "DiffChange" }) -- 修改的行
|
||||||
vim.api.nvim_set_hl(0, "MiniDiffSignDelete", { link = "DiffDelete" }) -- 删除的行
|
vim.api.nvim_set_hl(0, "MiniDiffSignDelete", { link = "DiffDelete" }) -- 删除的行
|
||||||
|
|
||||||
@ -134,12 +125,11 @@ vim.api.nvim_set_hl(0, "MiniDiffSignDelete", { link = "DiffDelete" }) -- 删除
|
|||||||
-- 复制文本时短暂高亮被复制的区域,提供视觉反馈。
|
-- 复制文本时短暂高亮被复制的区域,提供视觉反馈。
|
||||||
-- vim.hl.on_yank() 是 Neovim 0.11+ 的内置函数,
|
-- vim.hl.on_yank() 是 Neovim 0.11+ 的内置函数,
|
||||||
-- 旧版使用 vim.highlight.on_yank()。
|
-- 旧版使用 vim.highlight.on_yank()。
|
||||||
|
|
||||||
vim.api.nvim_create_autocmd("TextYankPost", {
|
vim.api.nvim_create_autocmd("TextYankPost", {
|
||||||
desc = "复制文本时高亮被复制的区域",
|
desc = "复制文本时高亮被复制的区域",
|
||||||
callback = function()
|
callback = function()
|
||||||
vim.hl.on_yank()
|
vim.hl.on_yank()
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
|||||||
451
lua/pack.lua
451
lua/pack.lua
@ -24,17 +24,17 @@
|
|||||||
-- =============================================================================
|
-- =============================================================================
|
||||||
|
|
||||||
local lazy = require("lazy")
|
local lazy = require("lazy")
|
||||||
local pick = require("pick")
|
local pick = require("plugins.pick")
|
||||||
require("git")
|
require("plugins.git")
|
||||||
|
|
||||||
-- 在 VimEnter 时记录完整启动时间(此时 runtime 插件、ShaDa 等已加载完毕),
|
-- 在 VimEnter 时记录完整启动时间(此时 runtime 插件、ShaDa 等已加载完毕),
|
||||||
-- 使启动页显示的耗时更接近 --startuptime 的口径。
|
-- 使启动页显示的耗时更接近 --startuptime 的口径。
|
||||||
-- starter 的 autoopen 在 VimEnter 之后渲染,footer 可以安全读取此值。
|
-- starter 的 autoopen 在 VimEnter 之后渲染,footer 可以安全读取此值。
|
||||||
vim.api.nvim_create_autocmd("VimEnter", {
|
vim.api.nvim_create_autocmd("VimEnter", {
|
||||||
once = true,
|
once = true,
|
||||||
callback = function()
|
callback = function()
|
||||||
_G.nvim_vimenter_done = (vim.uv or vim.loop).hrtime()
|
_G.nvim_vimenter_done = (vim.uv or vim.loop).hrtime()
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -43,16 +43,15 @@ vim.api.nvim_create_autocmd("VimEnter", {
|
|||||||
-- vim.pack.add(urls, { load = false }) 将插件下载到 pack 目录,
|
-- vim.pack.add(urls, { load = false }) 将插件下载到 pack 目录,
|
||||||
-- 但不自动加载(load = false)。后续通过 packadd 或 require 按需加载。
|
-- 但不自动加载(load = false)。后续通过 packadd 或 require 按需加载。
|
||||||
-- 所有插件的状态锁定在 nvim-pack-lock.json 中。
|
-- 所有插件的状态锁定在 nvim-pack-lock.json 中。
|
||||||
|
|
||||||
vim.pack.add({
|
vim.pack.add({
|
||||||
"https://github.com/nvim-mini/mini.nvim", -- 核心 UI/功能插件集
|
"https://github.com/nvim-mini/mini.nvim", -- 核心 UI/功能插件集
|
||||||
"https://github.com/rafamadriz/friendly-snippets", -- 代码片段库
|
"https://github.com/rafamadriz/friendly-snippets", -- 代码片段库
|
||||||
{ src = "https://github.com/nvim-treesitter/nvim-treesitter", branch = "main" }, -- 语法树
|
{ src = "https://github.com/nvim-treesitter/nvim-treesitter", branch = "main" }, -- 语法树
|
||||||
"https://github.com/neovim/nvim-lspconfig", -- LSP 配置
|
"https://github.com/neovim/nvim-lspconfig", -- LSP 配置
|
||||||
"https://github.com/mason-org/mason.nvim", -- 工具安装器
|
"https://github.com/mason-org/mason.nvim", -- 工具安装器
|
||||||
"https://github.com/stevearc/conform.nvim", -- 格式化
|
"https://github.com/stevearc/conform.nvim", -- 格式化
|
||||||
"https://github.com/tpope/vim-fugitive", -- Git 集成
|
"https://github.com/tpope/vim-fugitive", -- Git 集成
|
||||||
"https://github.com/MagicDuck/grug-far.nvim", -- 搜索替换
|
"https://github.com/MagicDuck/grug-far.nvim", -- 搜索替换
|
||||||
}, { load = false })
|
}, { load = false })
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -63,32 +62,32 @@ vim.pack.add({
|
|||||||
|
|
||||||
-- ASCII art 集合(用于启动页等展示)
|
-- ASCII art 集合(用于启动页等展示)
|
||||||
local logs = {
|
local logs = {
|
||||||
a = {
|
a = {
|
||||||
"⣇⣿⠘⣿⣿⣿⡿⡿⣟⣟⢟⢟⢝⠵⡝⣿⡿⢂⣼⣿⣷⣌⠩⡫⡻⣝⠹⢿⣿⣷",
|
"⣇⣿⠘⣿⣿⣿⡿⡿⣟⣟⢟⢟⢝⠵⡝⣿⡿⢂⣼⣿⣷⣌⠩⡫⡻⣝⠹⢿⣿⣷",
|
||||||
"⡆⣿⣆⠱⣝⡵⣝⢅⠙⣿⢕⢕⢕⢕⢝⣥⢒⠅⣿⣿⣿⡿⣳⣌⠪⡪⣡⢑⢝⣇",
|
"⡆⣿⣆⠱⣝⡵⣝⢅⠙⣿⢕⢕⢕⢕⢝⣥⢒⠅⣿⣿⣿⡿⣳⣌⠪⡪⣡⢑⢝⣇",
|
||||||
"⡆⣿⣿⣦⠹⣳⣳⣕⢅⠈⢗⢕⢕⢕⢕⢕⢈⢆⠟⠋⠉⠁⠉⠉⠁⠈⠼⢐⢕⢽",
|
"⡆⣿⣿⣦⠹⣳⣳⣕⢅⠈⢗⢕⢕⢕⢕⢕⢈⢆⠟⠋⠉⠁⠉⠉⠁⠈⠼⢐⢕⢽",
|
||||||
"⡗⢰⣶⣶⣦⣝⢝⢕⢕⠅⡆⢕⢕⢕⢕⢕⣴⠏⣠⡶⠛⡉⡉⡛⢶⣦⡀⠐⣕⢕",
|
"⡗⢰⣶⣶⣦⣝⢝⢕⢕⠅⡆⢕⢕⢕⢕⢕⣴⠏⣠⡶⠛⡉⡉⡛⢶⣦⡀⠐⣕⢕",
|
||||||
"⡝⡄⢻⢟⣿⣿⣷⣕⣕⣅⣿⣔⣕⣵⣵⣿⣿⢠⣿⢠⣮⡈⣌⠨⠅⠹⣷⡀⢱⢕",
|
"⡝⡄⢻⢟⣿⣿⣷⣕⣕⣅⣿⣔⣕⣵⣵⣿⣿⢠⣿⢠⣮⡈⣌⠨⠅⠹⣷⡀⢱⢕",
|
||||||
"⡝⡵⠟⠈⢀⣀⣀⡀⠉⢿⣿⣿⣿⣿⣿⣿⣿⣼⣿⢈⡋⠴⢿⡟⣡⡇⣿⡇⡀⢕",
|
"⡝⡵⠟⠈⢀⣀⣀⡀⠉⢿⣿⣿⣿⣿⣿⣿⣿⣼⣿⢈⡋⠴⢿⡟⣡⡇⣿⡇⡀⢕",
|
||||||
"⡝⠁⣠⣾⠟⡉⡉⡉⠻⣦⣻⣿⣿⣿⣿⣿⣿⣿⣿⣧⠸⣿⣦⣥⣿⡇⡿⣰⢗⢄",
|
"⡝⠁⣠⣾⠟⡉⡉⡉⠻⣦⣻⣿⣿⣿⣿⣿⣿⣿⣿⣧⠸⣿⣦⣥⣿⡇⡿⣰⢗⢄",
|
||||||
"⠁⢰⣿⡏⣴⣌⠈⣌⠡⠈⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣬⣉⣉⣁⣄⢖⢕⢕⢕",
|
"⠁⢰⣿⡏⣴⣌⠈⣌⠡⠈⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣬⣉⣉⣁⣄⢖⢕⢕⢕",
|
||||||
"⡀⢻⣿⡇⢙⠁⠴⢿⡟⣡⡆⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣵⣵⣿",
|
"⡀⢻⣿⡇⢙⠁⠴⢿⡟⣡⡆⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣵⣵⣿",
|
||||||
"⡻⣄⣻⣿⣌⠘⢿⣷⣥⣿⠇⣿⣿⣿⣿⣿⣿⠛⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
"⡻⣄⣻⣿⣌⠘⢿⣷⣥⣿⠇⣿⣿⣿⣿⣿⣿⠛⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
||||||
"⣷⢄⠻⣿⣟⠿⠦⠍⠉⣡⣾⣿⣿⣿⣿⣿⣿⢸⣿⣦⠙⣿⣿⣿⣿⣿⣿⣿⣿⠟",
|
"⣷⢄⠻⣿⣟⠿⠦⠍⠉⣡⣾⣿⣿⣿⣿⣿⣿⢸⣿⣦⠙⣿⣿⣿⣿⣿⣿⣿⣿⠟",
|
||||||
"⡕⡑⣑⣈⣻⢗⢟⢞⢝⣻⣿⣿⣿⣿⣿⣿⣿⠸⣿⠿⠃⣿⣿⣿⣿⣿⣿⡿⠁⣠",
|
"⡕⡑⣑⣈⣻⢗⢟⢞⢝⣻⣿⣿⣿⣿⣿⣿⣿⠸⣿⠿⠃⣿⣿⣿⣿⣿⣿⡿⠁⣠",
|
||||||
"⡝⡵⡈⢟⢕⢕⢕⢕⣵⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣿⣿⣿⣿⣿⠿⠋⣀⣈⠙",
|
"⡝⡵⡈⢟⢕⢕⢕⢕⣵⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣿⣿⣿⣿⣿⠿⠋⣀⣈⠙",
|
||||||
"⡝⡵⡕⡀⠑⠳⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⢉⡠⡲⡫⡪⡪⡣",
|
"⡝⡵⡕⡀⠑⠳⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⢉⡠⡲⡫⡪⡪⡣",
|
||||||
},
|
},
|
||||||
b = {
|
b = {
|
||||||
"░▒▓███████▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░ ",
|
"░▒▓███████▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░ ",
|
||||||
"░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░",
|
"░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░",
|
||||||
"░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░",
|
"░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░",
|
||||||
"░▒▓███████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓████████▓▒░",
|
"░▒▓███████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓████████▓▒░",
|
||||||
"░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░",
|
"░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░",
|
||||||
"░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░",
|
"░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░",
|
||||||
"░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░",
|
"░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░",
|
||||||
},
|
},
|
||||||
c = [[
|
c = [[
|
||||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
||||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⣠⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⣠⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
||||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣡⣾⣿⣿⣿⣿⣿⢿⣿⣿⣿⣿⣿⣿⣟⠻⣿⣿⣿⣿⣿⣿⣿⣿
|
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣡⣾⣿⣿⣿⣿⣿⢿⣿⣿⣿⣿⣿⣿⣟⠻⣿⣿⣿⣿⣿⣿⣿⣿
|
||||||
@ -108,52 +107,52 @@ local logs = {
|
|||||||
⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣀⡆⣠⢀⣴⣏⡀⠀⠀⠀⠉⠀⠀⢀⣠⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣀⡆⣠⢀⣴⣏⡀⠀⠀⠀⠉⠀⠀⢀⣠⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
||||||
⠿⠛⠛⠛⠛⠛⠛⠻⢿⣿⣿⣿⣿⣯⣟⠷⢷⣿⡿⠋⠀⠀⠀⠀⣵⡀⢠⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
⠿⠛⠛⠛⠛⠛⠛⠻⢿⣿⣿⣿⣿⣯⣟⠷⢷⣿⡿⠋⠀⠀⠀⠀⣵⡀⢠⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠛⢿⣿⣿⠂⠀⠀⠀⠀⠀⢀⣽⣿⣿⣿⣿⣿⣿⣿⣍⠛⠿⣿⣿⣿⣿⣿⣿]],
|
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠛⢿⣿⣿⠂⠀⠀⠀⠀⠀⢀⣽⣿⣿⣿⣿⣿⣿⣿⣍⠛⠿⣿⣿⣿⣿⣿⣿]],
|
||||||
d = {
|
d = {
|
||||||
"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⠋⠀⢀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠈⠉⠉⠙⠛⠛⠻⢿⣿⡿⠟⠁⠀⣀⣴⣿⣿⣿⣿⣿⠟",
|
"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⠋⠀⢀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠈⠉⠉⠙⠛⠛⠻⢿⣿⡿⠟⠁⠀⣀⣴⣿⣿⣿⣿⣿⠟",
|
||||||
"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⢀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠛⣉⣡⠀⣠⣴⣶⣶⣦⠄⣀⡀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⡿⢃⣾",
|
"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⢀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠛⣉⣡⠀⣠⣴⣶⣶⣦⠄⣀⡀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⡿⢃⣾",
|
||||||
"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⠀⣾⣤⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⣠⣾⡟⢡⣾⣿⣿⣿⡿⢋⣴⣿⡿⢀⣴⣾⣿⣿⣿⣿⣿⣿⣿⢡⣾⣿",
|
"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⠀⣾⣤⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⣠⣾⡟⢡⣾⣿⣿⣿⡿⢋⣴⣿⡿⢀⣴⣾⣿⣿⣿⣿⣿⣿⣿⢡⣾⣿",
|
||||||
"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠃⠀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⣼⣿⡟⣰⣿⣿⣿⣿⠏⣰⣿⣿⠟⣠⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⢚⣛⢿",
|
"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠃⠀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⣼⣿⡟⣰⣿⣿⣿⣿⠏⣰⣿⣿⠟⣠⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⢚⣛⢿",
|
||||||
"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⠸⣿⠟⢰⣿⣿⣿⣿⠃⣾⣿⣿⠏⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢋⣾",
|
"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⠸⣿⠟⢰⣿⣿⣿⣿⠃⣾⣿⣿⠏⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢋⣾",
|
||||||
"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠻⠻⠃⠀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⢉⣴⣿⣿⣿⣿⡇⠘⣿⣿⠋⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⡘⣿",
|
"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠻⠻⠃⠀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⢉⣴⣿⣿⣿⣿⡇⠘⣿⣿⠋⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⡘⣿",
|
||||||
"⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⠿⣿⣿⣿⣿⠁⢀⣀⠀⢀⣾⣿⣿⣿⣿⣿⣿⠟⠉⠉⠉⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣤⣤⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣌",
|
"⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⠿⣿⣿⣿⣿⠁⢀⣀⠀⢀⣾⣿⣿⣿⣿⣿⣿⠟⠉⠉⠉⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣤⣤⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣌",
|
||||||
"⣿⣿⣿⣿⣿⣿⡿⠁⣀⣤⡀⠀⠈⠻⢿⠀⣼⣿⣷⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
"⣿⣿⣿⣿⣿⣿⡿⠁⣀⣤⡀⠀⠈⠻⢿⠀⣼⣿⣷⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
||||||
"⣿⣿⣿⠟⠛⠙⠃⠀⣿⣿⣿⠀⠀⠀⠀⠀⠙⠿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⡿⠿⠿⠿⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠛⠁⠀⠀⠀⠈⠻⣿⣿⣿⣿⣿⣿⣿",
|
"⣿⣿⣿⠟⠛⠙⠃⠀⣿⣿⣿⠀⠀⠀⠀⠀⠙⠿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⡿⠿⠿⠿⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠛⠁⠀⠀⠀⠈⠻⣿⣿⣿⣿⣿⣿⣿",
|
||||||
"⣿⠟⠁⢀⣴⣶⣶⣾⣿⣿⣿⣿⣶⡐⢦⣄⠀⠀⠈⠛⢿⣿⣿⣿⣿⡀⠀⠀⠀⠀⢀⣼⡿⢛⣩⣴⣶⣶⣶⣶⣶⣶⣭⣙⠻⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿",
|
"⣿⠟⠁⢀⣴⣶⣶⣾⣿⣿⣿⣿⣶⡐⢦⣄⠀⠀⠈⠛⢿⣿⣿⣿⣿⡀⠀⠀⠀⠀⢀⣼⡿⢛⣩⣴⣶⣶⣶⣶⣶⣶⣭⣙⠻⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿",
|
||||||
"⠁⠀⣴⣿⣿⣿⣿⠿⠿⣿⣿⣿⣿⣿⣦⡙⠻⣶⣄⡀⠀⠈⠙⢿⣿⣷⣦⣤⣤⣴⣿⡏⣠⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣌⠻⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿",
|
"⠁⠀⣴⣿⣿⣿⣿⠿⠿⣿⣿⣿⣿⣿⣦⡙⠻⣶⣄⡀⠀⠈⠙⢿⣿⣷⣦⣤⣤⣴⣿⡏⣠⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣌⠻⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿",
|
||||||
"⠀⢸⣿⣿⣿⠋⣠⠔⠀⠀⠻⣿⣿⣿⣿⢉⡳⢦⣉⠛⢷⣤⣀⠀⠈⠙⠿⣿⣿⣿⣿⢸⣿⡄⠻⣿⣿⠟⡈⣿⣿⣿⣿⣿⢉⣿⣧⢹⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿",
|
"⠀⢸⣿⣿⣿⠋⣠⠔⠀⠀⠻⣿⣿⣿⣿⢉⡳⢦⣉⠛⢷⣤⣀⠀⠈⠙⠿⣿⣿⣿⣿⢸⣿⡄⠻⣿⣿⠟⡈⣿⣿⣿⣿⣿⢉⣿⣧⢹⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿",
|
||||||
"⠀⢸⣿⣿⡇⠠⡇⠀⠀⠀⠀⣿⣿⣿⣿⢸⣿⣷⣤⣙⠢⢌⡛⠷⣤⣄⠀⠈⠙⠿⣿⣿⣿⣿⣷⣦⣴⣾⣿⣤⣙⣛⣛⣥⣾⣿⣿⡌⣿⣿⣿⣷⣤⣀⣀⣀⣠⣴⣿⣿⣿⣿⣿⣿⣿",
|
"⠀⢸⣿⣿⡇⠠⡇⠀⠀⠀⠀⣿⣿⣿⣿⢸⣿⣷⣤⣙⠢⢌⡛⠷⣤⣄⠀⠈⠙⠿⣿⣿⣿⣿⣷⣦⣴⣾⣿⣤⣙⣛⣛⣥⣾⣿⣿⡌⣿⣿⣿⣷⣤⣀⣀⣀⣠⣴⣿⣿⣿⣿⣿⣿⣿",
|
||||||
"⠀⢸⣿⣿⣷⡀⠡⠀⠀⠀⣰⣿⣿⣿⣿⢸⣿⣿⣿⣿⣿⣦⣌⡓⠤⣙⣿⣦⡄⠀⠈⠙⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢡⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
"⠀⢸⣿⣿⣷⡀⠡⠀⠀⠀⣰⣿⣿⣿⣿⢸⣿⣿⣿⣿⣿⣦⣌⡓⠤⣙⣿⣦⡄⠀⠈⠙⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢡⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
||||||
"⠀⢸⣿⣿⣿⣿⣶⣤⣴⣾⣿⣿⣿⣿⣿⢸⣿⣿⣿⣿⣿⣿⣿⣿⣷⣾⣿⣿⣷⠀⣶⡄⠀⠈⠙⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢃⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
"⠀⢸⣿⣿⣿⣿⣶⣤⣴⣾⣿⣿⣿⣿⣿⢸⣿⣿⣿⣿⣿⣿⣿⣿⣷⣾⣿⣿⣷⠀⣶⡄⠀⠈⠙⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢃⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
||||||
"⠀⢸⣿⣿⣿⣿⣿⠟⠻⣿⣿⡏⣉⣭⣭⡘⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⣿⡇⢸⡇⢠⡀⠈⠙⠋⠉⠉⠉⠉⠛⠫⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
"⠀⢸⣿⣿⣿⣿⣿⠟⠻⣿⣿⡏⣉⣭⣭⡘⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⣿⡇⢸⡇⢠⡀⠈⠙⠋⠉⠉⠉⠉⠛⠫⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
||||||
"⠀⢸⣿⣿⠛⣿⣿⣀⣀⣾⡿⢀⣿⣿⣿⢻⣷⣦⢈⡙⠻⢿⣿⣿⣿⣿⣿⣿⣿⠀⣿⡇⢸⡇⢸⣿⠀⣦⠀⠀⠶⣶⣦⣀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
"⠀⢸⣿⣿⠛⣿⣿⣀⣀⣾⡿⢀⣿⣿⣿⢻⣷⣦⢈⡙⠻⢿⣿⣿⣿⣿⣿⣿⣿⠀⣿⡇⢸⡇⢸⣿⠀⣦⠀⠀⠶⣶⣦⣀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
||||||
"⠀⢸⣿⣿⣦⣈⡛⠿⠟⣋⣤⣾⣿⣿⣿⣸⣿⣿⢸⡇⢰⡆⢈⡙⠻⢿⣿⣿⣿⠀⢿⡇⢸⡇⢸⣿⢠⣿⡇⣿⡆⢈⡙⠻⠧⠀⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
"⠀⢸⣿⣿⣦⣈⡛⠿⠟⣋⣤⣾⣿⣿⣿⣸⣿⣿⢸⡇⢰⡆⢈⡙⠻⢿⣿⣿⣿⠀⢿⡇⢸⡇⢸⣿⢠⣿⡇⣿⡆⢈⡙⠻⠧⠀⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
||||||
"⠀⠀⣝⠛⢿⣿⣿⣿⣿⣿⣿⠟⣁⠀⠀⢈⠛⠿⢸⣇⢸⡇⢸⡇⣶⣦⣌⡙⠻⢄⡀⠁⠘⠇⠘⣿⢸⣿⡇⣿⡇⢸⡛⠷⣦⣄⠀⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
"⠀⠀⣝⠛⢿⣿⣿⣿⣿⣿⣿⠟⣁⠀⠀⢈⠛⠿⢸⣇⢸⡇⢸⡇⣶⣦⣌⡙⠻⢄⡀⠁⠘⠇⠘⣿⢸⣿⡇⣿⡇⢸⡛⠷⣦⣄⠀⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿",
|
||||||
},
|
},
|
||||||
e = {
|
e = {
|
||||||
" ____ __ _____ ",
|
" ____ __ _____ ",
|
||||||
" / __ \\/ / / / |",
|
" / __ \\/ / / / |",
|
||||||
" / /_/ / / / / /| |",
|
" / /_/ / / / / /| |",
|
||||||
" / _, _/ /_/ / ___ |",
|
" / _, _/ /_/ / ___ |",
|
||||||
"/_/ |_|\\____/_/ |_|",
|
"/_/ |_|\\____/_/ |_|",
|
||||||
},
|
},
|
||||||
f = {
|
f = {
|
||||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤⡤⠤⠤⠤⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤⡤⠤⠤⠤⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⠞⠋⠁⠀⠀⠀⠀⠀⠀⠀⠉⠛⢦⣤⠶⠦⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⠞⠋⠁⠀⠀⠀⠀⠀⠀⠀⠉⠛⢦⣤⠶⠦⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||||
"⠀⠀⠀⠀⠀⠀⠀⢀⣴⠞⢋⡽⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠃⠀⠀⠙⢶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
"⠀⠀⠀⠀⠀⠀⠀⢀⣴⠞⢋⡽⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠃⠀⠀⠙⢶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||||
"⠀⠀⠀⠀⠀⠀⣰⠟⠁⠀⠘⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⡀⠀⠀⠉⠓⠦⣤⣤⣤⣤⣤⣤⣄⣀⠀⠀⠀",
|
"⠀⠀⠀⠀⠀⠀⣰⠟⠁⠀⠘⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⡀⠀⠀⠉⠓⠦⣤⣤⣤⣤⣤⣤⣄⣀⠀⠀⠀",
|
||||||
"⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣷⡄⠀⠀⢻⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣆⠀",
|
"⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣷⡄⠀⠀⢻⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣆⠀",
|
||||||
"⠀⠀⣠⠞⠁⠀⠀⣀⣠⣏⡀⠀⢠⣶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⠿⡃⠀⠀⠀⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡆",
|
"⠀⠀⣠⠞⠁⠀⠀⣀⣠⣏⡀⠀⢠⣶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⠿⡃⠀⠀⠀⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡆",
|
||||||
"⢀⡞⠁⠀⣠⠶⠛⠉⠉⠉⠙⢦⡸⣿⡿⠀⠀⠀⡄⢀⣀⣀⡶⠀⠀⠀⢀⡄⣀⠀⣢⠟⢦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⠃",
|
"⢀⡞⠁⠀⣠⠶⠛⠉⠉⠉⠙⢦⡸⣿⡿⠀⠀⠀⡄⢀⣀⣀⡶⠀⠀⠀⢀⡄⣀⠀⣢⠟⢦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⠃",
|
||||||
"⡞⠀⠀⠸⠁⠀⠀⠀⠀⠀⠀⠀⢳⢀⣠⠀⠀⠀⠉⠉⠀⠀⣀⠀⠀⠀⢀⣠⡴⠞⠁⠀⠀⠈⠓⠦⣄⣀⠀⠀⠀⠀⣀⣤⠞⠁⠀",
|
"⡞⠀⠀⠸⠁⠀⠀⠀⠀⠀⠀⠀⢳⢀⣠⠀⠀⠀⠉⠉⠀⠀⣀⠀⠀⠀⢀⣠⡴⠞⠁⠀⠀⠈⠓⠦⣄⣀⠀⠀⠀⠀⣀⣤⠞⠁⠀",
|
||||||
"⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⠀⠁⠀⢀⣀⣀⡴⠋⢻⡉⠙⠾⡟⢿⣅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠙⠛⠉⠉⠀⠀⠀⠀",
|
"⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⠀⠁⠀⢀⣀⣀⡴⠋⢻⡉⠙⠾⡟⢿⣅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠙⠛⠉⠉⠀⠀⠀⠀",
|
||||||
"⠘⣦⡀⠀⠀⠀⠀⠀⠀⣀⣤⠞⢉⣹⣯⣍⣿⠉⠟⠀⠀⣸⠳⣄⡀⠀⠀⠙⢧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
"⠘⣦⡀⠀⠀⠀⠀⠀⠀⣀⣤⠞⢉⣹⣯⣍⣿⠉⠟⠀⠀⣸⠳⣄⡀⠀⠀⠙⢧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||||
"⠀⠈⠙⠒⠒⠒⠒⠚⠋⠁⠀⡴⠋⢀⡀⢠⡇⠀⠀⠀⠀⠃⠀⠀⠀⠀⠀⢀⡾⠋⢻⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
"⠀⠈⠙⠒⠒⠒⠒⠚⠋⠁⠀⡴⠋⢀⡀⢠⡇⠀⠀⠀⠀⠃⠀⠀⠀⠀⠀⢀⡾⠋⢻⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⢸⡀⠸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⢠⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⢸⡀⠸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⢠⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣇⠀⠀⠉⠋⠻⣄⠀⠀⠀⠀⠀⣀⣠⣴⠞⠋⠳⠶⠞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣇⠀⠀⠉⠋⠻⣄⠀⠀⠀⠀⠀⣀⣠⣴⠞⠋⠳⠶⠞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⠦⢤⠤⠶⠋⠙⠳⣆⣀⣈⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⠦⢤⠤⠶⠋⠙⠳⣆⣀⣈⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||||
},
|
},
|
||||||
g = [[
|
g = [[
|
||||||
███╗ ██╗███████╗ ██████╗ ██╗ ██╗██╗███╗ ███╗
|
███╗ ██╗███████╗ ██████╗ ██╗ ██╗██╗███╗ ███╗
|
||||||
████╗ ██║██╔════╝██╔═══██╗██║ ██║██║████╗ ████║
|
████╗ ██║██╔════╝██╔═══██╗██║ ██║██║████╗ ████║
|
||||||
██╔██╗ ██║█████╗ ██║ ██║██║ ██║██║██╔████╔██║
|
██╔██╗ ██║█████╗ ██║ ██║██║ ██║██║██╔████╔██║
|
||||||
@ -168,47 +167,57 @@ local starter = require("mini.starter")
|
|||||||
-- 口径与 lazy._loaded 一致:每个独立初始化的功能模块算一个,
|
-- 口径与 lazy._loaded 一致:每个独立初始化的功能模块算一个,
|
||||||
-- 不再按 vim.pack 的插件包统计(如 mini.nvim 包含多个模块)。
|
-- 不再按 vim.pack 的插件包统计(如 mini.nvim 包含多个模块)。
|
||||||
local all_modules = {
|
local all_modules = {
|
||||||
"starter", "notify", "cmdline", "icons",
|
"starter",
|
||||||
"pick", "files",
|
"notify",
|
||||||
"diff", "surround",
|
"cmdline",
|
||||||
"completion", "snippets",
|
"icons",
|
||||||
"treesitter", "lsp",
|
"pick",
|
||||||
"conform", "lspconfig", "mason",
|
"files",
|
||||||
"fugitive", "grugfar",
|
"diff",
|
||||||
|
"surround",
|
||||||
|
"completion",
|
||||||
|
"snippets",
|
||||||
|
"treesitter",
|
||||||
|
"lsp",
|
||||||
|
"conform",
|
||||||
|
"lspconfig",
|
||||||
|
"mason",
|
||||||
|
"fugitive",
|
||||||
|
"grugfar",
|
||||||
}
|
}
|
||||||
|
|
||||||
-- 计算 Logo 的最大显示宽度,用于页脚居中计算
|
-- 计算 Logo 的最大显示宽度,用于页脚居中计算
|
||||||
local max_header_width = 0
|
local max_header_width = 0
|
||||||
for _, line in ipairs(logs.f) do
|
for _, line in ipairs(logs.f) do
|
||||||
max_header_width = math.max(max_header_width, vim.fn.strdisplaywidth(line))
|
max_header_width = math.max(max_header_width, vim.fn.strdisplaywidth(line))
|
||||||
end
|
end
|
||||||
|
|
||||||
starter.setup({
|
starter.setup({
|
||||||
autoopen = true, -- 无参数启动时自动打开
|
autoopen = true, -- 无参数启动时自动打开
|
||||||
evaluate_single = false, -- 只有一个选项时不自动执行
|
evaluate_single = false, -- 只有一个选项时不自动执行
|
||||||
items = { { name = " ", action = "", section = "" } }, -- 空选项(仅展示页眉页脚)
|
items = { { name = " ", action = "", section = "" } }, -- 空选项(仅展示页眉页脚)
|
||||||
header = table.concat(logs.f, "\n"), -- Logo 文本
|
header = table.concat(logs.f, "\n"), -- Logo 文本
|
||||||
|
|
||||||
-- 页脚函数:显示启动耗时和模块加载统计
|
-- 页脚函数:显示启动耗时和模块加载统计
|
||||||
footer = function()
|
footer = function()
|
||||||
-- 已加载的模块数(动态统计,包含直接加载和懒加载)
|
-- 已加载的模块数(动态统计,包含直接加载和懒加载)
|
||||||
local loaded = vim.tbl_count(require("lazy")._loaded)
|
local loaded = vim.tbl_count(require("lazy")._loaded)
|
||||||
local total = #all_modules
|
local total = #all_modules
|
||||||
-- 优先使用 VimEnter 时间(runtime 插件、ShaDa 等已加载,最接近 --startuptime),
|
-- 优先使用 VimEnter 时间(runtime 插件、ShaDa 等已加载,最接近 --startuptime),
|
||||||
-- 回退到 init.lua 完成时间,最后回退到当前时间(理论上不会走到)
|
-- 回退到 init.lua 完成时间,最后回退到当前时间(理论上不会走到)
|
||||||
local end_time = _G.nvim_vimenter_done or _G.nvim_init_done or (vim.uv or vim.loop).hrtime()
|
local end_time = _G.nvim_vimenter_done or _G.nvim_init_done or (vim.uv or vim.loop).hrtime()
|
||||||
local ms = (end_time - _G.nvim_start_time) / 1e6
|
local ms = (end_time - _G.nvim_start_time) / 1e6
|
||||||
local text = string.format(" %d/%d modules | %.0f ms", loaded, total, ms)
|
local text = string.format(" %d/%d modules | %.0f ms", loaded, total, ms)
|
||||||
local text_width = vim.fn.strdisplaywidth(text)
|
local text_width = vim.fn.strdisplaywidth(text)
|
||||||
-- 计算左填充空格数以实现居中
|
-- 计算左填充空格数以实现居中
|
||||||
local pad = math.floor((max_header_width - text_width) / 2)
|
local pad = math.floor((max_header_width - text_width) / 2)
|
||||||
return string.rep(" ", pad) .. text
|
return string.rep(" ", pad) .. text
|
||||||
end,
|
end,
|
||||||
|
|
||||||
-- 内容钩子:水平和垂直居中
|
-- 内容钩子:水平和垂直居中
|
||||||
content_hooks = {
|
content_hooks = {
|
||||||
starter.gen_hook.aligning("center", "center"),
|
starter.gen_hook.aligning("center", "center"),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
lazy.track("starter")
|
lazy.track("starter")
|
||||||
@ -217,49 +226,48 @@ lazy.track("starter")
|
|||||||
-- mini.files — 文件浏览器(按键触发懒加载)
|
-- mini.files — 文件浏览器(按键触发懒加载)
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 提供悬浮文件浏览器,支持目录导航和文件操作。
|
-- 提供悬浮文件浏览器,支持目录导航和文件操作。
|
||||||
|
|
||||||
-- mini.files setup 配置(复用)
|
-- mini.files setup 配置(复用)
|
||||||
local function setup_mini_files()
|
local function setup_mini_files()
|
||||||
require("mini.files").setup({
|
require("mini.files").setup({
|
||||||
mappings = {
|
mappings = {
|
||||||
go_in = "<CR>", -- 回车进入目录或打开文件
|
go_in = "<CR>", -- 回车进入目录或打开文件
|
||||||
go_in_plus = "L", -- L 进入并同步光标
|
go_in_plus = "L", -- L 进入并同步光标
|
||||||
go_out = "_", -- _ 返回上级目录
|
go_out = "_", -- _ 返回上级目录
|
||||||
go_out_plus = "H", -- H 返回上级并同步光标
|
go_out_plus = "H", -- H 返回上级并同步光标
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- <leader>- :在当前工作目录打开文件浏览器
|
-- <leader>- :在当前工作目录打开文件浏览器
|
||||||
lazy.on_keys("files", "<leader>-", "n", setup_mini_files, function()
|
lazy.on_keys("files", "<leader>-", "n", setup_mini_files, function()
|
||||||
require("mini.files").open()
|
require("mini.files").open()
|
||||||
end, { desc = "打开文件浏览器(工作目录)" })
|
end, { desc = "打开文件浏览器(工作目录)" })
|
||||||
|
|
||||||
-- - :在当前文件所在目录打开文件浏览器
|
-- - :在当前文件所在目录打开文件浏览器
|
||||||
lazy.on_keys("files", "-", "n", setup_mini_files, function()
|
lazy.on_keys("files", "-", "n", setup_mini_files, function()
|
||||||
local MiniFiles = require("mini.files")
|
local MiniFiles = require("mini.files")
|
||||||
-- 打开当前文件所在目录,并定位到当前文件
|
-- 打开当前文件所在目录,并定位到当前文件
|
||||||
MiniFiles.open(vim.api.nvim_buf_get_name(0), false)
|
MiniFiles.open(vim.api.nvim_buf_get_name(0), false)
|
||||||
MiniFiles.reveal_cwd()
|
MiniFiles.reveal_cwd()
|
||||||
end, { desc = "打开文件浏览器(当前文件目录)" })
|
end, { desc = "打开文件浏览器(当前文件目录)" })
|
||||||
|
|
||||||
-- 在启动页(mini.starter)中也绑定 - / <leader>-,
|
-- 在启动页(mini.starter)中也绑定 - / <leader>-,
|
||||||
-- 因为 starter buffer 可能拦截全局映射
|
-- 因为 starter buffer 可能拦截全局映射
|
||||||
vim.api.nvim_create_autocmd("User", {
|
vim.api.nvim_create_autocmd("User", {
|
||||||
pattern = "MiniStarterOpened",
|
pattern = "MiniStarterOpened",
|
||||||
callback = function(args)
|
callback = function(args)
|
||||||
vim.keymap.set("n", "<leader>-", function()
|
vim.keymap.set("n", "<leader>-", function()
|
||||||
require("lazy").load("files", setup_mini_files)
|
require("lazy").load("files", setup_mini_files)
|
||||||
require("mini.files").open()
|
require("mini.files").open()
|
||||||
end, { buffer = args.buf, desc = "打开文件浏览器(工作目录)" })
|
end, { buffer = args.buf, desc = "打开文件浏览器(工作目录)" })
|
||||||
|
|
||||||
vim.keymap.set("n", "-", function()
|
vim.keymap.set("n", "-", function()
|
||||||
require("lazy").load("files", setup_mini_files)
|
require("lazy").load("files", setup_mini_files)
|
||||||
local MiniFiles = require("mini.files")
|
local MiniFiles = require("mini.files")
|
||||||
-- starter 无当前文件,打开工作目录
|
-- starter 无当前文件,打开工作目录
|
||||||
MiniFiles.open(vim.fn.getcwd())
|
MiniFiles.open(vim.fn.getcwd())
|
||||||
end, { buffer = args.buf, desc = "打开文件浏览器(工作目录)" })
|
end, { buffer = args.buf, desc = "打开文件浏览器(工作目录)" })
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -267,13 +275,12 @@ vim.api.nvim_create_autocmd("User", {
|
|||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 提供文件类型图标,供 mini.pick、mini.files 等使用。
|
-- 提供文件类型图标,供 mini.pick、mini.files 等使用。
|
||||||
-- 在 VimEnter 后 setup,确保 UI 已初始化。
|
-- 在 VimEnter 后 setup,确保 UI 已初始化。
|
||||||
|
|
||||||
vim.api.nvim_create_autocmd("VimEnter", {
|
vim.api.nvim_create_autocmd("VimEnter", {
|
||||||
once = true,
|
once = true,
|
||||||
callback = function()
|
callback = function()
|
||||||
require("mini.icons").setup()
|
require("mini.icons").setup()
|
||||||
lazy._loaded["icons"] = true
|
lazy._loaded["icons"] = true
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -281,14 +288,13 @@ vim.api.nvim_create_autocmd("VimEnter", {
|
|||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 替换默认的 vim.notify,提供美观的浮动通知窗口。
|
-- 替换默认的 vim.notify,提供美观的浮动通知窗口。
|
||||||
-- 直接初始化(轻量,不阻塞启动)。
|
-- 直接初始化(轻量,不阻塞启动)。
|
||||||
|
|
||||||
require("mini.notify").setup({
|
require("mini.notify").setup({
|
||||||
content = {
|
content = {
|
||||||
-- 简化格式:只显示消息内容,不附加时间戳等元信息
|
-- 简化格式:只显示消息内容,不附加时间戳等元信息
|
||||||
format = function(notif)
|
format = function(notif)
|
||||||
return notif.msg
|
return notif.msg
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
-- 将 vim.notify 重定向到 mini.notify
|
-- 将 vim.notify 重定向到 mini.notify
|
||||||
vim.notify = require("mini.notify").make_notify()
|
vim.notify = require("mini.notify").make_notify()
|
||||||
@ -299,20 +305,19 @@ lazy.track("notify")
|
|||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 提供美观的命令行界面,首次按 : 时加载。
|
-- 提供美观的命令行界面,首次按 : 时加载。
|
||||||
-- 使用 expr 映射:返回 ":" 让 Vim 继续处理命令行输入。
|
-- 使用 expr 映射:返回 ":" 让 Vim 继续处理命令行输入。
|
||||||
|
|
||||||
vim.keymap.set("n", ":", function()
|
vim.keymap.set("n", ":", function()
|
||||||
-- 首次按下 : 时删除此映射,避免后续重复触发 setup
|
-- 首次按下 : 时删除此映射,避免后续重复触发 setup
|
||||||
vim.keymap.del("n", ":")
|
vim.keymap.del("n", ":")
|
||||||
require("mini.cmdline").setup({
|
require("mini.cmdline").setup({
|
||||||
autocorrect = { enable = false }, -- 禁用自动纠正
|
autocorrect = { enable = false }, -- 禁用自动纠正
|
||||||
})
|
})
|
||||||
lazy.track("cmdline")
|
lazy.track("cmdline")
|
||||||
return ":"
|
return ":"
|
||||||
end, { expr = true, noremap = true })
|
end, { expr = true, noremap = true })
|
||||||
|
|
||||||
-- 诊断位置列表(Quickfix 的本地化版本)
|
-- 诊断位置列表(Quickfix 的本地化版本)
|
||||||
vim.keymap.set("n", "<leader>ds", function()
|
vim.keymap.set("n", "<leader>ds", function()
|
||||||
vim.diagnostic.setloclist()
|
vim.diagnostic.setloclist()
|
||||||
end, { desc = "诊断位置列表" })
|
end, { desc = "诊断位置列表" })
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -320,120 +325,114 @@ end, { desc = "诊断位置列表" })
|
|||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 所有 pick 相关映射共用 pick.load_pick() 初始化,确保 mini.pick 和 mini.extra
|
-- 所有 pick 相关映射共用 pick.load_pick() 初始化,确保 mini.pick 和 mini.extra
|
||||||
-- 只在首次使用时 setup 一次。
|
-- 只在首次使用时 setup 一次。
|
||||||
|
|
||||||
-- <leader>ff :文件查找
|
-- <leader>ff :文件查找
|
||||||
lazy.on_keys("pick", "<leader>ff", "n", pick.load_pick, function()
|
lazy.on_keys("pick", "<leader>ff", "n", pick.load_pick, function()
|
||||||
require("mini.pick").builtin.files()
|
require("mini.pick").builtin.files()
|
||||||
end, { desc = "文件查找" })
|
end, { desc = "文件查找" })
|
||||||
|
|
||||||
-- <leader>fw :实时 grep(在项目中搜索文本)
|
-- <leader>fw :实时 grep(在项目中搜索文本)
|
||||||
lazy.on_keys("pick", "<leader>fw", "n", pick.load_pick, function()
|
lazy.on_keys("pick", "<leader>fw", "n", pick.load_pick, function()
|
||||||
require("mini.pick").builtin.grep_live()
|
require("mini.pick").builtin.grep_live()
|
||||||
end, { desc = "项目内实时搜索" })
|
end, { desc = "项目内实时搜索" })
|
||||||
|
|
||||||
-- <leader>sk :键位映射搜索
|
-- <leader>sk :键位映射搜索
|
||||||
lazy.on_keys("pick", "<leader>sk", "n", pick.load_pick, function()
|
lazy.on_keys("pick", "<leader>sk", "n", pick.load_pick, function()
|
||||||
require("mini.extra").pickers.keymaps()
|
require("mini.extra").pickers.keymaps()
|
||||||
end, { desc = "搜索键位映射" })
|
end, { desc = "搜索键位映射" })
|
||||||
|
|
||||||
-- <leader>fa :查找所有文件(含隐藏和忽略的文件)
|
-- <leader>fa :查找所有文件(含隐藏和忽略的文件)
|
||||||
lazy.on_keys("pick", "<leader>fa", "n", pick.load_pick, function()
|
lazy.on_keys("pick", "<leader>fa", "n", pick.load_pick, function()
|
||||||
require("mini.pick").builtin.cli({
|
require("mini.pick").builtin.cli({
|
||||||
command = { "rg", "--files", "--hidden", "--no-ignore", "--color=never" }
|
command = { "rg", "--files", "--hidden", "--no-ignore", "--color=never" },
|
||||||
})
|
})
|
||||||
end, { desc = "查找所有文件(含隐藏/忽略)" })
|
end, { desc = "查找所有文件(含隐藏/忽略)" })
|
||||||
|
|
||||||
-- <leader>fh :帮助标签搜索
|
-- <leader>fh :帮助标签搜索
|
||||||
lazy.on_keys("pick", "<leader>fh", "n", pick.load_pick, function()
|
lazy.on_keys("pick", "<leader>fh", "n", pick.load_pick, function()
|
||||||
require("mini.pick").builtin.help()
|
require("mini.pick").builtin.help()
|
||||||
end, { desc = "搜索帮助标签" })
|
end, { desc = "搜索帮助标签" })
|
||||||
|
|
||||||
-- <leader>fo :最近打开的文件
|
-- <leader>fo :最近打开的文件
|
||||||
lazy.on_keys("pick", "<leader>fo", "n", pick.load_pick, function()
|
lazy.on_keys("pick", "<leader>fo", "n", pick.load_pick, function()
|
||||||
require("mini.extra").pickers.oldfiles()
|
require("mini.extra").pickers.oldfiles()
|
||||||
end, { desc = "最近打开的文件" })
|
end, { desc = "最近打开的文件" })
|
||||||
|
|
||||||
-- <leader>fz :当前缓冲区行内搜索
|
-- <leader>fz :当前缓冲区行内搜索
|
||||||
lazy.on_keys("pick", "<leader>fz", "n", pick.load_pick, function()
|
lazy.on_keys("pick", "<leader>fz", "n", pick.load_pick, function()
|
||||||
require("mini.extra").pickers.buf_lines({ scope = "current" })
|
require("mini.extra").pickers.buf_lines({ scope = "current" })
|
||||||
end, { desc = "当前缓冲区行内搜索" })
|
end, { desc = "当前缓冲区行内搜索" })
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- vim-fugitive — Git 集成(按键触发懒加载)
|
-- vim-fugitive — Git 集成(按键触发懒加载)
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- tpope 的 Git 包装插件,提供 :Git 等命令。
|
-- tpope 的 Git 包装插件,提供 :Git 等命令。
|
||||||
|
|
||||||
local function load_fugitive()
|
local function load_fugitive()
|
||||||
vim.cmd.packadd("vim-fugitive")
|
vim.cmd.packadd("vim-fugitive")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- <leader>gg :在新标签页中打开 Fugitive 全屏
|
-- <leader>gg :在新标签页中打开 Fugitive 全屏
|
||||||
lazy.on_keys("fugitive", "<leader>gg", "n", load_fugitive, function()
|
lazy.on_keys("fugitive", "<leader>gg", "n", load_fugitive, function()
|
||||||
vim.cmd("tabnew | Git | only")
|
vim.cmd("tabnew | Git | only")
|
||||||
end, { desc = "Fugitive 全屏新标签" })
|
end, { desc = "Fugitive 全屏新标签" })
|
||||||
|
|
||||||
-- <leader>gd :Git diff 垂直分割
|
-- <leader>gd :Git diff 垂直分割
|
||||||
lazy.on_keys("fugitive", "<leader>gd", "n", load_fugitive, function()
|
lazy.on_keys("fugitive", "<leader>gd", "n", load_fugitive, function()
|
||||||
vim.cmd("Gvdiffsplit")
|
vim.cmd("Gvdiffsplit")
|
||||||
end, { desc = "Git diff 分割" })
|
end, { desc = "Git diff 分割" })
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- mini.completion — 自动补全(InsertEnter 懒加载)
|
-- mini.completion — 自动补全(InsertEnter 懒加载)
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 轻量级补全引擎,支持 LSP 补全、buffer 单词、路径补全。
|
-- 轻量级补全引擎,支持 LSP 补全、buffer 单词、路径补全。
|
||||||
|
|
||||||
lazy.on_event("completion", "InsertEnter", "*", function()
|
lazy.on_event("completion", "InsertEnter", "*", function()
|
||||||
require("mini.completion").setup({
|
require("mini.completion").setup({
|
||||||
lsp_completion = {
|
lsp_completion = {
|
||||||
auto_setup = true, -- 自动配置 LSP 补全源
|
auto_setup = true, -- 自动配置 LSP 补全源
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- mini.snippets — 代码片段(InsertEnter 懒加载)
|
-- mini.snippets — 代码片段(InsertEnter 懒加载)
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 代码片段引擎,支持 LSP 片段扩展。
|
-- 代码片段引擎,支持 LSP 片段扩展。
|
||||||
|
|
||||||
lazy.on_event("snippets", "InsertEnter", "*", function()
|
lazy.on_event("snippets", "InsertEnter", "*", function()
|
||||||
local MiniSnippets = require("mini.snippets")
|
local MiniSnippets = require("mini.snippets")
|
||||||
MiniSnippets.setup({
|
MiniSnippets.setup({
|
||||||
snippets = {
|
snippets = {
|
||||||
-- 从 friendly-snippets 加载对应语言的片段
|
-- 从 friendly-snippets 加载对应语言的片段
|
||||||
MiniSnippets.gen_loader.from_lang(),
|
MiniSnippets.gen_loader.from_lang(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
-- 启动 LSP 片段服务器(match = false 表示不匹配时不自动触发)
|
-- 启动 LSP 片段服务器(match = false 表示不匹配时不自动触发)
|
||||||
MiniSnippets.start_lsp_server({ match = false })
|
MiniSnippets.start_lsp_server({ match = false })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- mini.diff — Git diff 标记(BufReadPost 懒加载)
|
-- mini.diff — Git diff 标记(BufReadPost 懒加载)
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 在 signcolumn 中显示当前 buffer 相对于 git HEAD 的变更标记。
|
-- 在 signcolumn 中显示当前 buffer 相对于 git HEAD 的变更标记。
|
||||||
|
|
||||||
lazy.on_event("diff", "BufReadPost", "*", function()
|
lazy.on_event("diff", "BufReadPost", "*", function()
|
||||||
require("mini.diff").setup({
|
require("mini.diff").setup({
|
||||||
-- 使用 git 作为 diff 源(index = false 表示对比工作区 vs HEAD,不含暂存区)
|
-- 使用 git 作为 diff 源(index = false 表示对比工作区 vs HEAD,不含暂存区)
|
||||||
source = require("mini.diff").gen_source.git({ index = false }),
|
source = require("mini.diff").gen_source.git({ index = false }),
|
||||||
view = {
|
view = {
|
||||||
style = "sign", -- 以符号形式显示(在 signcolumn 中)
|
style = "sign", -- 以符号形式显示(在 signcolumn 中)
|
||||||
signs = { add = "│", change = "│", delete = "│" }, -- 统一的竖线符号
|
signs = { add = "│", change = "│", delete = "│" }, -- 统一的竖线符号
|
||||||
},
|
},
|
||||||
mappings = {
|
mappings = {
|
||||||
apply = "gs", -- gs 应用当前 hunk
|
apply = "gs", -- gs 应用当前 hunk
|
||||||
textobject = "", -- 禁用文本对象映射
|
textobject = "", -- 禁用文本对象映射
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- mini.surround — 环绕文本操作(BufReadPost 懒加载)
|
-- mini.surround — 环绕文本操作(BufReadPost 懒加载)
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 快速添加、删除、修改包围符号(如括号、引号、HTML 标签等)。
|
-- 快速添加、删除、修改包围符号(如括号、引号、HTML 标签等)。
|
||||||
|
|
||||||
lazy.on_event("surround", "BufReadPost", "*", function()
|
lazy.on_event("surround", "BufReadPost", "*", function()
|
||||||
require("mini.surround").setup()
|
require("mini.surround").setup()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -441,35 +440,33 @@ end)
|
|||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- treesitter 和 lsp 是启动时最耗时的模块,
|
-- treesitter 和 lsp 是启动时最耗时的模块,
|
||||||
-- 延迟到 VimEnter 事件触发后加载,让编辑器界面先渲染出来。
|
-- 延迟到 VimEnter 事件触发后加载,让编辑器界面先渲染出来。
|
||||||
|
|
||||||
lazy.on_event("treesitter", "VimEnter", "*", function()
|
lazy.on_event("treesitter", "VimEnter", "*", function()
|
||||||
require("treesitter").setup()
|
require("plugins.treesitter").setup()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
lazy.on_event("lsp", "VimEnter", "*", function()
|
lazy.on_event("lsp", "VimEnter", "*", function()
|
||||||
require("lsp")
|
require("plugins.lsp")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- grug-far.nvim — 搜索与替换(按键触发懒加载)
|
-- grug-far.nvim — 搜索与替换(按键触发懒加载)
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- 提供类似 VS Code 的查找替换界面,支持正则和文件过滤。
|
-- 提供类似 VS Code 的查找替换界面,支持正则和文件过滤。
|
||||||
|
|
||||||
local function load_grug_far()
|
local function load_grug_far()
|
||||||
vim.cmd.packadd("grug-far.nvim")
|
vim.cmd.packadd("grug-far.nvim")
|
||||||
require("grug-far").setup({ headerMaxWidth = 80 })
|
require("grug-far").setup({ headerMaxWidth = 80 })
|
||||||
end
|
end
|
||||||
|
|
||||||
local function open_grug_far()
|
local function open_grug_far()
|
||||||
local grug = require("grug-far")
|
local grug = require("grug-far")
|
||||||
-- 根据当前文件扩展名预填充文件过滤器
|
-- 根据当前文件扩展名预填充文件过滤器
|
||||||
local ext = vim.bo.buftype == "" and vim.fn.expand("%:e")
|
local ext = vim.bo.buftype == "" and vim.fn.expand("%:e")
|
||||||
grug.open({
|
grug.open({
|
||||||
transient = true, -- 关闭后自动销毁 buffer
|
transient = true, -- 关闭后自动销毁 buffer
|
||||||
prefills = {
|
prefills = {
|
||||||
filesFilter = ext and ext ~= "" and "*." .. ext or nil,
|
filesFilter = ext and ext ~= "" and "*." .. ext or nil,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Normal 模式和 Visual 模式均绑定 <leader>sr
|
-- Normal 模式和 Visual 模式均绑定 <leader>sr
|
||||||
|
|||||||
125
lua/pick.lua
125
lua/pick.lua
@ -1,125 +0,0 @@
|
|||||||
-- =============================================================================
|
|
||||||
-- mini.pick 封装 (lua/pick.lua)
|
|
||||||
-- =============================================================================
|
|
||||||
-- 本模块封装 mini.pick 和 mini.extra 的初始化逻辑,
|
|
||||||
-- 提供统一的懒加载入口和自定义 picker。
|
|
||||||
--
|
|
||||||
-- 主要功能:
|
|
||||||
-- 1. load_pick() — 懒加载 mini.pick 和 mini.extra
|
|
||||||
-- 2. Buffer picker(<leader><leader>)— 自定义 buffer 列表,支持 <C-d> 删除
|
|
||||||
-- 3. Filetype picker(<leader>ft)— 快速切换文件类型
|
|
||||||
-- =============================================================================
|
|
||||||
|
|
||||||
local lazy = require("lazy")
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- 懒加载入口
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- 通过 lazy.load 确保 mini.pick 和 mini.extra 只初始化一次。
|
|
||||||
-- 此函数被 pack.lua 中所有 pick 相关的 on_keys 映射共用。
|
|
||||||
|
|
||||||
M.load_pick = function()
|
|
||||||
lazy.load("pick", function()
|
|
||||||
require("mini.pick").setup()
|
|
||||||
end)
|
|
||||||
lazy.load("extra", function()
|
|
||||||
require("mini.extra").setup()
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- Buffer Picker(<leader><leader>)
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- 显示当前打开的 buffer 列表,按最近使用时间排序。
|
|
||||||
-- 特殊功能:
|
|
||||||
-- - <C-d>:删除当前选中的 buffer(带图标过滤)
|
|
||||||
-- - 支持 mini.icons 图标显示
|
|
||||||
|
|
||||||
vim.keymap.set("n", "<leader><leader>", function()
|
|
||||||
M.load_pick()
|
|
||||||
local MiniPick = require("mini.pick")
|
|
||||||
|
|
||||||
-- 删除当前选中 buffer 的回调函数
|
|
||||||
local delete_buf = function()
|
|
||||||
local matches = MiniPick.get_picker_matches()
|
|
||||||
local item = matches and matches.current
|
|
||||||
if not item or not item.bufnr then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local bufnr = item.bufnr
|
|
||||||
|
|
||||||
-- 安全删除 buffer(force = true 跳过未保存确认)
|
|
||||||
pcall(vim.api.nvim_buf_delete, bufnr, { force = true })
|
|
||||||
|
|
||||||
-- 如果 picker 仍活跃,刷新列表以移除已删除的 buffer
|
|
||||||
if MiniPick.is_picker_active() then
|
|
||||||
local items = vim.tbl_filter(function(i)
|
|
||||||
return i.bufnr and vim.api.nvim_buf_is_valid(i.bufnr)
|
|
||||||
end, MiniPick.get_picker_items() or {})
|
|
||||||
MiniPick.set_picker_items(items)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 获取所有普通 buffer(排除特殊 buffer 如终端、quickfix)
|
|
||||||
local bufs = vim.tbl_filter(function(b)
|
|
||||||
return vim.bo[b.bufnr].buftype == "" and b.listed == 1
|
|
||||||
end, vim.fn.getbufinfo())
|
|
||||||
|
|
||||||
-- 按最后使用时间降序排列(最近使用的在前)
|
|
||||||
table.sort(bufs, function(a, b)
|
|
||||||
return a.lastused > b.lastused
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- 构建 picker items
|
|
||||||
local items = {}
|
|
||||||
for _, info in ipairs(bufs) do
|
|
||||||
-- 相对路径显示(当前工作目录为基准)
|
|
||||||
local name = info.name ~= "" and vim.fn.fnamemodify(info.name, ":.") or "[No Name]"
|
|
||||||
table.insert(items, {
|
|
||||||
text = name,
|
|
||||||
bufnr = info.bufnr,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 启动 picker
|
|
||||||
MiniPick.start({
|
|
||||||
source = {
|
|
||||||
name = "Buffers",
|
|
||||||
items = items,
|
|
||||||
show = function(buf_id, items_arr, query)
|
|
||||||
-- 使用默认显示函数,启用图标
|
|
||||||
MiniPick.default_show(buf_id, items_arr, query, { show_icons = true })
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
mappings = {
|
|
||||||
delete_buffer = { char = "<C-d>", func = delete_buf },
|
|
||||||
},
|
|
||||||
})
|
|
||||||
end, { desc = "Buffer 列表" })
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- Filetype Picker(<leader>ft)
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- 显示所有可用的文件类型列表,选择后设置当前 buffer 的 filetype。
|
|
||||||
-- 常用于打开无扩展名文件或纠正错误的文件类型检测。
|
|
||||||
|
|
||||||
vim.keymap.set("n", "<leader>ft", function()
|
|
||||||
M.load_pick()
|
|
||||||
local MiniPick = require("mini.pick")
|
|
||||||
-- 获取所有可用的文件类型名称
|
|
||||||
local filetypes = vim.fn.getcompletion("", "filetype")
|
|
||||||
MiniPick.start({
|
|
||||||
source = {
|
|
||||||
name = "Filetypes",
|
|
||||||
items = filetypes,
|
|
||||||
choose = function(item)
|
|
||||||
-- 选择后将当前 buffer 的 filetype 设为选中值
|
|
||||||
vim.bo.filetype = item
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
end, { desc = "切换文件类型" })
|
|
||||||
|
|
||||||
return M
|
|
||||||
199
lua/plugins/git.lua
Normal file
199
lua/plugins/git.lua
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
-- =============================================================================
|
||||||
|
-- Git 工具封装 (lua/git.lua)
|
||||||
|
-- =============================================================================
|
||||||
|
-- 本模块提供基于 mini.diff 和原生 git 命令的 Git 相关功能。
|
||||||
|
--
|
||||||
|
-- 功能列表:
|
||||||
|
-- 1. Hunk Preview(<leader>ghp)— 预览当前光标处 git diff hunk
|
||||||
|
-- 2. Blame Line(<leader>ghb)— 查看当前行的 git blame 信息
|
||||||
|
-- 3. Blame Buffer(<leader>gB)— 整文件 blame(via fugitive)
|
||||||
|
-- 4. File History(<leader>gD)— 查看当前文件的 git log
|
||||||
|
--
|
||||||
|
-- 依赖:
|
||||||
|
-- - mini.diff(已在 pack.lua 中通过 BufReadPost 懒加载)
|
||||||
|
-- - vim-fugitive(已在 pack.lua 中通过按键触发懒加载)
|
||||||
|
-- =============================================================================
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- 辅助函数:获取光标所在行的 hunk
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- 遍历当前 buffer 的所有 hunks,找到包含光标所在行的那个。
|
||||||
|
--
|
||||||
|
-- 返回值:
|
||||||
|
-- hunk - hunk 对象 { type, buf_start, buf_count, ref_start, ref_count }
|
||||||
|
-- ref_text - 参考文本(HEAD 版本的内容)
|
||||||
|
-- nil - 光标不在任何 hunk 上
|
||||||
|
local function get_cursor_hunk()
|
||||||
|
local buf = vim.api.nvim_get_current_buf()
|
||||||
|
-- 从 mini.diff 获取当前 buffer 的 diff 数据
|
||||||
|
local data = require("mini.diff").get_buf_data(buf)
|
||||||
|
if not data or not data.hunks or #data.hunks == 0 then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local cursor_line = vim.api.nvim_win_get_cursor(0)[1]
|
||||||
|
|
||||||
|
for _, h in ipairs(data.hunks) do
|
||||||
|
-- hunk 在 buffer 中的起始行(1-based)
|
||||||
|
local start_line = math.max(h.buf_start, 1)
|
||||||
|
-- hunk 在 buffer 中的结束行
|
||||||
|
local end_line = h.buf_start + h.buf_count - 1
|
||||||
|
-- 空删除(0 行)时特殊处理
|
||||||
|
if h.buf_count == 0 then
|
||||||
|
end_line = start_line
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 检查光标是否在此 hunk 范围内
|
||||||
|
if cursor_line >= start_line and cursor_line <= end_line then
|
||||||
|
return h, data.ref_text
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- Hunk Preview — 浮动窗口预览当前 hunk
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- 创建一个居中的浮动窗口,显示光标所在 hunk 的详细 diff 信息。
|
||||||
|
-- 支持三种 hunk 类型:
|
||||||
|
-- add — 显示新增的行
|
||||||
|
-- delete — 显示被删除的行(从参考文本中恢复)
|
||||||
|
-- change — 并排显示修改前后的内容
|
||||||
|
local function preview_hunk()
|
||||||
|
local hunk, ref_text = get_cursor_hunk()
|
||||||
|
if not hunk then
|
||||||
|
vim.notify("光标不在变更区域", vim.log.levels.WARN)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 构建预览内容
|
||||||
|
local lines = {}
|
||||||
|
table.insert(lines, "Hunk 类型: " .. hunk.type)
|
||||||
|
table.insert(lines, string.format("Buffer 行: %d-%d", hunk.buf_start, hunk.buf_start + hunk.buf_count - 1))
|
||||||
|
table.insert(lines, string.format("参考行: %d-%d", hunk.ref_start, hunk.ref_start + hunk.ref_count - 1))
|
||||||
|
table.insert(lines, "---")
|
||||||
|
|
||||||
|
local buf = vim.api.nvim_get_current_buf()
|
||||||
|
local ref_lines = vim.split(ref_text or "", "\n")
|
||||||
|
|
||||||
|
if hunk.type == "delete" then
|
||||||
|
-- 删除型 hunk:显示被删除的内容(来自参考文本)
|
||||||
|
table.insert(lines, "被删除的行(来自参考版本):")
|
||||||
|
for i = hunk.ref_start, hunk.ref_start + hunk.ref_count - 1 do
|
||||||
|
table.insert(lines, "- " .. (ref_lines[i] or ""))
|
||||||
|
end
|
||||||
|
elseif hunk.type == "add" then
|
||||||
|
-- 新增型 hunk:显示 buffer 中新增的内容
|
||||||
|
table.insert(lines, "新增的行:")
|
||||||
|
for i = hunk.buf_start, hunk.buf_start + hunk.buf_count - 1 do
|
||||||
|
table.insert(lines, "+ " .. (vim.api.nvim_buf_get_lines(buf, i - 1, i, false)[1] or ""))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- 修改型 hunk:显示修改前后的对比
|
||||||
|
table.insert(lines, "修改前(参考版本):")
|
||||||
|
for i = hunk.ref_start, hunk.ref_start + hunk.ref_count - 1 do
|
||||||
|
table.insert(lines, "- " .. (ref_lines[i] or ""))
|
||||||
|
end
|
||||||
|
table.insert(lines, "修改后(当前版本):")
|
||||||
|
for i = hunk.buf_start, hunk.buf_start + hunk.buf_count - 1 do
|
||||||
|
table.insert(lines, "+ " .. (vim.api.nvim_buf_get_lines(buf, i - 1, i, false)[1] or ""))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 计算浮动窗口尺寸
|
||||||
|
local width = math.min(80, vim.o.columns - 4)
|
||||||
|
local height = math.min(#lines + 2, vim.o.lines - 4)
|
||||||
|
|
||||||
|
-- 创建预览 buffer
|
||||||
|
local preview_buf = vim.api.nvim_create_buf(false, true) -- 无文件、可编辑
|
||||||
|
vim.api.nvim_buf_set_lines(preview_buf, 0, -1, false, lines)
|
||||||
|
vim.api.nvim_set_option_value("modifiable", false, { buf = preview_buf })
|
||||||
|
vim.api.nvim_set_option_value("filetype", "diff", { buf = preview_buf }) -- diff 语法高亮
|
||||||
|
|
||||||
|
-- 打开浮动窗口
|
||||||
|
local win = vim.api.nvim_open_win(preview_buf, true, {
|
||||||
|
relative = "editor",
|
||||||
|
row = math.floor((vim.o.lines - height) / 2),
|
||||||
|
col = math.floor((vim.o.columns - width) / 2),
|
||||||
|
width = width,
|
||||||
|
height = height,
|
||||||
|
style = "minimal",
|
||||||
|
border = "rounded",
|
||||||
|
title = " Hunk Preview ",
|
||||||
|
title_pos = "center",
|
||||||
|
})
|
||||||
|
|
||||||
|
-- q / Esc 关闭窗口
|
||||||
|
vim.keymap.set("n", "q", function()
|
||||||
|
vim.api.nvim_win_close(win, true)
|
||||||
|
end, { buffer = preview_buf })
|
||||||
|
vim.keymap.set("n", "<Esc>", function()
|
||||||
|
vim.api.nvim_win_close(win, true)
|
||||||
|
end, { buffer = preview_buf })
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- Blame Line — 查看当前行的 Git blame 信息
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- 执行 git blame --porcelain 获取当前行的详细提交信息,
|
||||||
|
-- 以通知消息的形式展示提交哈希、作者、时间和提交摘要。
|
||||||
|
--
|
||||||
|
-- --porcelain 格式是机器可读的 blame 输出,包含以下字段:
|
||||||
|
-- <hash> <orig-line> <final-line> [<num-lines>]
|
||||||
|
-- author <name>
|
||||||
|
-- author-mail <email>
|
||||||
|
-- author-time <timestamp>
|
||||||
|
-- author-tz <timezone>
|
||||||
|
-- summary <commit-message>
|
||||||
|
-- ...
|
||||||
|
local function blame_line()
|
||||||
|
local file = vim.api.nvim_buf_get_name(0)
|
||||||
|
if file == "" then
|
||||||
|
vim.notify("当前 buffer 无文件名", vim.log.levels.WARN)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local line = vim.api.nvim_win_get_cursor(0)[1]
|
||||||
|
-- -L 限制 blame 范围为单行,提升性能
|
||||||
|
local cmd = { "git", "blame", "-L", line .. "," .. line, "--porcelain", file }
|
||||||
|
local output = vim.fn.system(cmd)
|
||||||
|
|
||||||
|
if vim.v.shell_error ~= 0 then
|
||||||
|
vim.notify("git blame 执行失败", vim.log.levels.ERROR)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 解析 --porcelain 输出
|
||||||
|
local hash = output:match("^(%x+)%s") or "?"
|
||||||
|
local author = output:match("author ([^\n]+)") or "?"
|
||||||
|
local email = output:match("author%-mail ([^\n]+)") or "?"
|
||||||
|
local time = output:match("author%-time (%d+)")
|
||||||
|
local summary = output:match("summary ([^\n]+)") or "?"
|
||||||
|
local time_str = time and os.date("%Y-%m-%d %H:%M", tonumber(time)) or "?"
|
||||||
|
|
||||||
|
vim.notify(
|
||||||
|
string.format("%s | %s %s | %s\n%s", hash:sub(1, 8), author, email, time_str, summary),
|
||||||
|
vim.log.levels.INFO
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- 键位映射
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- <leader>ghp — 预览当前 hunk
|
||||||
|
vim.keymap.set("n", "<leader>ghp", preview_hunk, { desc = "预览 hunk" })
|
||||||
|
|
||||||
|
-- <leader>ghb — 查看当前行 blame
|
||||||
|
vim.keymap.set("n", "<leader>ghb", blame_line, { desc = "Blame 当前行" })
|
||||||
|
|
||||||
|
-- <leader>gB — 整文件 blame(使用 fugitive 的 :Git blame)
|
||||||
|
vim.keymap.set("n", "<leader>gB", function()
|
||||||
|
vim.cmd("Git blame")
|
||||||
|
end, { desc = "Blame 整个文件" })
|
||||||
|
|
||||||
|
-- <leader>gD — 查看当前文件的 git 历史
|
||||||
|
vim.keymap.set("n", "<leader>gD", function()
|
||||||
|
vim.cmd("Git log -p -- %")
|
||||||
|
end, { desc = "查看文件 Git 历史" })
|
||||||
@ -12,7 +12,6 @@
|
|||||||
-- 2. nvim-lspconfig(直接 packadd)
|
-- 2. nvim-lspconfig(直接 packadd)
|
||||||
-- 3. mason.nvim(直接 setup)
|
-- 3. mason.nvim(直接 setup)
|
||||||
-- =============================================================================
|
-- =============================================================================
|
||||||
|
|
||||||
local lazy = require("lazy")
|
local lazy = require("lazy")
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -21,47 +20,46 @@ local lazy = require("lazy")
|
|||||||
-- conform.nvim 是一个轻量级格式化器包装器,支持保存时自动格式化。
|
-- conform.nvim 是一个轻量级格式化器包装器,支持保存时自动格式化。
|
||||||
-- 由于格式化器通常不是立即需要的,通过 lazy.on_event 在 BufWritePre 时
|
-- 由于格式化器通常不是立即需要的,通过 lazy.on_event 在 BufWritePre 时
|
||||||
-- 才进行 packadd 和 setup。
|
-- 才进行 packadd 和 setup。
|
||||||
|
|
||||||
local function setup_conform()
|
local function setup_conform()
|
||||||
-- 通过 packadd 加载 conform.nvim(因为 vim.pack.add 时设置了 load = false)
|
-- 通过 packadd 加载 conform.nvim(因为 vim.pack.add 时设置了 load = false)
|
||||||
vim.cmd.packadd("conform.nvim")
|
vim.cmd.packadd("conform.nvim")
|
||||||
|
|
||||||
-- 动态判断使用 Biome 还是 Prettier。
|
-- 动态判断使用 Biome 还是 Prettier。
|
||||||
-- 从当前文件向上搜索 biome.json / biome.jsonc,如果找到则使用 Biome,
|
-- 从当前文件向上搜索 biome.json / biome.jsonc,如果找到则使用 Biome,
|
||||||
-- 否则回退到 Prettier。stop 参数限制搜索到用户主目录,避免向上搜索到根目录。
|
-- 否则回退到 Prettier。stop 参数限制搜索到用户主目录,避免向上搜索到根目录。
|
||||||
local function biome_or_prettier()
|
local function biome_or_prettier()
|
||||||
if vim.fs.find({ "biome.json", "biome.jsonc" }, { upward = true, stop = vim.uv.os_homedir() })[1] then
|
if vim.fs.find({ "biome.json", "biome.jsonc" }, { upward = true, stop = vim.uv.os_homedir() })[1] then
|
||||||
return { "biome-check", "biome", stop_after_first = true }
|
return { "biome-check", "biome", stop_after_first = true }
|
||||||
end
|
end
|
||||||
return { "prettier" }
|
return { "prettier" }
|
||||||
end
|
end
|
||||||
|
|
||||||
require("conform").setup({
|
require("conform").setup({
|
||||||
-- 按文件类型配置格式化器
|
-- 按文件类型配置格式化器
|
||||||
formatters_by_ft = {
|
formatters_by_ft = {
|
||||||
lua = { "stylua" }, -- Lua 格式化
|
lua = { "stylua" }, -- Lua 格式化
|
||||||
go = { "gofumpt", "goimports" }, -- Go:先 gofumpt 格式化,再 goimports 整理导入
|
go = { "gofumpt", "goimports" }, -- Go:先 gofumpt 格式化,再 goimports 整理导入
|
||||||
javascript = biome_or_prettier, -- JS:Biome 或 Prettier
|
javascript = biome_or_prettier, -- JS:Biome 或 Prettier
|
||||||
typescript = biome_or_prettier, -- TS:Biome 或 Prettier
|
typescript = biome_or_prettier, -- TS:Biome 或 Prettier
|
||||||
javascriptreact = biome_or_prettier, -- JSX:Biome 或 Prettier
|
javascriptreact = biome_or_prettier, -- JSX:Biome 或 Prettier
|
||||||
typescriptreact = biome_or_prettier, -- TSX:Biome 或 Prettier
|
typescriptreact = biome_or_prettier, -- TSX:Biome 或 Prettier
|
||||||
json = biome_or_prettier, -- JSON:Biome 或 Prettier
|
json = biome_or_prettier, -- JSON:Biome 或 Prettier
|
||||||
css = { "prettier" }, -- CSS:Prettier
|
css = { "prettier" }, -- CSS:Prettier
|
||||||
html = { "prettier" }, -- HTML:Prettier
|
html = { "prettier" }, -- HTML:Prettier
|
||||||
markdown = { "prettier" }, -- Markdown:Prettier
|
markdown = { "prettier" }, -- Markdown:Prettier
|
||||||
toml = { "taplo" }, -- TOML:taplo
|
toml = { "taplo" }, -- TOML:taplo
|
||||||
},
|
},
|
||||||
|
|
||||||
-- 保存时自动格式化回调
|
-- 保存时自动格式化回调
|
||||||
-- 可通过 vim.b[bufnr].autoformat = false 关闭当前 buffer 的自动格式化
|
-- 可通过 vim.b[bufnr].autoformat = false 关闭当前 buffer 的自动格式化
|
||||||
-- 或通过 vim.g.autoformat = false 全局关闭
|
-- 或通过 vim.g.autoformat = false 全局关闭
|
||||||
format_on_save = function(bufnr)
|
format_on_save = function(bufnr)
|
||||||
if vim.b[bufnr].autoformat == false or vim.g.autoformat == false then
|
if vim.b[bufnr].autoformat == false or vim.g.autoformat == false then
|
||||||
return nil -- 返回 nil 表示不格式化
|
return nil -- 返回 nil 表示不格式化
|
||||||
end
|
end
|
||||||
return { timeout_ms = 500, lsp_fallback = true }
|
return { timeout_ms = 500, lsp_fallback = true }
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- BufWritePre 时触发 conform 加载。
|
-- BufWritePre 时触发 conform 加载。
|
||||||
@ -69,11 +67,11 @@ end
|
|||||||
-- 但新创建的 autocmd 不会在同一次事件中触发。
|
-- 但新创建的 autocmd 不会在同一次事件中触发。
|
||||||
-- 因此这里手动调用 format 补偿第一次保存(确保首次保存也能格式化)。
|
-- 因此这里手动调用 format 补偿第一次保存(确保首次保存也能格式化)。
|
||||||
lazy.on_event("conform", "BufWritePre", "*", function()
|
lazy.on_event("conform", "BufWritePre", "*", function()
|
||||||
setup_conform()
|
setup_conform()
|
||||||
local bufnr = vim.api.nvim_get_current_buf()
|
local bufnr = vim.api.nvim_get_current_buf()
|
||||||
if vim.b[bufnr].autoformat ~= false and vim.g.autoformat ~= false then
|
if vim.b[bufnr].autoformat ~= false and vim.g.autoformat ~= false then
|
||||||
require("conform").format({ bufnr = bufnr, timeout_ms = 500, lsp_fallback = true })
|
require("conform").format({ bufnr = bufnr, timeout_ms = 500, lsp_fallback = true })
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -81,7 +79,6 @@ end)
|
|||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- Mason 是 LSP 服务器、DAP 适配器和格式化工具的安装管理器。
|
-- Mason 是 LSP 服务器、DAP 适配器和格式化工具的安装管理器。
|
||||||
-- nvim-lspconfig 提供常见 LSP 服务器的预设配置。
|
-- nvim-lspconfig 提供常见 LSP 服务器的预设配置。
|
||||||
|
|
||||||
vim.cmd.packadd("nvim-lspconfig")
|
vim.cmd.packadd("nvim-lspconfig")
|
||||||
lazy.track("lspconfig")
|
lazy.track("lspconfig")
|
||||||
|
|
||||||
@ -98,11 +95,11 @@ vim.lsp.config("*", { capabilities = capabilities })
|
|||||||
|
|
||||||
-- Lua 语言服务器特殊配置:将 "vim" 声明为全局变量,避免 "Undefined global" 诊断
|
-- Lua 语言服务器特殊配置:将 "vim" 声明为全局变量,避免 "Undefined global" 诊断
|
||||||
vim.lsp.config("lua_ls", {
|
vim.lsp.config("lua_ls", {
|
||||||
settings = {
|
settings = {
|
||||||
Lua = {
|
Lua = {
|
||||||
diagnostics = { globals = { "vim" } },
|
diagnostics = { globals = { "vim" } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -127,16 +124,16 @@ vim.lsp.config("lua_ls", {
|
|||||||
|
|
||||||
-- 启用指定的 LSP 服务器
|
-- 启用指定的 LSP 服务器
|
||||||
vim.lsp.enable({
|
vim.lsp.enable({
|
||||||
"html", -- HTML 语言支持
|
"html", -- HTML 语言支持
|
||||||
"cssls", -- CSS/SCSS/Less 语言支持
|
"cssls", -- CSS/SCSS/Less 语言支持
|
||||||
"gopls", -- Go 语言支持
|
"gopls", -- Go 语言支持
|
||||||
"vtsls", -- TypeScript/JavaScript 支持(推荐替代 tsserver)
|
"vtsls", -- TypeScript/JavaScript 支持(推荐替代 tsserver)
|
||||||
"rust_analyzer", -- Rust 语言支持
|
"rust_analyzer", -- Rust 语言支持
|
||||||
"lua_ls", -- Lua 语言支持
|
"lua_ls", -- Lua 语言支持
|
||||||
"taplo", -- TOML 支持
|
"taplo", -- TOML 支持
|
||||||
"svelte", -- Svelte 框架支持
|
"svelte", -- Svelte 框架支持
|
||||||
"dartls", -- Dart/Flutter 支持
|
"dartls", -- Dart/Flutter 支持
|
||||||
"kotlin_lsp", -- Kotlin 支持
|
"kotlin_lsp", -- Kotlin 支持
|
||||||
})
|
})
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -147,28 +144,28 @@ vim.lsp.enable({
|
|||||||
|
|
||||||
-- gd - Go to Definition:跳转到定义位置
|
-- gd - Go to Definition:跳转到定义位置
|
||||||
vim.keymap.set("n", "gd", function()
|
vim.keymap.set("n", "gd", function()
|
||||||
vim.lsp.buf.definition()
|
vim.lsp.buf.definition()
|
||||||
end, { desc = "跳转到定义" })
|
end, { desc = "跳转到定义" })
|
||||||
|
|
||||||
-- gh - Hover:显示光标下符号的文档悬浮窗
|
-- gh - Hover:显示光标下符号的文档悬浮窗
|
||||||
vim.keymap.set("n", "gh", function()
|
vim.keymap.set("n", "gh", function()
|
||||||
vim.lsp.buf.hover()
|
vim.lsp.buf.hover()
|
||||||
end, { desc = "悬停查看文档" })
|
end, { desc = "悬停查看文档" })
|
||||||
|
|
||||||
-- <leader>fm - 手动格式化当前 buffer
|
-- <leader>fm - 手动格式化当前 buffer
|
||||||
vim.keymap.set("n", "<leader>fm", function()
|
vim.keymap.set("n", "<leader>fm", function()
|
||||||
lazy.load("conform", setup_conform)
|
lazy.load("conform", setup_conform)
|
||||||
require("conform").format({ lsp_fallback = true })
|
require("conform").format({ lsp_fallback = true })
|
||||||
end, { desc = "格式化当前 Buffer" })
|
end, { desc = "格式化当前 Buffer" })
|
||||||
|
|
||||||
-- df - 显示当前行的诊断浮动窗口
|
-- df - 显示当前行的诊断浮动窗口
|
||||||
vim.keymap.set("n", "df", function()
|
vim.keymap.set("n", "df", function()
|
||||||
vim.diagnostic.open_float()
|
vim.diagnostic.open_float()
|
||||||
end, { desc = "显示行诊断" })
|
end, { desc = "显示行诊断" })
|
||||||
|
|
||||||
-- <leader>ca - Code Action:显示可用的代码操作(如自动修复、重构)
|
-- <leader>ca - Code Action:显示可用的代码操作(如自动修复、重构)
|
||||||
vim.keymap.set("n", "<leader>ca", function()
|
vim.keymap.set("n", "<leader>ca", function()
|
||||||
vim.lsp.buf.code_action()
|
vim.lsp.buf.code_action()
|
||||||
end, { desc = "代码操作" })
|
end, { desc = "代码操作" })
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -182,25 +179,25 @@ end, { desc = "代码操作" })
|
|||||||
-- vim.v.count1 是计数前缀的默认值(无数字时为 1),
|
-- vim.v.count1 是计数前缀的默认值(无数字时为 1),
|
||||||
-- 支持 3]d 跳转到第 3 个诊断。
|
-- 支持 3]d 跳转到第 3 个诊断。
|
||||||
local diagnostic_goto = function(next, severity)
|
local diagnostic_goto = function(next, severity)
|
||||||
return function()
|
return function()
|
||||||
vim.diagnostic.jump({
|
vim.diagnostic.jump({
|
||||||
count = (next and 1 or -1) * vim.v.count1,
|
count = (next and 1 or -1) * vim.v.count1,
|
||||||
severity = severity and vim.diagnostic.severity[severity] or nil,
|
severity = severity and vim.diagnostic.severity[severity] or nil,
|
||||||
float = true, -- 跳转时显示诊断浮动窗口
|
float = true, -- 跳转时显示诊断浮动窗口
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ]d / [d - 下一个 / 上一个诊断(所有级别)
|
-- ]d / [d - 下一个 / 上一个诊断(所有级别)
|
||||||
vim.keymap.set("n", "]d", diagnostic_goto(true), { desc = "下一个诊断" })
|
vim.keymap.set("n", "]d", diagnostic_goto(true), { desc = "下一个诊断" })
|
||||||
vim.keymap.set("n", "[d", diagnostic_goto(false), { desc = "上一个诊断" })
|
vim.keymap.set("n", "[d", diagnostic_goto(false), { desc = "上一个诊断" })
|
||||||
|
|
||||||
-- ]e / [e - 下一个 / 上一个错误
|
-- ]e / [e - 下一个 / 上一个错误
|
||||||
vim.keymap.set("n", "]e", diagnostic_goto(true, "ERROR"), { desc = "下一个错误" })
|
vim.keymap.set("n", "]e", diagnostic_goto(true, "ERROR"), { desc = "下一个错误" })
|
||||||
vim.keymap.set("n", "[e", diagnostic_goto(false, "ERROR"), { desc = "上一个错误" })
|
vim.keymap.set("n", "[e", diagnostic_goto(false, "ERROR"), { desc = "上一个错误" })
|
||||||
|
|
||||||
-- ]w / [w - 下一个 / 上一个警告
|
-- ]w / [w - 下一个 / 上一个警告
|
||||||
vim.keymap.set("n", "]w", diagnostic_goto(true, "WARN"), { desc = "下一个警告" })
|
vim.keymap.set("n", "]w", diagnostic_goto(true, "WARN"), { desc = "下一个警告" })
|
||||||
vim.keymap.set("n", "[w", diagnostic_goto(false, "WARN"), { desc = "上一个警告" })
|
vim.keymap.set("n", "[w", diagnostic_goto(false, "WARN"), { desc = "上一个警告" })
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
121
lua/plugins/pick.lua
Normal file
121
lua/plugins/pick.lua
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
-- =============================================================================
|
||||||
|
-- mini.pick 封装 (lua/pick.lua)
|
||||||
|
-- =============================================================================
|
||||||
|
-- 本模块封装 mini.pick 和 mini.extra 的初始化逻辑,
|
||||||
|
-- 提供统一的懒加载入口和自定义 picker。
|
||||||
|
--
|
||||||
|
-- 主要功能:
|
||||||
|
-- 1. load_pick() — 懒加载 mini.pick 和 mini.extra
|
||||||
|
-- 2. Buffer picker(<leader><leader>)— 自定义 buffer 列表,支持 <C-d> 删除
|
||||||
|
-- 3. Filetype picker(<leader>ft)— 快速切换文件类型
|
||||||
|
-- =============================================================================
|
||||||
|
local lazy = require("lazy")
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- 懒加载入口
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- 通过 lazy.load 确保 mini.pick 和 mini.extra 只初始化一次。
|
||||||
|
-- 此函数被 pack.lua 中所有 pick 相关的 on_keys 映射共用。
|
||||||
|
M.load_pick = function()
|
||||||
|
lazy.load("pick", function()
|
||||||
|
require("mini.pick").setup()
|
||||||
|
end)
|
||||||
|
lazy.load("extra", function()
|
||||||
|
require("mini.extra").setup()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- Buffer Picker(<leader><leader>)
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- 显示当前打开的 buffer 列表,按最近使用时间排序。
|
||||||
|
-- 特殊功能:
|
||||||
|
-- - <C-d>:删除当前选中的 buffer(带图标过滤)
|
||||||
|
-- - 支持 mini.icons 图标显示
|
||||||
|
vim.keymap.set("n", "<leader><leader>", function()
|
||||||
|
M.load_pick()
|
||||||
|
local MiniPick = require("mini.pick")
|
||||||
|
|
||||||
|
-- 删除当前选中 buffer 的回调函数
|
||||||
|
local delete_buf = function()
|
||||||
|
local matches = MiniPick.get_picker_matches()
|
||||||
|
local item = matches and matches.current
|
||||||
|
if not item or not item.bufnr then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local bufnr = item.bufnr
|
||||||
|
|
||||||
|
-- 安全删除 buffer(force = true 跳过未保存确认)
|
||||||
|
pcall(vim.api.nvim_buf_delete, bufnr, { force = true })
|
||||||
|
|
||||||
|
-- 如果 picker 仍活跃,刷新列表以移除已删除的 buffer
|
||||||
|
if MiniPick.is_picker_active() then
|
||||||
|
local items = vim.tbl_filter(function(i)
|
||||||
|
return i.bufnr and vim.api.nvim_buf_is_valid(i.bufnr)
|
||||||
|
end, MiniPick.get_picker_items() or {})
|
||||||
|
MiniPick.set_picker_items(items)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 获取所有普通 buffer(排除特殊 buffer 如终端、quickfix)
|
||||||
|
local bufs = vim.tbl_filter(function(b)
|
||||||
|
return vim.bo[b.bufnr].buftype == "" and b.listed == 1
|
||||||
|
end, vim.fn.getbufinfo())
|
||||||
|
|
||||||
|
-- 按最后使用时间降序排列(最近使用的在前)
|
||||||
|
table.sort(bufs, function(a, b)
|
||||||
|
return a.lastused > b.lastused
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- 构建 picker items
|
||||||
|
local items = {}
|
||||||
|
for _, info in ipairs(bufs) do
|
||||||
|
-- 相对路径显示(当前工作目录为基准)
|
||||||
|
local name = info.name ~= "" and vim.fn.fnamemodify(info.name, ":.") or "[No Name]"
|
||||||
|
table.insert(items, {
|
||||||
|
text = name,
|
||||||
|
bufnr = info.bufnr,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 启动 picker
|
||||||
|
MiniPick.start({
|
||||||
|
source = {
|
||||||
|
name = "Buffers",
|
||||||
|
items = items,
|
||||||
|
show = function(buf_id, items_arr, query)
|
||||||
|
-- 使用默认显示函数,启用图标
|
||||||
|
MiniPick.default_show(buf_id, items_arr, query, { show_icons = true })
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
mappings = {
|
||||||
|
delete_buffer = { char = "<C-d>", func = delete_buf },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end, { desc = "Buffer 列表" })
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- Filetype Picker(<leader>ft)
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- 显示所有可用的文件类型列表,选择后设置当前 buffer 的 filetype。
|
||||||
|
-- 常用于打开无扩展名文件或纠正错误的文件类型检测。
|
||||||
|
vim.keymap.set("n", "<leader>ft", function()
|
||||||
|
M.load_pick()
|
||||||
|
local MiniPick = require("mini.pick")
|
||||||
|
-- 获取所有可用的文件类型名称
|
||||||
|
local filetypes = vim.fn.getcompletion("", "filetype")
|
||||||
|
MiniPick.start({
|
||||||
|
source = {
|
||||||
|
name = "Filetypes",
|
||||||
|
items = filetypes,
|
||||||
|
choose = function(item)
|
||||||
|
-- 选择后将当前 buffer 的 filetype 设为选中值
|
||||||
|
vim.bo.filetype = item
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end, { desc = "切换文件类型" })
|
||||||
|
|
||||||
|
return M
|
||||||
92
lua/plugins/treesitter.lua
Normal file
92
lua/plugins/treesitter.lua
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
-- =============================================================================
|
||||||
|
-- Treesitter 配置 (lua/treesitter.lua)
|
||||||
|
-- =============================================================================
|
||||||
|
-- 本模块配置 Neovim 的 Treesitter 集成,提供语法树驱动的语法高亮、
|
||||||
|
-- 代码折叠和文本对象支持。
|
||||||
|
--
|
||||||
|
-- 加载方式:
|
||||||
|
-- 由 pack.lua 通过 lazy.on_event("treesitter", "VimEnter", "*", ...) 延迟加载。
|
||||||
|
--
|
||||||
|
-- 设计要点:
|
||||||
|
-- 1. Parser 安装延迟 100ms 执行,避免阻塞 startup
|
||||||
|
-- 2. 高亮按 buffer 动态附加(FileType autocmd),只安装需要的 parser
|
||||||
|
-- =============================================================================
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- 预安装的 parser 列表
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- 这些 parser 会在首次启动后延迟安装。
|
||||||
|
-- 如果某个 parser 未在此列表中,打开对应文件类型时仍可通过 nvim-treesitter
|
||||||
|
-- 的 :TSInstall 手动安装。
|
||||||
|
local ensure_installed = {
|
||||||
|
"lua",
|
||||||
|
"vim",
|
||||||
|
"vimdoc",
|
||||||
|
-- Web 前端
|
||||||
|
"javascript",
|
||||||
|
"typescript",
|
||||||
|
"tsx", -- TypeScript JSX
|
||||||
|
"jsdoc", -- JSDoc 注释
|
||||||
|
"json",
|
||||||
|
"html",
|
||||||
|
"css",
|
||||||
|
"yaml",
|
||||||
|
-- 后端
|
||||||
|
"c",
|
||||||
|
"rust",
|
||||||
|
"toml",
|
||||||
|
"go",
|
||||||
|
"gomod", -- Go Modules
|
||||||
|
"gosum", -- Go Sum
|
||||||
|
"gowork", -- Go Workspaces
|
||||||
|
-- 基础设施
|
||||||
|
"dockerfile",
|
||||||
|
"make",
|
||||||
|
}
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- 模块初始化
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
M.setup = function()
|
||||||
|
-- 加载 nvim-treesitter(通过 packadd 激活 opt 插件)
|
||||||
|
vim.cmd.packadd("nvim-treesitter")
|
||||||
|
local treesitter = require("nvim-treesitter")
|
||||||
|
|
||||||
|
-- 延迟安装 parser:在 startup 完成 100ms 后后台安装,
|
||||||
|
-- 避免在安装过程中阻塞编辑器。
|
||||||
|
vim.defer_fn(function()
|
||||||
|
treesitter.install(ensure_installed)
|
||||||
|
end, 100)
|
||||||
|
|
||||||
|
-- 按文件类型动态启用 treesitter 高亮。
|
||||||
|
-- 当文件的 filetype 被设置时(BufRead、:setfiletype 等),
|
||||||
|
-- 尝试查找并加载对应的 parser,成功后启用高亮。
|
||||||
|
vim.api.nvim_create_autocmd("FileType", {
|
||||||
|
pattern = "*", -- 匹配所有文件类型
|
||||||
|
callback = function(args)
|
||||||
|
local buf = args.buf
|
||||||
|
local ft = vim.bo[buf].filetype
|
||||||
|
|
||||||
|
-- 将文件类型映射到 treesitter 语言名
|
||||||
|
-- 例如 "javascriptreact" → "javascript"
|
||||||
|
local lang = vim.treesitter.language.get_lang(ft)
|
||||||
|
if not lang then
|
||||||
|
return -- 无对应语言,跳过
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 尝试注册语言(如果 parser 已安装)
|
||||||
|
-- pcall 用于安全调用:parser 未安装时不会报错
|
||||||
|
local ok_add = pcall(vim.treesitter.language.add, lang)
|
||||||
|
if not ok_add then
|
||||||
|
return -- parser 未安装,跳过
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 启用 treesitter 高亮
|
||||||
|
pcall(vim.treesitter.start, buf, lang)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
@ -1,93 +0,0 @@
|
|||||||
-- =============================================================================
|
|
||||||
-- Treesitter 配置 (lua/treesitter.lua)
|
|
||||||
-- =============================================================================
|
|
||||||
-- 本模块配置 Neovim 的 Treesitter 集成,提供语法树驱动的语法高亮、
|
|
||||||
-- 代码折叠和文本对象支持。
|
|
||||||
--
|
|
||||||
-- 加载方式:
|
|
||||||
-- 由 pack.lua 通过 lazy.on_event("treesitter", "VimEnter", "*", ...) 延迟加载。
|
|
||||||
--
|
|
||||||
-- 设计要点:
|
|
||||||
-- 1. Parser 安装延迟 100ms 执行,避免阻塞 startup
|
|
||||||
-- 2. 高亮按 buffer 动态附加(FileType autocmd),只安装需要的 parser
|
|
||||||
-- =============================================================================
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- 预安装的 parser 列表
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- 这些 parser 会在首次启动后延迟安装。
|
|
||||||
-- 如果某个 parser 未在此列表中,打开对应文件类型时仍可通过 nvim-treesitter
|
|
||||||
-- 的 :TSInstall 手动安装。
|
|
||||||
|
|
||||||
local ensure_installed = {
|
|
||||||
"lua",
|
|
||||||
"vim",
|
|
||||||
"vimdoc",
|
|
||||||
-- Web 前端
|
|
||||||
"javascript",
|
|
||||||
"typescript",
|
|
||||||
"tsx", -- TypeScript JSX
|
|
||||||
"jsdoc", -- JSDoc 注释
|
|
||||||
"json",
|
|
||||||
"html",
|
|
||||||
"css",
|
|
||||||
"yaml",
|
|
||||||
-- 后端
|
|
||||||
"c",
|
|
||||||
"rust",
|
|
||||||
"toml",
|
|
||||||
"go",
|
|
||||||
"gomod", -- Go Modules
|
|
||||||
"gosum", -- Go Sum
|
|
||||||
"gowork", -- Go Workspaces
|
|
||||||
-- 基础设施
|
|
||||||
"dockerfile",
|
|
||||||
"make",
|
|
||||||
}
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
-- 模块初始化
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
M.setup = function()
|
|
||||||
-- 加载 nvim-treesitter(通过 packadd 激活 opt 插件)
|
|
||||||
vim.cmd.packadd("nvim-treesitter")
|
|
||||||
local treesitter = require("nvim-treesitter")
|
|
||||||
|
|
||||||
-- 延迟安装 parser:在 startup 完成 100ms 后后台安装,
|
|
||||||
-- 避免在安装过程中阻塞编辑器。
|
|
||||||
vim.defer_fn(function()
|
|
||||||
treesitter.install(ensure_installed)
|
|
||||||
end, 100)
|
|
||||||
|
|
||||||
-- 按文件类型动态启用 treesitter 高亮。
|
|
||||||
-- 当文件的 filetype 被设置时(BufRead、:setfiletype 等),
|
|
||||||
-- 尝试查找并加载对应的 parser,成功后启用高亮。
|
|
||||||
vim.api.nvim_create_autocmd("FileType", {
|
|
||||||
pattern = "*", -- 匹配所有文件类型
|
|
||||||
callback = function(args)
|
|
||||||
local buf = args.buf
|
|
||||||
local ft = vim.bo[buf].filetype
|
|
||||||
|
|
||||||
-- 将文件类型映射到 treesitter 语言名
|
|
||||||
-- 例如 "javascriptreact" → "javascript"
|
|
||||||
local lang = vim.treesitter.language.get_lang(ft)
|
|
||||||
if not lang then
|
|
||||||
return -- 无对应语言,跳过
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 尝试注册语言(如果 parser 已安装)
|
|
||||||
-- pcall 用于安全调用:parser 未安装时不会报错
|
|
||||||
local ok_add = pcall(vim.treesitter.language.add, lang)
|
|
||||||
if not ok_add then
|
|
||||||
return -- parser 未安装,跳过
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 启用 treesitter 高亮
|
|
||||||
pcall(vim.treesitter.start, buf, lang)
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -23,9 +23,8 @@
|
|||||||
-- vim.pack 会从 GitHub 下载插件到 stdpath("data")/site/pack/core/opt/。
|
-- vim.pack 会从 GitHub 下载插件到 stdpath("data")/site/pack/core/opt/。
|
||||||
--
|
--
|
||||||
-- nargs = "+" 表示至少需要 1 个参数。
|
-- nargs = "+" 表示至少需要 1 个参数。
|
||||||
|
|
||||||
vim.api.nvim_create_user_command("PackAdd", function(opts)
|
vim.api.nvim_create_user_command("PackAdd", function(opts)
|
||||||
vim.pack.add(opts.fargs)
|
vim.pack.add(opts.fargs)
|
||||||
end, { nargs = "+", desc = "添加插件 (:PackAdd user/repo1 user/repo2)" })
|
end, { nargs = "+", desc = "添加插件 (:PackAdd user/repo1 user/repo2)" })
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -39,9 +38,8 @@ end, { nargs = "+", desc = "添加插件 (:PackAdd user/repo1 user/repo2)" })
|
|||||||
-- Neovim 0.13 Nightly 已内置此命令,这里为 0.12 提供兼容。
|
-- Neovim 0.13 Nightly 已内置此命令,这里为 0.12 提供兼容。
|
||||||
--
|
--
|
||||||
-- nargs = "+" 表示至少需要 1 个参数。
|
-- nargs = "+" 表示至少需要 1 个参数。
|
||||||
|
|
||||||
vim.api.nvim_create_user_command("PackDel", function(opts)
|
vim.api.nvim_create_user_command("PackDel", function(opts)
|
||||||
vim.pack.del(opts.fargs)
|
vim.pack.del(opts.fargs)
|
||||||
end, { nargs = "+", desc = "删除插件 (:PackDel plugin1 plugin2)" })
|
end, { nargs = "+", desc = "删除插件 (:PackDel plugin1 plugin2)" })
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@ -57,16 +55,15 @@ end, { nargs = "+", desc = "删除插件 (:PackDel plugin1 plugin2)" })
|
|||||||
-- 如果无参数,调用无参版本更新所有插件。
|
-- 如果无参数,调用无参版本更新所有插件。
|
||||||
--
|
--
|
||||||
-- nargs = "*" 表示接受 0 个或多个参数。
|
-- nargs = "*" 表示接受 0 个或多个参数。
|
||||||
|
|
||||||
vim.api.nvim_create_user_command("PackUpdate", function(opts)
|
vim.api.nvim_create_user_command("PackUpdate", function(opts)
|
||||||
-- 检查是否有传入任何参数(包含非空白字符)
|
-- 检查是否有传入任何参数(包含非空白字符)
|
||||||
if opts.args:match("%S") then
|
if opts.args:match("%S") then
|
||||||
-- 按空白字符分割参数,trimempty 去除空字符串
|
-- 按空白字符分割参数,trimempty 去除空字符串
|
||||||
local plugins = vim.split(opts.args, "%s+", { trimempty = true })
|
local plugins = vim.split(opts.args, "%s+", { trimempty = true })
|
||||||
-- 仅更新指定的插件
|
-- 仅更新指定的插件
|
||||||
vim.pack.update(plugins)
|
vim.pack.update(plugins)
|
||||||
else
|
else
|
||||||
-- 无参数,更新所有插件
|
-- 无参数,更新所有插件
|
||||||
vim.pack.update()
|
vim.pack.update()
|
||||||
end
|
end
|
||||||
end, { nargs = "*", desc = "更新所有插件或指定插件" })
|
end, { nargs = "*", desc = "更新所有插件或指定插件" })
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user