diff --git a/nvim/lua/plugins/cmp.lua b/nvim/lua/plugins/cmp.lua new file mode 100644 index 0000000..142cb92 --- /dev/null +++ b/nvim/lua/plugins/cmp.lua @@ -0,0 +1,34 @@ +-- cmp.lua - 自动补全配置 +return { + { + "hrsh7th/nvim-cmp", + dependencies = { + "hrsh7th/cmp-nvim-lsp", + "hrsh7th/cmp-buffer", + "hrsh7th/cmp-path", + "L3MON4D3/LuaSnip", + "saadparwaiz1/cmp_luasnip", + }, + event = "InsertEnter", + opts = function() + local cmp = require("cmp") + return { + snippet = { + expand = function(args) + require("luasnip").lsp_expand(args.body) + end, + }, + mapping = cmp.mapping.preset.insert({ + [""] = cmp.mapping.complete(), + [""] = cmp.mapping.confirm({ select = true }), + }), + sources = cmp.config.sources({ + { name = "nvim_lsp" }, + { name = "luasnip" }, + { name = "buffer" }, + { name = "path" }, + }), + } + end, + }, +} diff --git a/nvim/lua/plugins/coding.lua b/nvim/lua/plugins/coding.lua new file mode 100644 index 0000000..7e1c91e --- /dev/null +++ b/nvim/lua/plugins/coding.lua @@ -0,0 +1,625 @@ +-- coding.lua - 代码增强插件配置 + +return { + -- LSP 配置 + { + "neovim/nvim-lspconfig", + event = { "BufReadPre", "BufNewFile" }, + dependencies = { + -- LSP 管理器 + { "williamboman/mason.nvim" }, + { "williamboman/mason-lspconfig.nvim" }, + + -- 自动安装 LSP + { "WhoIsSethDaniel/mason-tool-installer.nvim" }, + + -- 显示 LSP 进度 + { "j-hui/fidget.nvim", opts = {} }, + + -- 额外 LSP 功能 + { "folke/neodev.nvim", opts = {} }, + }, + opts = { + -- LSP 服务器诊断设置 + diagnostics = { + underline = true, + update_in_insert = false, + virtual_text = { + spacing = 4, + source = "if_many", + prefix = "●", + }, + severity_sort = true, + signs = { + text = { + [vim.diagnostic.severity.ERROR] = "✘", + [vim.diagnostic.severity.WARN] = "▲", + [vim.diagnostic.severity.HINT] = "⚑", + [vim.diagnostic.severity.INFO] = "»", + }, + }, + }, + + -- 自动格式化 + format = { + formatting_options = nil, + timeout_ms = 1000, + }, + + -- LSP 服务器设置 + servers = { + -- 根据语言配置服务器 + lua_ls = { + settings = { + Lua = { + completion = { + callSnippet = "Replace", + }, + workspace = { + checkThirdParty = false, + }, + telemetry = { + enable = false, + }, + diagnostics = { + globals = { "vim" }, + }, + }, + }, + }, + + -- Python 服务器 + pyright = { + settings = { + python = { + analysis = { + typeCheckingMode = "basic", + autoSearchPaths = true, + useLibraryCodeForTypes = true, + diagnosticMode = "workspace", + }, + }, + }, + }, + ruff_lsp = { + -- Ruff 会处理导入和排序 + init_options = { + settings = { + args = {}, + }, + }, + }, + + -- Go 服务器 + gopls = { + settings = { + gopls = { + gofumpt = true, + codelenses = { + gc_details = true, + generate = true, + regenerate_cgo = true, + run_govulncheck = true, + test = true, + tidy = true, + upgrade_dependency = true, + vendor = true, + }, + hints = { + assignVariableTypes = true, + compositeLiteralFields = true, + compositeLiteralTypes = true, + constantValues = true, + functionTypeParameters = true, + parameterNames = true, + rangeVariableTypes = true, + }, + analyses = { + fieldalignment = true, + nilness = true, + unusedparams = true, + unusedwrite = true, + useany = true, + shadow = true, + }, + usePlaceholders = true, + completeUnimported = true, + staticcheck = true, + directoryFilters = { "-.git", "-.vscode", "-.idea", "-.vscode-test", "-node_modules" }, + semanticTokens = true, + }, + }, + }, + }, + + -- 自动设置功能 + setup = { + ruff_lsp = function() + require("lazyvim.util").lsp.on_attach(function(client, _) + -- 禁用 ruff 格式化功能,由 none-ls 处理 + if client.name == "ruff_lsp" then + client.server_capabilities.documentFormattingProvider = false + end + end) + end, + }, + }, + config = function(_, opts) + -- 设置诊断标志 + for name, icon in pairs(opts.diagnostics.signs.text) do + name = "DiagnosticSign" .. name + vim.fn.sign_define(name, { text = icon, texthl = name, numhl = "" }) + end + + -- 配置诊断 + vim.diagnostic.config(vim.deepcopy(opts.diagnostics)) + + -- 设置 LSP 的键绑定和自动命令 + vim.api.nvim_create_autocmd("LspAttach", { + callback = function(args) + local buffer = args.buf + local client = vim.lsp.get_client_by_id(args.data.client_id) + + -- 设置 LSP 键绑定 + local map = function(mode, l, r, opts_) + opts_ = opts_ or {} + opts_.silent = true + opts_.buffer = buffer + vim.keymap.set(mode, l, r, opts_) + end + + -- 导航键绑定 + map("n", "gd", "Telescope lsp_definitions", { desc = "转到定义" }) + map("n", "gr", "Telescope lsp_references", { desc = "查找引用" }) + map("n", "gD", vim.lsp.buf.declaration, { desc = "转到声明" }) + map("n", "gI", "Telescope lsp_implementations", { desc = "转到实现" }) + map("n", "gt", "Telescope lsp_type_definitions", { desc = "转到类型定义" }) + map("n", "K", vim.lsp.buf.hover, { desc = "显示悬停信息" }) + map("n", "gK", vim.lsp.buf.signature_help, { desc = "显示签名帮助" }) + + -- 代码操作键绑定 + map("n", "ca", vim.lsp.buf.code_action, { desc = "代码操作" }) + map("n", "cr", vim.lsp.buf.rename, { desc = "重命名" }) + + -- 诊断键绑定 + map("n", "]d", vim.diagnostic.goto_next, { desc = "下一个诊断" }) + map("n", "[d", vim.diagnostic.goto_prev, { desc = "上一个诊断" }) + map("n", "cd", vim.diagnostic.open_float, { desc = "行诊断" }) + map("n", "cl", "LspInfo", { desc = "LSP 信息" }) + + -- 格式化文档(如果服务器支持) + if client and client.supports_method("textDocument/formatting") then + map("n", "cf", vim.lsp.buf.format, { desc = "格式化代码" }) + end + end, + }) + + -- 设置 LSP 服务器 + local capabilities = vim.tbl_deep_extend( + "force", + {}, + vim.lsp.protocol.make_client_capabilities(), + require("cmp_nvim_lsp").default_capabilities(), + opts.capabilities or {} + ) + + -- 为 Lua 开发环境配置 + require("neodev").setup({ + library = { + plugins = { "nvim-dap-ui" }, + types = true, + }, + }) + + -- 设置 mason-lspconfig + require("mason").setup() + + local ensure_installed = {} -- 要安装的服务器列表 + + -- 收集需要安装的服务器 + for server, server_opts in pairs(opts.servers) do + if server_opts then + server_opts = server_opts == true and {} or server_opts + -- 将服务器添加到安装列表 + ensure_installed[#ensure_installed + 1] = server + end + end + + -- 设置 mason-lspconfig + require("mason-lspconfig").setup({ + ensure_installed = vim.tbl_keys(ensure_installed), + automatic_installation = true, + }) + + -- 设置工具安装程序 + require("mason-tool-installer").setup({ + ensure_installed = { + -- Python 工具 + "black", + "isort", + "mypy", + "ruff", + "debugpy", + + -- Go 工具 + "gofumpt", + "goimports", + "golangci-lint", + "delve", + + -- 通用工具 + "stylua", + "shfmt", + }, + }) + + -- 启动服务器 + require("mason-lspconfig").setup_handlers({ + function(server) + local server_opts = vim.tbl_deep_extend("force", { + capabilities = vim.deepcopy(capabilities), + }, opts.servers[server] or {}) + + -- 特殊设置钩子 + if opts.setup[server] then + if opts.setup[server](server, server_opts) then + return + end + end + + -- 启动服务器 + require("lspconfig")[server].setup(server_opts) + end, + }) + end, + }, + + -- 自动完成 + { + "hrsh7th/nvim-cmp", + version = false, + event = "InsertEnter", + dependencies = { + "hrsh7th/cmp-nvim-lsp", + "hrsh7th/cmp-buffer", + "hrsh7th/cmp-path", + "saadparwaiz1/cmp_luasnip", + "hrsh7th/cmp-cmdline", + }, + opts = function() + vim.api.nvim_set_hl(0, "CmpGhostText", { link = "Comment", default = true }) + local cmp = require("cmp") + local luasnip = require("luasnip") + + local function has_words_before() + unpack = unpack or table.unpack + local line, col = unpack(vim.api.nvim_win_get_cursor(0)) + return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil + end + + return { + completion = { + completeopt = "menu,menuone,noinsert", + }, + snippet = { + expand = function(args) + luasnip.lsp_expand(args.body) + end, + }, + mapping = cmp.mapping.preset.insert({ + [""] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }), + [""] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }), + [""] = cmp.mapping.scroll_docs(-4), + [""] = cmp.mapping.scroll_docs(4), + [""] = cmp.mapping.complete(), + [""] = cmp.mapping.abort(), + [""] = cmp.mapping.confirm({ select = true }), + [""] = cmp.mapping.confirm({ + behavior = cmp.ConfirmBehavior.Replace, + select = true, + }), + [""] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_next_item() + elseif luasnip.expand_or_jumpable() then + luasnip.expand_or_jump() + elseif has_words_before() then + cmp.complete() + else + fallback() + end + end, { "i", "s" }), + [""] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_prev_item() + elseif luasnip.jumpable(-1) then + luasnip.jump(-1) + else + fallback() + end + end, { "i", "s" }), + }), + sources = cmp.config.sources({ + { name = "nvim_lsp", priority = 1000 }, + { name = "luasnip", priority = 750 }, + { name = "buffer", priority = 500 }, + { name = "path", priority = 250 }, + }), + formatting = { + format = function(entry, vim_item) + -- 添加源信息 + vim_item.menu = ({ + nvim_lsp = "[LSP]", + luasnip = "[Snip]", + buffer = "[Buf]", + path = "[Path]", + })[entry.source.name] + + -- 设置最大宽度 + local MAX_LABEL_WIDTH = 50 + if #vim_item.abbr > MAX_LABEL_WIDTH then + vim_item.abbr = vim_item.abbr:sub(1, MAX_LABEL_WIDTH) .. "..." + end + + return vim_item + end, + }, + experimental = { + ghost_text = { + hl_group = "CmpGhostText", + }, + }, + } + end, + config = function(_, opts) + -- 设置 nvim-cmp + local cmp = require("cmp") + cmp.setup(opts) + + -- 为命令行设置完成 + cmp.setup.cmdline(":", { + mapping = cmp.mapping.preset.cmdline(), + sources = cmp.config.sources({ + { name = "path" }, + { name = "cmdline" }, + }), + }) + + -- 为搜索设置完成 + cmp.setup.cmdline("/", { + mapping = cmp.mapping.preset.cmdline(), + sources = cmp.config.sources({ + { name = "buffer" }, + }), + }) + end, + }, + + -- 代码格式化和 Linting + { + "stevearc/conform.nvim", + event = { "BufReadPre", "BufNewFile" }, + cmd = { "ConformInfo" }, + keys = { + { + "cf", + function() + require("conform").format({ lsp_fallback = true, async = false }) + end, + mode = { "n", "v" }, + desc = "格式化代码", + }, + }, + opts = { + formatters_by_ft = { + lua = { "stylua" }, + python = { "isort", "black" }, + go = { "goimports", "gofumpt" }, + javascript = { "prettierd" }, + typescript = { "prettierd" }, + javascriptreact = { "prettierd" }, + typescriptreact = { "prettierd" }, + json = { "prettierd" }, + html = { "prettierd" }, + css = { "prettierd" }, + yaml = { "prettierd" }, + markdown = { "prettierd" }, + sh = { "shfmt" }, + }, + + -- 每个格式化工具的设置 + formatters = { + black = { + args = { "--line-length", "88", "--fast", "-" }, + }, + isort = { + args = { "--stdout", "--profile", "black", "--line-length", "88", "-" }, + }, + stylua = { + args = { "--indent-type", "Spaces", "--indent-width", "2", "-" }, + }, + }, + + -- 保存时自动格式化 + format_on_save = function(bufnr) + if vim.b[bufnr].disable_autoformat or vim.g.disable_autoformat then + return + end + return { timeout_ms = 500, lsp_fallback = true } + end, + + -- 格式化超时时间 + format_after_save = function(bufnr) + if vim.b[bufnr].disable_autoformat or vim.g.disable_autoformat then + return + end + return { lsp_fallback = true } + end, + }, + init = function() + -- 添加用户命令以切换格式化 + vim.api.nvim_create_user_command("FormatToggle", function(args) + if args.bang then + -- FormatToggle! 将为当前缓冲区切换格式化 + vim.b.disable_autoformat = not vim.b.disable_autoformat + vim.notify(string.format("Buffer autoformatting %s", vim.b.disable_autoformat and "disabled" or "enabled")) + else + -- FormatToggle 将全局切换格式化 + vim.g.disable_autoformat = not vim.g.disable_autoformat + vim.notify(string.format("Global autoformatting %s", vim.g.disable_autoformat and "disabled" or "enabled")) + end + end, { desc = "切换自动格式化", bang = true }) + end, + }, + + -- 调试支持 + { + "mfussenegger/nvim-dap", + dependencies = { + -- UI 相关 + { + "rcarriga/nvim-dap-ui", + keys = { + { "du", function() require("dapui").toggle() end, desc = "Dap UI" }, + }, + opts = {}, + config = function(_, opts) + local dap = require("dap") + local dapui = require("dapui") + dapui.setup(opts) + dap.listeners.after.event_initialized["dapui_config"] = function() + dapui.open() + end + dap.listeners.before.event_terminated["dapui_config"] = function() + dapui.close() + end + dap.listeners.before.event_exited["dapui_config"] = function() + dapui.close() + end + end, + }, + -- 虚拟文本支持 + { + "theHamsta/nvim-dap-virtual-text", + opts = {}, + }, + -- Python 调试支持 + { + "mfussenegger/nvim-dap-python", + config = function() + local path = require("mason-registry").get_package("debugpy"):get_install_path() + require("dap-python").setup(path .. "/venv/bin/python") + end, + }, + -- Go 调试支持 + { + "leoluz/nvim-dap-go", + config = true, + }, + }, + keys = { + { "dB", function() require("dap").set_breakpoint(vim.fn.input('断点条件: ')) end, desc = "条件断点" }, + { "db", function() require("dap").toggle_breakpoint() end, desc = "切换断点" }, + { "dc", function() require("dap").continue() end, desc = "继续执行" }, + { "da", function() require("dap").continue({ before = get_args }) end, desc = "带参数运行" }, + { "dC", function() require("dap").run_to_cursor() end, desc = "运行到光标处" }, + { "dg", function() require("dap").goto_() end, desc = "跳转到行" }, + { "di", function() require("dap").step_into() end, desc = "单步进入" }, + { "dj", function() require("dap").down() end, desc = "下栈帧" }, + { "dk", function() require("dap").up() end, desc = "上栈帧" }, + { "dl", function() require("dap").run_last() end, desc = "运行最后的配置" }, + { "do", function() require("dap").step_out() end, desc = "单步跳出" }, + { "dO", function() require("dap").step_over() end, desc = "单步跳过" }, + { "dp", function() require("dap").pause() end, desc = "暂停执行" }, + { "dr", function() require("dap").repl.toggle() end, desc = "切换 REPL" }, + { "ds", function() require("dap").session() end, desc = "获取会话" }, + { "dt", function() require("dap").terminate() end, desc = "终止调试" }, + { "dw", function() require("dap.ui.widgets").hover() end, desc = "小部件" }, + }, + config = function() + local icons = { + dap = { + Stopped = { "󰁕 ", "DiagnosticWarn", "DapStoppedLine" }, + Breakpoint = " ", + BreakpointCondition = " ", + BreakpointRejected = { " ", "DiagnosticError" }, + LogPoint = ".>", + }, + } + + vim.api.nvim_set_hl(0, "DapStoppedLine", { default = true, link = "Visual" }) + + for name, sign in pairs(icons.dap) do + sign = type(sign) == "table" and sign or { sign } + vim.fn.sign_define( + "Dap" .. name, + { text = sign[1], texthl = sign[2] or "DiagnosticInfo", linehl = sign[3], numhl = sign[3] } + ) + end + end, + }, + + -- 问题检测器 + { + "folke/trouble.nvim", + cmd = { "TroubleToggle", "Trouble" }, + opts = { + use_diagnostic_signs = true, + action_keys = { + close = "q", + cancel = "", + refresh = "r", + jump = { "", "", "<2-leftmouse>" }, + open_split = { "" }, + open_vsplit = { "" }, + open_tab = { "" }, + jump_close = { "o" }, + toggle_mode = "m", + switch_severity = "s", + toggle_preview = "P", + hover = "K", + preview = "p", + close_folds = { "zM", "zm" }, + open_folds = { "zR", "zr" }, + toggle_fold = { "zA", "za" }, + previous = "k", + next = "j", + help = "?", + }, + }, + keys = { + { "xx", "TroubleToggle document_diagnostics", desc = "文档诊断" }, + { "xX", "TroubleToggle workspace_diagnostics", desc = "工作区诊断" }, + { "xL", "TroubleToggle loclist", desc = "位置列表" }, + { "xQ", "TroubleToggle quickfix", desc = "快速修复" }, + { + "[q", + function() + if require("trouble").is_open() then + require("trouble").previous({ skip_groups = true, jump = true }) + else + local ok, err = pcall(vim.cmd.cprev) + if not ok then + vim.notify(err, vim.log.levels.ERROR) + end + end + end, + desc = "上一个问题", + }, + { + "]q", + function() + if require("trouble").is_open() then + require("trouble").next({ skip_groups = true, jump = true }) + else + local ok, err = pcall(vim.cmd.cnext) + if not ok then + vim.notify(err, vim.log.levels.ERROR) + end + end + end, + desc = "下一个问题", + }, + }, + }, +} \ No newline at end of file diff --git a/nvim/lua/plugins/colorscheme.lua b/nvim/lua/plugins/colorscheme.lua new file mode 100644 index 0000000..d9953fc --- /dev/null +++ b/nvim/lua/plugins/colorscheme.lua @@ -0,0 +1,101 @@ +-- colorscheme.lua - 主题配置 + +return { + -- 主题:Tokyo Night + { + "folke/tokyonight.nvim", + lazy = false, -- 不延迟加载主题 + priority = 1000, -- 确保先加载主题 + config = function() + require("tokyonight").setup({ + style = "night", -- 可选值:"storm", "moon", "night", "day" + transparent = false, -- 启用背景透明 + terminal_colors = true, -- 设置终端颜色 + styles = { + comments = { italic = true }, + keywords = { italic = true }, + functions = {}, + variables = {}, + sidebars = "dark", + floats = "dark", + }, + sidebars = { "qf", "help", "terminal", "packer", "NvimTree", "Trouble" }, + dim_inactive = false, -- 非活动窗口变暗 + lualine_bold = true, -- 在状态栏中使用粗体 + + on_highlights = function(hl, c) + -- 自定义高亮组 + hl.CursorLineNr = { fg = c.orange, bold = true } + hl.LineNr = { fg = c.orange, bold = false } + hl.LineNrAbove = { fg = c.fg_gutter } + hl.LineNrBelow = { fg = c.fg_gutter } + + -- 浮动窗口 + hl.NormalFloat = { bg = c.bg_dark } + hl.FloatBorder = { bg = c.bg_dark, fg = c.blue } + end, + }) + + -- 加载主题 + vim.cmd.colorscheme("tokyonight") + end + }, + + -- 替代主题:Catppuccin + { + "catppuccin/nvim", + name = "catppuccin", + lazy = true, -- 懒加载此主题 + opts = { + flavour = "mocha", -- 风格: latte, frappe, macchiato, mocha + term_colors = true, + transparent_background = false, + styles = { + comments = { "italic" }, + conditionals = { "italic" }, + loops = {}, + functions = {}, + keywords = {}, + strings = {}, + variables = {}, + numbers = {}, + booleans = {}, + properties = {}, + types = {}, + operators = {}, + }, + integrations = { + cmp = true, + gitsigns = true, + nvimtree = true, + treesitter = true, + mason = true, + telescope = { + enabled = true, + style = "nvchad", + }, + native_lsp = { + enabled = true, + virtual_text = { + errors = { "italic" }, + hints = { "italic" }, + warnings = { "italic" }, + information = { "italic" }, + }, + underlines = { + errors = { "underline" }, + hints = { "underline" }, + warnings = { "underline" }, + information = { "underline" }, + }, + }, + }, + }, + }, + + -- 图标支持 + { + "nvim-tree/nvim-web-devicons", + lazy = true, + }, +} \ No newline at end of file diff --git a/nvim/lua/plugins/dap.lua b/nvim/lua/plugins/dap.lua new file mode 100644 index 0000000..16a30c6 --- /dev/null +++ b/nvim/lua/plugins/dap.lua @@ -0,0 +1,23 @@ +-- dap.lua - 调试支持 +return { + { + "mfussenegger/nvim-dap", + event = "VeryLazy", + }, + { + "leoluz/nvim-dap-go", + ft = "go", + dependencies = { "mfussenegger/nvim-dap" }, + config = function() + require("dap-go").setup() + end, + }, + { + "mfussenegger/nvim-dap-python", + ft = "python", + dependencies = { "mfussenegger/nvim-dap" }, + config = function() + require("dap-python").setup("python") + end, + }, +} diff --git a/nvim/lua/plugins/disabled.lua b/nvim/lua/plugins/disabled.lua deleted file mode 100644 index 7f52995..0000000 --- a/nvim/lua/plugins/disabled.lua +++ /dev/null @@ -1,3 +0,0 @@ -return { - -- disable the plugins -} diff --git a/nvim/lua/plugins/editor.lua b/nvim/lua/plugins/editor.lua new file mode 100644 index 0000000..3fe3519 --- /dev/null +++ b/nvim/lua/plugins/editor.lua @@ -0,0 +1,516 @@ +-- editor.lua - 编辑器增强插件配置 + +return { + -- 模糊搜索 + { + "nvim-telescope/telescope.nvim", + cmd = "Telescope", + version = false, + dependencies = { + "nvim-lua/plenary.nvim", + { + "nvim-telescope/telescope-fzf-native.nvim", + build = "make", + enabled = vim.fn.executable("make") == 1, + }, + }, + keys = { + -- 文件查找 + { "ff", "Telescope find_files", desc = "查找文件" }, + { "fr", "Telescope oldfiles", desc = "最近文件" }, + { "fb", "Telescope buffers", desc = "查找缓冲区" }, + + -- 内容搜索 + { "fg", "Telescope live_grep", desc = "全局搜索" }, + { "fw", "Telescope grep_string", desc = "搜索当前单词" }, + + -- 其他功能 + { "fh", "Telescope help_tags", desc = "帮助标签" }, + { "fm", "Telescope marks", desc = "跳转到书签" }, + { "fc", "Telescope commands", desc = "命令" }, + { "fk", "Telescope keymaps", desc = "快捷键" }, + + -- 工作区相关 + { "ws", "Telescope lsp_workspace_symbols", desc = "工作区符号" }, + + -- LSP 相关 + { "cs", "Telescope lsp_document_symbols", desc = "文档符号" }, + { "cr", "Telescope lsp_references", desc = "引用" }, + { "ci", "Telescope lsp_implementations", desc = "实现" }, + { "cd", "Telescope lsp_definitions", desc = "定义" }, + { "ct", "Telescope lsp_type_definitions", desc = "类型定义" }, + + -- 诊断 + { "xx", "Telescope diagnostics bufnr=0", desc = "当前文件诊断" }, + { "xw", "Telescope diagnostics", desc = "工作区诊断" }, + }, + opts = { + defaults = { + prompt_prefix = " ", + selection_caret = " ", + mappings = { + i = { + [""] = function(...) + return require("telescope.actions").move_selection_next(...) + end, + [""] = function(...) + return require("telescope.actions").move_selection_previous(...) + end, + [""] = function(...) + return require("telescope.actions").cycle_history_next(...) + end, + [""] = function(...) + return require("telescope.actions").cycle_history_prev(...) + end, + [""] = function(...) + return require("telescope.actions").close(...) + end, + [""] = function(...) + return require("telescope.actions").preview_scrolling_up(...) + end, + [""] = function(...) + return require("telescope.actions").preview_scrolling_down(...) + end, + }, + n = { + ["q"] = function(...) + return require("telescope.actions").close(...) + end, + }, + }, + }, + pickers = { + find_files = { + -- 默认包含隐藏文件 + find_command = { "rg", "--files", "--hidden", "--glob", "!.git" }, + }, + }, + }, + config = function(_, opts) + local telescope = require("telescope") + telescope.setup(opts) + + -- 加载扩展 + pcall(telescope.load_extension, "fzf") + end, + }, + + -- 高级语法高亮 + { + "nvim-treesitter/nvim-treesitter", + build = ":TSUpdate", + event = { "BufReadPost", "BufNewFile" }, + dependencies = { + "nvim-treesitter/nvim-treesitter-textobjects", + }, + opts = { + -- 自动安装的语法 + ensure_installed = { + "bash", + "c", + "cmake", + "comment", + "cpp", + "css", + "dockerfile", + "gitignore", + "go", + "gomod", + "gowork", + "html", + "http", + "java", + "javascript", + "json", + "kotlin", + "lua", + "make", + "markdown", + "markdown_inline", + "python", + "regex", + "ruby", + "rust", + "sql", + "toml", + "tsx", + "typescript", + "vim", + "vimdoc", + "xml", + "yaml", + }, + + -- 启用特性 + highlight = { enable = true }, + indent = { enable = true }, + incremental_selection = { + enable = true, + keymaps = { + init_selection = "", + node_incremental = "", + scope_incremental = false, + node_decremental = "", + }, + }, + + -- 文本对象 + textobjects = { + select = { + enable = true, + lookahead = true, + keymaps = { + ["af"] = "@function.outer", + ["if"] = "@function.inner", + ["ac"] = "@class.outer", + ["ic"] = "@class.inner", + ["aa"] = "@parameter.outer", + ["ia"] = "@parameter.inner", + }, + }, + move = { + enable = true, + set_jumps = true, + goto_next_start = { + ["]f"] = "@function.outer", + ["]c"] = "@class.outer", + }, + goto_next_end = { + ["]F"] = "@function.outer", + ["]C"] = "@class.outer", + }, + goto_previous_start = { + ["[f"] = "@function.outer", + ["[c"] = "@class.outer", + }, + goto_previous_end = { + ["[F"] = "@function.outer", + ["[C"] = "@class.outer", + }, + }, + }, + }, + config = function(_, opts) + require("nvim-treesitter.configs").setup(opts) + end, + }, + + -- 代码注释 + { + "numToStr/Comment.nvim", + opts = { + padding = true, -- 在注释分隔符后添加空格 + sticky = true, -- 注释时光标不移动 + toggler = { + line = "gcc", -- 行注释切换 + block = "gbc", -- 块注释切换 + }, + opleader = { + line = "gc", -- 行注释操作 + block = "gb", -- 块注释操作 + }, + extra = { + above = "gcO", -- 在当前行上方添加注释 + below = "gco", -- 在当前行下方添加注释 + eol = "gcA", -- 在当前行尾添加注释 + }, + mappings = { + basic = true, -- 基本映射 + extra = true, -- 额外映射 + }, + }, + keys = { + { "gcc", mode = "n", desc = "行注释" }, + { "gbc", mode = "n", desc = "块注释" }, + { "gc", mode = { "n", "o" }, desc = "行注释操作" }, + { "gb", mode = { "n", "o" }, desc = "块注释操作" }, + }, + }, + + -- 代码折叠 + { + "kevinhwang91/nvim-ufo", + dependencies = { + "kevinhwang91/promise-async", + { + "luukvbaal/statuscol.nvim", + config = function() + local builtin = require("statuscol.builtin") + require("statuscol").setup({ + relculright = true, + segments = { + { text = { builtin.foldfunc }, click = "v:lua.ScFa" }, + { text = { "%s" }, click = "v:lua.ScSa" }, + { text = { builtin.lnumfunc, " " }, click = "v:lua.ScLa" }, + }, + }) + end, + }, + }, + event = "BufReadPost", + opts = { + provider_selector = function() + return { "treesitter", "indent" } + end, + open_fold_hl_timeout = 150, + close_fold_kinds_for_ft = { + default = { "imports", "comment" }, + json = { "array" }, + yaml = { "sequence" }, + }, + preview = { + win_config = { + border = { "", "─", "", "", "", "─", "", "" }, + winhighlight = "Normal:Folded", + winblend = 0, + }, + mappings = { + scrollU = "", + scrollD = "", + jumpTop = "[", + jumpBot = "]", + }, + }, + }, + init = function() + vim.o.foldcolumn = "0" + vim.o.foldlevel = 99 + vim.o.foldlevelstart = 99 + vim.o.foldenable = true + end, + keys = { + { "zR", function() require("ufo").openAllFolds() end, desc = "打开所有折叠" }, + { "zM", function() require("ufo").closeAllFolds() end, desc = "关闭所有折叠" }, + { "zr", function() require("ufo").openFoldsExceptKinds() end, desc = "打开一级折叠" }, + { "zm", function() require("ufo").closeFoldsWith() end, desc = "关闭一级折叠" }, + { "zp", function() require("ufo").peekFoldedLinesUnderCursor() end, desc = "预览当前折叠" }, + }, + }, + + -- 终端集成 + { + "akinsho/toggleterm.nvim", + version = "*", + keys = { + { "tf", "ToggleTerm direction=float", desc = "浮动终端" }, + { "th", "ToggleTerm direction=horizontal", desc = "水平终端" }, + { "tv", "ToggleTerm direction=vertical size=40", desc = "垂直终端" }, + { "tt", "ToggleTerm", desc = "切换终端" }, + }, + opts = { + size = function(term) + if term.direction == "horizontal" then + return 15 + elseif term.direction == "vertical" then + return vim.o.columns * 0.4 + end + end, + open_mapping = [[]], + hide_numbers = true, + shade_filetypes = {}, + autochdir = true, + shade_terminals = true, + shading_factor = 2, + start_in_insert = true, + insert_mappings = true, + terminal_mappings = true, + persist_size = true, + persist_mode = true, + direction = "float", + close_on_exit = true, + shell = vim.o.shell, + float_opts = { + border = "curved", + winblend = 3, + highlights = { + border = "Normal", + background = "Normal", + }, + }, + }, + }, + + -- 代码片段 + { + "L3MON4D3/LuaSnip", + dependencies = { + "rafamadriz/friendly-snippets", + config = function() + require("luasnip.loaders.from_vscode").lazy_load() + end, + }, + opts = { + history = true, + delete_check_events = "TextChanged", + }, + keys = { + { + "", + function() + return require("luasnip").jumpable(1) and "luasnip-jump-next" or "" + end, + expr = true, silent = true, mode = "i", + }, + { "", function() require("luasnip").jump(1) end, mode = "s" }, + { "", function() require("luasnip").jump(-1) end, mode = { "i", "s" } }, + }, + }, + + -- 自动括号配对 + { + "windwp/nvim-autopairs", + event = "InsertEnter", + opts = { + check_ts = true, -- 检查 treesitter + ts_config = { + lua = { "string", "source" }, + javascript = { "string", "template_string" }, + java = false, + }, + fast_wrap = { + map = "", + chars = { "{", "[", "(", '"', "'" }, + pattern = string.gsub([[ [%'%"%)%>%]%)%}%,] ]], "%s+", ""), + offset = 0, + end_key = "$", + keys = "qwertyuiopzxcvbnmasdfghjkl", + check_comma = true, + highlight = "PmenuSel", + highlight_grey = "LineNr", + }, + }, + }, + + -- Git 集成 + { + "lewis6991/gitsigns.nvim", + event = { "BufReadPre", "BufNewFile" }, + opts = { + signs = { + add = { text = "▎" }, + change = { text = "▎" }, + delete = { text = "▁" }, + topdelete = { text = "▔" }, + changedelete = { text = "▎" }, + untracked = { text = "▎" }, + }, + on_attach = function(buffer) + local gs = package.loaded.gitsigns + + local function map(mode, l, r, desc) + vim.keymap.set(mode, l, r, { buffer = buffer, desc = desc }) + end + + -- 导航 + map("n", "]h", gs.next_hunk, "下一个变更") + map("n", "[h", gs.prev_hunk, "上一个变更") + + -- 操作 + map({ "n", "v" }, "gs", ":Gitsigns stage_hunk", "暂存变更") + map({ "n", "v" }, "gr", ":Gitsigns reset_hunk", "重置变更") + map("n", "gS", gs.stage_buffer, "暂存文件") + map("n", "gu", gs.undo_stage_hunk, "取消暂存变更") + map("n", "gR", gs.reset_buffer, "重置文件") + map("n", "gp", gs.preview_hunk, "预览变更") + map("n", "gb", function() gs.blame_line({ full = true }) end, "查看责任") + map("n", "gB", gs.toggle_current_line_blame, "开关行责任") + map("n", "gd", gs.diffthis, "文件差异") + map("n", "gD", function() gs.diffthis("~") end, "与HEAD差异") + map("n", "gt", gs.toggle_deleted, "开关显示删除") + + -- 文本对象 + map({ "o", "x" }, "ih", ":Gitsigns select_hunk", "选择变更") + end, + }, + }, + + -- 多光标编辑 + { + "mg979/vim-visual-multi", + event = "BufReadPost", + init = function() + vim.g.VM_leader = ";" + vim.g.VM_maps = { + ["Find Under"] = "", + ["Find Subword Under"] = "", + } + end, + }, + + -- 高亮相同单词 + { + "RRethy/vim-illuminate", + event = "BufReadPost", + opts = { + delay = 200, + large_file_cutoff = 2000, + large_file_overrides = { + providers = { "lsp" }, + }, + }, + config = function(_, opts) + require("illuminate").configure(opts) + + local function map(key, dir, buffer) + vim.keymap.set("n", key, function() + require("illuminate")["goto_" .. dir .. "_reference"](false) + end, { desc = dir:sub(1, 1):upper() .. dir:sub(2) .. " 引用", buffer = buffer }) + end + + -- 下一个/上一个引用导航 + map("]]", "next") + map("[[", "prev") + + -- 同时也是 LSP 附加时设置键绑定 + vim.api.nvim_create_autocmd("LspAttach", { + callback = function(args) + local buffer = args.buf + map("]]", "next", buffer) + map("[[", "prev", buffer) + end, + }) + end, + keys = { + { "]]", desc = "下一个引用" }, + { "[[", desc = "上一个引用" }, + }, + }, + + -- 缓冲区删除 + { + "echasnovski/mini.bufremove", + keys = { + { "bd", function() require("mini.bufremove").delete(0, false) end, desc = "删除缓冲区" }, + { "bD", function() require("mini.bufremove").delete(0, true) end, desc = "强制删除缓冲区" }, + }, + }, + + -- 括号高亮配对 + { + "HiPhish/rainbow-delimiters.nvim", + event = "BufReadPost", + config = function() + local rainbow_delimiters = require("rainbow-delimiters") + + vim.g.rainbow_delimiters = { + strategy = { + [""] = rainbow_delimiters.strategy["global"], + vim = rainbow_delimiters.strategy["local"], + }, + query = { + [""] = "rainbow-delimiters", + lua = "rainbow-blocks", + }, + highlight = { + "RainbowDelimiterRed", + "RainbowDelimiterYellow", + "RainbowDelimiterBlue", + "RainbowDelimiterOrange", + "RainbowDelimiterGreen", + "RainbowDelimiterViolet", + "RainbowDelimiterCyan", + }, + } + end, + }, +} \ No newline at end of file diff --git a/nvim/lua/plugins/example.lua b/nvim/lua/plugins/example.lua deleted file mode 100644 index 17f53d6..0000000 --- a/nvim/lua/plugins/example.lua +++ /dev/null @@ -1,197 +0,0 @@ --- since this is just an example spec, don't actually load anything here and return an empty spec --- stylua: ignore -if true then return {} end - --- every spec file under the "plugins" directory will be loaded automatically by lazy.nvim --- --- In your plugin files, you can: --- * add extra plugins --- * disable/enabled LazyVim plugins --- * override the configuration of LazyVim plugins -return { - -- add gruvbox - { "ellisonleao/gruvbox.nvim" }, - - -- Configure LazyVim to load gruvbox - { - "LazyVim/LazyVim", - opts = { - colorscheme = "gruvbox", - }, - }, - - -- change trouble config - { - "folke/trouble.nvim", - -- opts will be merged with the parent spec - opts = { use_diagnostic_signs = true }, - }, - - -- disable trouble - { "folke/trouble.nvim", enabled = false }, - - -- override nvim-cmp and add cmp-emoji - { - "hrsh7th/nvim-cmp", - dependencies = { "hrsh7th/cmp-emoji" }, - ---@param opts cmp.ConfigSchema - opts = function(_, opts) - table.insert(opts.sources, { name = "emoji" }) - end, - }, - - -- change some telescope options and a keymap to browse plugin files - { - "nvim-telescope/telescope.nvim", - keys = { - -- add a keymap to browse plugin files - -- stylua: ignore - { - "fp", - function() require("telescope.builtin").find_files({ cwd = require("lazy.core.config").options.root }) end, - desc = "Find Plugin File", - }, - }, - -- change some options - opts = { - defaults = { - layout_strategy = "horizontal", - layout_config = { prompt_position = "top" }, - sorting_strategy = "ascending", - winblend = 0, - }, - }, - }, - - -- add pyright to lspconfig - { - "neovim/nvim-lspconfig", - ---@class PluginLspOpts - opts = { - ---@type lspconfig.options - servers = { - -- pyright will be automatically installed with mason and loaded with lspconfig - pyright = {}, - }, - }, - }, - - -- add tsserver and setup with typescript.nvim instead of lspconfig - { - "neovim/nvim-lspconfig", - dependencies = { - "jose-elias-alvarez/typescript.nvim", - init = function() - require("lazyvim.util").lsp.on_attach(function(_, buffer) - -- stylua: ignore - vim.keymap.set( "n", "co", "TypescriptOrganizeImports", { buffer = buffer, desc = "Organize Imports" }) - vim.keymap.set("n", "cR", "TypescriptRenameFile", { desc = "Rename File", buffer = buffer }) - end) - end, - }, - ---@class PluginLspOpts - opts = { - ---@type lspconfig.options - servers = { - -- tsserver will be automatically installed with mason and loaded with lspconfig - tsserver = {}, - }, - -- you can do any additional lsp server setup here - -- return true if you don't want this server to be setup with lspconfig - ---@type table - setup = { - -- example to setup with typescript.nvim - tsserver = function(_, opts) - require("typescript").setup({ server = opts }) - return true - end, - -- Specify * to use this function as a fallback for any server - -- ["*"] = function(server, opts) end, - }, - }, - }, - - -- for typescript, LazyVim also includes extra specs to properly setup lspconfig, - -- treesitter, mason and typescript.nvim. So instead of the above, you can use: - { import = "lazyvim.plugins.extras.lang.typescript" }, - - -- add more treesitter parsers - { - "nvim-treesitter/nvim-treesitter", - opts = { - ensure_installed = { - "bash", - "html", - "javascript", - "json", - "lua", - "markdown", - "markdown_inline", - "python", - "query", - "regex", - "tsx", - "typescript", - "vim", - "yaml", - }, - }, - }, - - -- since `vim.tbl_deep_extend`, can only merge tables and not lists, the code above - -- would overwrite `ensure_installed` with the new value. - -- If you'd rather extend the default config, use the code below instead: - { - "nvim-treesitter/nvim-treesitter", - opts = function(_, opts) - -- add tsx and treesitter - vim.list_extend(opts.ensure_installed, { - "tsx", - "typescript", - }) - end, - }, - - -- the opts function can also be used to change the default opts: - { - "nvim-lualine/lualine.nvim", - event = "VeryLazy", - opts = function(_, opts) - table.insert(opts.sections.lualine_x, { - function() - return "😄" - end, - }) - end, - }, - - -- or you can return new options to override all the defaults - { - "nvim-lualine/lualine.nvim", - event = "VeryLazy", - opts = function() - return { - --[[add your custom lualine config here]] - } - end, - }, - - -- use mini.starter instead of alpha - { import = "lazyvim.plugins.extras.ui.mini-starter" }, - - -- add jsonls and schemastore packages, and setup treesitter for json, json5 and jsonc - { import = "lazyvim.plugins.extras.lang.json" }, - - -- add any tools you want to have installed below - { - "williamboman/mason.nvim", - opts = { - ensure_installed = { - "stylua", - "shellcheck", - "shfmt", - "flake8", - }, - }, - }, -} diff --git a/nvim/lua/plugins/flash.lua b/nvim/lua/plugins/flash.lua new file mode 100644 index 0000000..f52abc6 --- /dev/null +++ b/nvim/lua/plugins/flash.lua @@ -0,0 +1 @@ +return {"folke/flash.nvim", opts={}} \ No newline at end of file diff --git a/nvim/lua/plugins/go.lua b/nvim/lua/plugins/go.lua new file mode 100644 index 0000000..243002b --- /dev/null +++ b/nvim/lua/plugins/go.lua @@ -0,0 +1,285 @@ +-- go.lua - Go 开发专用配置 + +return { + -- Go 专用插件 + { + "ray-x/go.nvim", + dependencies = { + "ray-x/guihua.lua", + "neovim/nvim-lspconfig", + "nvim-treesitter/nvim-treesitter", + }, + ft = { "go", "gomod", "gowork", "gotmpl" }, + build = ':lua require("go.install").update_all_sync()', -- 同步更新所有解析器 + opts = { + -- 日志级别: 可以是 'trace', 'debug', 'info', 'warn', 'error', 'fatal' + lsp_cfg = { + settings = { + gopls = { + gofumpt = true, + codelenses = { + gc_details = true, + generate = true, + regenerate_cgo = true, + run_govulncheck = true, + test = true, + tidy = true, + upgrade_dependency = true, + vendor = true, + }, + hints = { + assignVariableTypes = true, + compositeLiteralFields = true, + constantValues = true, + functionTypeParameters = true, + parameterNames = true, + rangeVariableTypes = true, + }, + analyses = { + fieldalignment = true, + nilness = true, + unusedparams = true, + unusedwrite = true, + useany = true, + shadow = true, + }, + usePlaceholders = true, + completeUnimported = true, + staticcheck = true, + directoryFilters = { "-.git", "-.vscode", "-.idea", "-.vscode-test", "-node_modules" }, + semanticTokens = true, + }, + }, + }, + lsp_on_attach = function(client, bufnr) + -- 启用自动格式化 + vim.api.nvim_buf_set_option(bufnr, "formatexpr", "v:lua.vim.lsp.formatexpr()") + + -- 设置键映射 + local map = function(mode, lhs, rhs, desc) + if desc then + desc = desc + end + vim.keymap.set(mode, lhs, rhs, { silent = true, desc = desc, buffer = bufnr, noremap = true }) + end + + -- Go 特定映射 + map("n", "gfs", "GoFillStruct", "填充结构体") + map("n", "gfa", "GoAddTag", "添加标签") + map("n", "gfr", "GoRmTag", "移除标签") + map("n", "gcl", "GoClearTag", "清除标签") + map("n", "ge", "GoIfErr", "生成错误处理") + + -- 代码生成 + map("n", "ggt", "GoTest", "生成测试") + map("n", "ggf", "GoTestFunc", "生成函数测试") + map("n", "ggc", "GoCoverage", "显示测试覆盖率") + map("n", "ggC", "GoCoverageClear", "清除测试覆盖率") + map("n", "ggb", "GoBuild", "构建") + map("n", "ggr", "GoRun", "运行") + + -- 代码操作 + map("n", "gil", "GoImport", "导入包") + map("n", "gia", "GoImportAll", "导入所有") + map("n", "gif", "GoImpl", "实现接口") + map("n", "gid", "GoDoc", "查看文档") + + -- 代码移动 + map("n", "gca", "GoCodeAction", "代码操作") + map("n", "gfd", "GoFixDocumentation", "修复文档") + map("n", "gsf", "GoFillSwitch", "填充 switch") + map("n", "gsj", "GoAddErrCheck", "添加错误检查") + + -- 调试和测试 + map("n", "gtc", "GoCmt", "生成注释") + map("n", "gts", "GoAlt", "在实现和测试间切换") + end, + lsp_codelens = true, + -- 控制 gopls 设置 + lsp_keymaps = false, -- 我们手动设置键映射 + lsp_diag_hdlr = true, + lsp_diag_virtual_text = { space = 0, prefix = "" }, + lsp_diag_signs = true, + lsp_diag_update_in_insert = false, + lsp_document_formatting = true, + -- 代码格式化设置 + formatter = "gofumpt", -- gofmt, gofumpt, golines + formatter_extra_args = { "-s" }, + -- 测试设置 + test_runner = "go", -- richgo, go test, richgo, dlv, ginkgo + run_in_floaterm = true, + -- 调试设置 + dap_debug = true, + dap_debug_gui = true, + dap_debug_vt = true, + dap_port = 38697, + dap_timeout = 15, + -- 其他设置 + textobjects = true, + gofmt = true, -- 设置 gofmt 和 goimports + goimport = "gopls", -- goimport, gopls + diagnostic = { + hdlr = true, + underline = true, + virtual_text = { space = 0, prefix = "" }, + signs = true, + update_in_insert = false, + }, + tag_transform = "snakecase", + -- 路径设置 + verbose = false, + trouble = true, + lsp_inlay_hints = { + enable = true, + -- 使用 LSP 内联提示而不是 virtualtypes + only_current_line = false, + only_current_line_autocmd = "CursorHold", + show_parameter_hints = true, + show_variable_name = true, + parameter_hints_prefix = " ", + other_hints_prefix = " ", + highlight = "LspInlayHint", + }, + }, + config = function(_, opts) + require("go").setup(opts) + + -- 设置自动命令 + local gogroup = vim.api.nvim_create_augroup("GoGroup", { clear = true }) + + vim.api.nvim_create_autocmd("BufWritePre", { + pattern = "*.go", + group = gogroup, + callback = function() + require("go.format").goimport() + end, + }) + + vim.api.nvim_create_autocmd("FileType", { + pattern = "go", + group = gogroup, + callback = function() + -- 将 tab 宽度设置为 Go 的标准 + vim.bo.tabstop = 4 + vim.bo.shiftwidth = 4 + vim.bo.softtabstop = 4 + vim.bo.expandtab = false + end, + }) + end, + keys = { + -- 测试 + { "gts", "GoAlt", desc = "切换测试/实现文件" }, + { "gtt", "GoTest", desc = "运行包测试" }, + { "gtf", "GoTestFunc", desc = "测试函数" }, + { "gtc", "GoCoverage", desc = "测试覆盖率" }, + { "gtC", "GoCoverageClear", desc = "清除测试覆盖率" }, + + -- 格式化 + { "gff", "GoFormat", desc = "格式化" }, + { "gfi", "GoImport", desc = "导入" }, + { "gfI", "GoImportAll", desc = "导入所有" }, + + -- 模板 + { "gge", "GoIfErr", desc = "生成错误处理" }, + { "ggf", "GoFillStruct", desc = "填充结构体" }, + { "ggs", "GoFillSwitch", desc = "填充 switch" }, + + -- 标签 + { "gta", "GoAddTag", desc = "添加标签" }, + { "gtr", "GoRmTag", desc = "移除标签" }, + { "gtc", "GoClearTag", desc = "清除标签" }, + + -- 运行和构建 + { "gr", "GoRun", desc = "运行" }, + { "gb", "GoBuild", desc = "构建" }, + + -- 工具 + { "gi", "GoImpl", desc = "实现接口" }, + { "gd", "GoDoc", desc = "查看文档" }, + { "gl", "GoLint", desc = "运行 golint" }, + { "gv", "GoVet", desc = "运行 go vet" }, + }, + }, + + -- 格式化集成 + { + "stevearc/conform.nvim", + optional = true, + opts = { + formatters_by_ft = { + go = { "goimports", "gofumpt" }, + }, + }, + }, + + -- 调试支持 + { + "mfussenegger/nvim-dap", + optional = true, + dependencies = { + { + "leoluz/nvim-dap-go", + config = true, + }, + }, + keys = { + { "dgr", function() require("dap-go").debug_test() end, desc = "调试当前测试" }, + { "dgl", function() require("dap-go").debug_last_test() end, desc = "调试上一个测试" }, + }, + }, + + -- 单元测试 + { + "nvim-neotest/neotest", + optional = true, + dependencies = { + "nvim-neotest/neotest-go", + }, + opts = { + adapters = { + ["neotest-go"] = { + -- 使用 gotest 作为测试器 + args = { "-count=1", "-timeout=30s", "-v" }, + }, + }, + }, + }, + + -- 工具安装程序 + { + "williamboman/mason.nvim", + optional = true, + opts = function(_, opts) + -- 添加 Go 工具到确保安装列表 + if type(opts.ensure_installed) == "table" then + vim.list_extend(opts.ensure_installed, { + "gopls", + "gofumpt", + "goimports", + "golangci-lint", + "gomodifytags", + "gotests", + "impl", + "delve", + }) + end + end, + }, + + -- Treesitter 集成 + { + "nvim-treesitter/nvim-treesitter", + opts = function(_, opts) + -- 添加 Go 相关的解析器 + if type(opts.ensure_installed) == "table" then + vim.list_extend(opts.ensure_installed, { + "go", + "gomod", + "gowork", + "gosum", + }) + end + end, + }, +} \ No newline at end of file diff --git a/nvim/lua/plugins/lsp.lua b/nvim/lua/plugins/lsp.lua deleted file mode 100644 index f7b001a..0000000 --- a/nvim/lua/plugins/lsp.lua +++ /dev/null @@ -1,18 +0,0 @@ -return { - "williamboman/mason.nvim", - opts = { - ensure_installed = { - "bash-language-server", - "shfmt", - "shellcheck", - "emmet-ls", - "eslint_d", - "pyright", - "html-lsp", - "prettier", - "autopep8", - "stylua", - "gopls", - }, - }, -} diff --git a/nvim/lua/plugins/lspconfig.lua b/nvim/lua/plugins/lspconfig.lua new file mode 100644 index 0000000..bbd8f57 --- /dev/null +++ b/nvim/lua/plugins/lspconfig.lua @@ -0,0 +1,19 @@ +-- lspconfig.lua - LSP 配置 +return { + { + "neovim/nvim-lspconfig", + event = { "BufReadPre", "BufNewFile" }, + dependencies = { + "hrsh7th/cmp-nvim-lsp", + "williamboman/mason-lspconfig.nvim", + }, + config = function() + local lspconfig = require("lspconfig") + local capabilities = require("cmp_nvim_lsp").default_capabilities() + -- Go + lspconfig.gopls.setup({ capabilities = capabilities }) + -- Python + lspconfig.pyright.setup({ capabilities = capabilities }) + end, + }, +} diff --git a/nvim/lua/plugins/lua.lua b/nvim/lua/plugins/lua.lua new file mode 100644 index 0000000..e69de29 diff --git a/nvim/lua/plugins/mason.lua b/nvim/lua/plugins/mason.lua new file mode 100644 index 0000000..4ba74ce --- /dev/null +++ b/nvim/lua/plugins/mason.lua @@ -0,0 +1,23 @@ +-- mason.lua - LSP/DAP/格式化工具自动安装 +return { + { + "williamboman/mason.nvim", + build = ":MasonUpdate", + config = true, + }, + { + "williamboman/mason-lspconfig.nvim", + dependencies = { "williamboman/mason.nvim" }, + opts = { + ensure_installed = { "gopls", "pyright" }, + }, + }, + { + "jay-babu/mason-null-ls.nvim", + dependencies = { "williamboman/mason.nvim", "nvimtools/none-ls.nvim" }, + opts = { + ensure_installed = { "gofumpt", "golines", "black", "isort", "flake8" }, + automatic_installation = true, + }, + }, +} diff --git a/nvim/lua/plugins/noice.lua b/nvim/lua/plugins/noice.lua new file mode 100644 index 0000000..79c3a53 --- /dev/null +++ b/nvim/lua/plugins/noice.lua @@ -0,0 +1 @@ +return {"folke/noice.nvim", opts={}} \ No newline at end of file diff --git a/nvim/lua/plugins/null-ls.lua b/nvim/lua/plugins/null-ls.lua new file mode 100644 index 0000000..859aec0 --- /dev/null +++ b/nvim/lua/plugins/null-ls.lua @@ -0,0 +1,21 @@ +-- null-ls.lua - 格式化与诊断 +return { + { + "nvimtools/none-ls.nvim", + event = { "BufReadPre", "BufNewFile" }, + opts = function() + local null_ls = require("null-ls") + return { + sources = { + -- Go + null_ls.builtins.formatting.gofumpt, + null_ls.builtins.formatting.golines, + -- Python + null_ls.builtins.formatting.black, + null_ls.builtins.formatting.isort, + null_ls.builtins.diagnostics.ruff, + }, + } + end, + }, +} diff --git a/nvim/lua/plugins/python.lua b/nvim/lua/plugins/python.lua new file mode 100644 index 0000000..e6047b5 --- /dev/null +++ b/nvim/lua/plugins/python.lua @@ -0,0 +1,213 @@ +-- python.lua - Python 开发专用配置 + +return { + -- Python 专用插件 + { + "linux-cultist/venv-selector.nvim", + cmd = "VenvSelect", + keys = { + { "pv", "VenvSelect", desc = "选择 Python 虚拟环境" }, + { "pc", "VenvSelectCached", desc = "选择缓存的虚拟环境" }, + }, + opts = { + name = { + "venv", + ".venv", + "env", + ".env", + "virtualenv", + }, + auto_refresh = true, + search_from = "root", -- 从项目根目录搜索 + }, + config = function(_, opts) + require("venv-selector").setup(opts) + + -- 自动激活虚拟环境 + vim.api.nvim_create_autocmd("BufEnter", { + pattern = { "*.py" }, + callback = function() + -- 使用缓存的 venv + require("venv-selector").retrieve_from_cache() + end, + }) + end, + }, + + -- Python 单元测试插件 + { + "nvim-neotest/neotest", + optional = true, + dependencies = { + "nvim-neotest/neotest-python", + }, + opts = { + adapters = { + ["neotest-python"] = { + -- 使用项目根目录中的 pytest.ini + runner = "pytest", + -- 可以使用 pytest 或 unittest + -- runner = function() + -- if vim.fn.filereadable("pytest.ini") == 1 then + -- return "pytest" + -- else + -- return "unittest" + -- end + -- end, + + -- 额外的 pytest 参数 + args = { + "--color=yes", + "-v", + }, + + -- Python 测试发现模式 + python = function() + -- 如果激活了虚拟环境,使用它 + if vim.env.VIRTUAL_ENV then + return vim.env.VIRTUAL_ENV .. "/bin/python" + end + + -- 否则使用系统的 Python + return "python" + end, + }, + }, + }, + keys = { + { "pt", "lua require('neotest').run.run()", desc = "运行最近的测试" }, + { "pT", "lua require('neotest').run.run(vim.fn.expand('%'))", desc = "运行文件中的测试" }, + { "pd", "lua require('neotest').run.run({strategy = 'dap'})", desc = "调试最近的测试" }, + { "ps", "lua require('neotest').run.stop()", desc = "停止测试" }, + { "pa", "lua require('neotest').run.attach()", desc = "附加到测试" }, + { "po", "lua require('neotest').output.open()", desc = "查看测试输出" }, + { "pO", "lua require('neotest').output_panel.toggle()", desc = "切换输出面板" }, + { "pS", "lua require('neotest').summary.toggle()", desc = "切换摘要窗口" }, + }, + }, + + -- Python 导入排序和格式化 + { + "stevearc/conform.nvim", + optional = true, + opts = { + formatters_by_ft = { + python = { "isort", "black" }, + }, + formatters = { + black = { + args = { "--line-length", "88", "--fast", "-" }, + }, + isort = { + args = { "--stdout", "--profile", "black", "--line-length", "88", "-" }, + }, + }, + }, + }, + + -- Python 调试 + { + "mfussenegger/nvim-dap", + optional = true, + dependencies = { + "mfussenegger/nvim-dap-python", + }, + opts = function() + local path = require("mason-registry").get_package("debugpy"):get_install_path() + require("dap-python").setup(path .. "/venv/bin/python") + + -- 设置 pytest 调试 + require("dap-python").test_runner = "pytest" + + -- 添加自定义配置 + table.insert(require("dap").configurations.python, { + type = "python", + request = "launch", + name = "启动带参数的文件", + program = "${file}", + args = function() + local args_string = vim.fn.input("命令行参数: ") + return vim.split(args_string, " ") + end, + console = "integratedTerminal", + }) + + -- 添加 FastAPI 配置 + table.insert(require("dap").configurations.python, { + type = "python", + request = "launch", + name = "FastAPI", + module = "uvicorn", + args = function() + local args = vim.fn.input("uvicorn 参数 (例如 main:app --reload): ") + return vim.split(args, " ") + end, + console = "integratedTerminal", + }) + end, + keys = { + -- Python 特定调试键 + { "dpr", function() require("dap-python").test_method() end, desc = "调试当前方法" }, + { "dpc", function() require("dap-python").test_class() end, desc = "调试当前类" }, + { "dpf", function() require("dap-python").test_method() end, desc = "调试当前函数" }, + }, + }, + + -- Python 代码格式化和排序 + { + "williamboman/mason.nvim", + optional = true, + opts = function(_, opts) + -- 将额外的 Python 工具添加到确保安装列表中 + if type(opts.ensure_installed) == "table" then + vim.list_extend(opts.ensure_installed, { + "black", + "isort", + "mypy", + "ruff", + "ruff-lsp", + "pyright", + "debugpy", + }) + end + end, + }, + + -- 代码折叠 + { + "kevinhwang91/nvim-ufo", + optional = true, + opts = { + close_fold_kinds_for_ft = { + python = { "imports", "comment" }, + }, + }, + }, + + -- REPL 集成 + { + "michaelb/sniprun", + build = "sh ./install.sh", + cmd = { "SnipRun", "SnipInfo", "SnipReset", "SnipClose" }, + keys = { + { "pe", "SnipRun", desc = "执行选中代码", mode = { "n", "v" } }, + { "pE", "SnipInfo", desc = "Sniprun 信息" }, + }, + opts = { + display = { "NvimNotify" }, + interpreter_options = { + Python3_fifo = { + venv = function() + return vim.env.VIRTUAL_ENV + end, + cwd = function() + return vim.fn.getcwd() + end, + }, + }, + }, + config = function(_, opts) + require("sniprun").setup(opts) + end, + }, +} \ No newline at end of file diff --git a/nvim/lua/plugins/snacks.lua b/nvim/lua/plugins/snacks.lua new file mode 100644 index 0000000..fcfd409 --- /dev/null +++ b/nvim/lua/plugins/snacks.lua @@ -0,0 +1 @@ +return {"folke/snacks.nvim", opts={}} \ No newline at end of file diff --git a/nvim/lua/plugins/todo-comment.lua b/nvim/lua/plugins/todo-comment.lua new file mode 100644 index 0000000..b65b82e --- /dev/null +++ b/nvim/lua/plugins/todo-comment.lua @@ -0,0 +1 @@ +return { "folke/todo-comments.nvim", opts = {} } \ No newline at end of file diff --git a/nvim/lua/plugins/treesitter.lua b/nvim/lua/plugins/treesitter.lua new file mode 100644 index 0000000..d11ea6e --- /dev/null +++ b/nvim/lua/plugins/treesitter.lua @@ -0,0 +1,13 @@ +-- treesitter.lua - 语法高亮与代码结构 +return { + { + "nvim-treesitter/nvim-treesitter", + build = ":TSUpdate", + event = { "BufReadPost", "BufNewFile" }, + opts = { + ensure_installed = { "go", "python", "lua", "json", "yaml", "markdown" }, + highlight = { enable = true }, + indent = { enable = true }, + }, + }, +} diff --git a/nvim/lua/plugins/trouble.lua b/nvim/lua/plugins/trouble.lua new file mode 100644 index 0000000..c22edba --- /dev/null +++ b/nvim/lua/plugins/trouble.lua @@ -0,0 +1 @@ +return {"folke/trouble.nvim", opts={}} \ No newline at end of file diff --git a/nvim/lua/plugins/ts-comments.lua b/nvim/lua/plugins/ts-comments.lua new file mode 100644 index 0000000..a251d44 --- /dev/null +++ b/nvim/lua/plugins/ts-comments.lua @@ -0,0 +1 @@ +return {"folke/ts-comments.nvim", opts={}} \ No newline at end of file diff --git a/nvim/lua/plugins/ui.lua b/nvim/lua/plugins/ui.lua new file mode 100644 index 0000000..1b1cf6d --- /dev/null +++ b/nvim/lua/plugins/ui.lua @@ -0,0 +1,330 @@ +-- ui.lua - UI 增强插件配置 + +return { + -- 状态栏 + { + "nvim-lualine/lualine.nvim", + event = "VeryLazy", + dependencies = { "nvim-tree/nvim-web-devicons" }, + opts = { + options = { + theme = "auto", -- 自动匹配当前主题 + globalstatus = true, -- 全局状态栏 + component_separators = { left = "", right = "" }, + section_separators = { left = "", right = "" }, + disabled_filetypes = { + statusline = { "dashboard", "alpha" }, + winbar = { "dashboard", "alpha" }, + }, + }, + sections = { + lualine_a = { { "mode", icon = "" } }, + lualine_b = { + { "branch", icon = "" }, + { + "diff", + symbols = { added = " ", modified = " ", removed = " " }, + colored = true + } + }, + lualine_c = { + { + "diagnostics", + sources = { "nvim_diagnostic" }, + symbols = { + error = " ", + warn = " ", + info = " ", + hint = " ", + }, + }, + { "filetype", icon_only = true, separator = "", padding = { left = 1, right = 0 } }, + { "filename", path = 1, symbols = { modified = " ", readonly = " ", unnamed = " " } }, + }, + lualine_x = { + -- Git 文件状态 + { + function() + local status = "" + local ft = vim.bo.filetype + + -- 检查 LSP 是否连接 + local clients = vim.lsp.get_active_clients({ bufnr = 0 }) + if #clients > 0 then + status = status .. " LSP" + end + + return status + end, + }, + { "encoding" }, + { "fileformat" }, + { "filetype" }, + }, + lualine_y = { + { "progress", separator = " ", padding = { left = 1, right = 1 } }, + { "location", padding = { left = 1, right = 1 } }, + }, + lualine_z = { + function() + return " " .. os.date("%R") + end, + }, + }, + tabline = {}, + extensions = { "neo-tree", "lazy" }, + }, + }, + + -- 缩进线 + { + "lukas-reineke/indent-blankline.nvim", + main = "ibl", + event = "BufReadPost", + opts = { + indent = { + char = "│", -- 缩进字符 + tab_char = "│", -- Tab 缩进字符 + }, + scope = { enabled = false }, -- 禁用范围高亮 + exclude = { + filetypes = { + "help", + "alpha", + "dashboard", + "neo-tree", + "Trouble", + "lazy", + "mason", + "notify", + "toggleterm", + "lazyterm", + }, + }, + }, + }, + + -- 文件树 + { + "nvim-neo-tree/neo-tree.nvim", + branch = "v3.x", + cmd = "Neotree", + dependencies = { + "nvim-lua/plenary.nvim", + "nvim-tree/nvim-web-devicons", + "MunifTanjim/nui.nvim", + }, + keys = { + { "e", "Neotree toggle", desc = "切换文件浏览器" }, + { "o", "Neotree focus", desc = "聚焦文件浏览器" }, + }, + opts = { + sources = { "filesystem", "buffers", "git_status", "document_symbols" }, + open_files_do_not_replace_types = { "terminal", "Trouble", "qf", "edgy" }, + filesystem = { + bind_to_cwd = false, + follow_current_file = { enabled = true }, + use_libuv_file_watcher = true, + filtered_items = { + visible = true, -- 显示被过滤的项目 + hide_dotfiles = false, -- 不隐藏点文件 + hide_gitignored = false, -- 不隐藏被 gitignore 的文件 + }, + }, + window = { + position = "left", + width = 30, + mappings = { + [""] = "none", + ["o"] = "open", + ["h"] = "close_node", + ["l"] = "open", + }, + }, + default_component_configs = { + indent = { + with_expanders = true, -- 启用展开图标 + expander_collapsed = "", + expander_expanded = "", + expander_highlight = "NeoTreeExpander", + }, + git_status = { + symbols = { + -- 状态图标 + added = "✚", -- 或 "✚" + modified = "", -- 或 "" + deleted = "✖", -- 或 "✖" + renamed = "", -- 或 "" + untracked = "", + ignored = "", + unstaged = "", + staged = "", + conflict = "", + }, + }, + }, + commands = { + -- 添加自定义命令,如创建文件时创建路径 + parent_or_close = function(state) + local node = state.tree:get_node() + if (node.type == "directory" or node:has_children()) and node:is_expanded() then + state.commands.toggle_node(state) + else + require("neo-tree.ui.renderer").focus_node(state, node:get_parent_id()) + end + end, + child_or_open = function(state) + local node = state.tree:get_node() + if node.type == "directory" or node:has_children() then + if not node:is_expanded() then + state.commands.toggle_node(state) + else + require("neo-tree.ui.renderer").focus_node(state, node:get_child_ids()[1]) + end + else + state.commands.open(state) + end + end, + }, + }, + }, + + -- 顶部标签页 + { + "akinsho/bufferline.nvim", + event = "VeryLazy", + keys = { + { "bp", "BufferLineTogglePin", desc = "标记/取消标记缓冲区" }, + { "bP", "BufferLineGroupClose ungrouped", desc = "关闭未标记的缓冲区" }, + { "bo", "BufferLineCloseOthers", desc = "关闭其他缓冲区" }, + { "br", "BufferLineCloseRight", desc = "关闭右侧缓冲区" }, + { "bl", "BufferLineCloseLeft", desc = "关闭左侧缓冲区" }, + { "", "BufferLineCyclePrev", desc = "上一个缓冲区" }, + { "", "BufferLineCycleNext", desc = "下一个缓冲区" }, + }, + opts = { + options = { + close_command = function(n) require("mini.bufremove").delete(n, false) end, + right_mouse_command = function(n) require("mini.bufremove").delete(n, false) end, + diagnostics = "nvim_lsp", -- 显示诊断 + always_show_bufferline = false, + diagnostics_indicator = function(_, _, diag) + local icons = { + Error = " ", + Warn = " ", + Hint = " ", + Info = " ", + } + local ret = (diag.error and icons.Error .. diag.error .. " " or "") + .. (diag.warning and icons.Warn .. diag.warning or "") + return vim.trim(ret) + end, + offsets = { + { + filetype = "neo-tree", + text = "文件浏览器", + highlight = "Directory", + text_align = "left", + }, + }, + }, + }, + }, + + -- 通知系统 + { + "rcarriga/nvim-notify", + keys = { + { + "un", + function() + require("notify").dismiss({ silent = true, pending = true }) + end, + desc = "清除所有通知", + }, + }, + opts = { + timeout = 3000, + max_height = function() + return math.floor(vim.o.lines * 0.75) + end, + max_width = function() + return math.floor(vim.o.columns * 0.75) + end, + on_open = function(win) + vim.api.nvim_win_set_config(win, { zindex = 100 }) + end, + }, + init = function() + -- 当 "notify" 可用时,将其替换为 vim.notify + vim.notify = function(...) + local loaded, notify = pcall(require, "notify") + if loaded then + vim.notify = notify + return notify(...) + else + return vim.api.nvim_notify(...) + end + end + end, + }, + -- 快捷键提示 + { + "folke/which-key.nvim", + event = "VeryLazy", + opts = { + plugins = { + marks = true, -- 显示标记 + registers = true, -- 显示寄存器 + spelling = { + enabled = true, -- 启用拼写建议 + suggestions = 20, + }, + presets = { + operators = true, -- 添加操作符帮助 + motions = true, -- 添加动作帮助 + text_objects = true, -- 添加文本对象帮助 + windows = true, -- 添加窗口帮助 (meta-w) + nav = true, -- 添加导航帮助 + z = true, -- 添加折叠帮助 + g = true, -- 添加 g 命令帮助 + }, + }, + icons = { + breadcrumb = "»", -- 面包屑分隔符 + separator = "➜", -- 键映射前缀和命令之间的分隔符 + group = "+", -- 组图标 + }, + window = { + border = "rounded", -- 边框样式 + position = "bottom", -- 位置 + margin = { 1, 0, 1, 0 }, -- 边距 + padding = { 1, 1, 1, 1 }, -- 内边距 + }, + layout = { + height = { min = 3, max = 25 }, -- 最小和最大高度 + width = { min = 20, max = 50 }, -- 最小和最大宽度 + spacing = 3, -- 间距 + align = "center", -- 对齐方式 + }, + ignore_missing = false, -- 不忽略缺少的键映射 + hidden = { "", "", "", "", "^:", "^ ", "^call ", "^lua " }, -- 隐藏的命令前缀 + show_help = true, -- 显示帮助信息 + triggers = "auto", -- 触发自动显示 + triggers_nowait = { -- 不等待这些前缀的键映射 + -- 字符表示操作符等待模式 + "`", + "'", + "g`", + "g'", + '"', + "", + "z=", + }, + }, + config = function(_, opts) + local wk = require("which-key") + wk.setup(opts) + end, + }, +} \ No newline at end of file diff --git a/nvim/lua/plugins/utils.lua b/nvim/lua/plugins/utils.lua new file mode 100644 index 0000000..5a5abea --- /dev/null +++ b/nvim/lua/plugins/utils.lua @@ -0,0 +1,337 @@ +-- utils.lua - 实用工具插件配置 + +return { + -- 启动界面 + { + "goolord/alpha-nvim", + event = "VimEnter", + opts = function() + local dashboard = require("alpha.themes.dashboard") + local logo = [[ + ███╗ ██╗███████╗ ██████╗ ██╗ ██╗██╗███╗ ███╗ + ████╗ ██║██╔════╝██╔═══██╗██║ ██║██║████╗ ████║ + ██╔██╗ ██║█████╗ ██║ ██║██║ ██║██║██╔████╔██║ + ██║╚██╗██║██╔══╝ ██║ ██║╚██╗ ██╔╝██║██║╚██╔╝██║ + ██║ ╚████║███████╗╚██████╔╝ ╚████╔╝ ██║██║ ╚═╝ ██║ + ╚═╝ ╚═══╝╚══════╝ ╚═════╝ ╚═══╝ ╚═╝╚═╝ ╚═╝ + ]] + + dashboard.section.header.val = vim.split(logo, "\n") + dashboard.section.buttons.val = { + dashboard.button("f", " 查找文件", ":Telescope find_files "), + dashboard.button("e", " 新文件", ":ene startinsert "), + dashboard.button("r", " 最近文件", ":Telescope oldfiles "), + dashboard.button("g", " 查找文本", ":Telescope live_grep "), + dashboard.button("c", " 配置", ":e $MYVIMRC "), + dashboard.button("l", " 懒加载插件", ":Lazy"), + dashboard.button("q", " 退出", ":qa"), + } + + dashboard.section.footer.val = "Neovim 配置 - 专注于 Python 和 Go 开发" + + dashboard.section.header.opts.hl = "Type" + dashboard.section.buttons.opts.hl = "Keyword" + dashboard.section.footer.opts.hl = "Comment" + + dashboard.opts.opts.noautocmd = true + return dashboard + end, + config = function(_, dashboard) + require("alpha").setup(dashboard.opts) + + vim.api.nvim_create_autocmd("User", { + pattern = "LazyVimStarted", + callback = function() + local stats = require("lazy").stats() + local ms = (math.floor(stats.startuptime * 100 + 0.5) / 100) + local version = " v" .. vim.version().major .. "." .. vim.version().minor .. "." .. vim.version().patch + local plugins = " " .. stats.count .. " 个插件加载完成,用时 " .. ms .. "ms" + local footer = version .. "\n" .. plugins + + pcall(function() + local alpha = require("alpha") + local dashboard = alpha.themes.dashboard + dashboard.section.footer.val = footer + alpha.redraw() + end) + end, + }) + end, + }, + + -- 查找器增强 + { + "folke/flash.nvim", + event = "VeryLazy", + opts = { + search = { + multi_window = false, -- 只在当前窗口搜索 + wrap = true, -- 循环搜索 + }, + modes = { + char = { + enabled = true, + keys = { "f", "F", "t", "T", ";", "," }, + }, + }, + }, + keys = { + { + "s", + mode = { "n", "x", "o" }, + function() + require("flash").jump() + end, + desc = "闪烁跳转", + }, + { + "S", + mode = { "n", "x", "o" }, + function() + require("flash").treesitter() + end, + desc = "闪烁 Treesitter", + }, + { + "r", + mode = "o", + function() + require("flash").remote() + end, + desc = "远程闪烁", + }, + { + "R", + mode = { "o", "x" }, + function() + require("flash").treesitter_search() + end, + desc = "Treesitter 搜索", + }, + }, + }, + + -- 项目管理 + { + "ahmedkhalf/project.nvim", + config = function() + require("project_nvim").setup({ + patterns = { ".git", "_darcs", ".hg", ".bzr", ".svn", "Makefile", "package.json", "pyproject.toml", "go.mod" }, + detection_methods = { "pattern", "lsp" }, + show_hidden = true, + silent_chdir = true, + scope_chdir = "global", + }) + + require("telescope").load_extension("projects") + end, + keys = { + { "fp", "Telescope projects", desc = "项目" }, + }, + }, + + -- 文件浏览器增强 + { + "stevearc/oil.nvim", + opts = { + default_file_explorer = true, + columns = { + "icon", + "permissions", + "size", + "mtime", + }, + buf_options = { + buflisted = false, + bufhidden = "hide", + }, + win_options = { + wrap = false, + signcolumn = "no", + cursorcolumn = false, + foldcolumn = "0", + spell = false, + list = false, + conceallevel = 3, + concealcursor = "n", + }, + delete_to_trash = true, + skip_confirm_for_simple_edits = false, + prompt_save_on_select_new_entry = true, + cleanup_delay_ms = 2000, + keymaps = { + ["g?"] = "actions.show_help", + [""] = "actions.select", + [""] = "actions.select_vsplit", + [""] = "actions.select_split", + [""] = "actions.select_tab", + [""] = "actions.preview", + [""] = "actions.close", + [""] = "actions.refresh", + ["-"] = "actions.parent", + ["_"] = "actions.open_cwd", + ["`"] = "actions.cd", + ["~"] = "actions.tcd", + ["gs"] = "actions.change_sort", + ["gx"] = "actions.open_external", + ["g."] = "actions.toggle_hidden", + ["g\\"] = "actions.toggle_trash", + }, + use_default_keymaps = true, + view_options = { + show_hidden = true, + is_hidden_file = function(name, bufnr) + return vim.startswith(name, ".") + end, + is_always_hidden = function(name, bufnr) + return false + end, + }, + float = { + padding = 2, + max_width = 0, + max_height = 0, + border = "rounded", + win_options = { + winblend = 0, + }, + }, + preview = { + max_width = 0.9, + min_width = { 40, 0.4 }, + width = nil, + max_height = 0.9, + min_height = { 5, 0.1 }, + height = nil, + border = "rounded", + win_options = { + winblend = 0, + }, + }, + progress = { + max_width = 0.9, + min_width = { 40, 0.4 }, + width = nil, + max_height = 0.9, + min_height = { 5, 0.1 }, + height = nil, + border = "rounded", + minimized_border = "none", + win_options = { + winblend = 0, + }, + }, + }, + keys = { + { "-", "Oil", desc = "打开父目录" }, + { "fo", "Oil", desc = "打开文件浏览器" }, + }, + }, + + -- 自动调整窗口大小 + { + "anuvyklack/windows.nvim", + event = "WinNew", + dependencies = { + { "anuvyklack/middleclass" }, + { "anuvyklack/animation.nvim", enabled = true }, + }, + keys = { + { "wm", "WindowsMaximize", desc = "最大化窗口" }, + { "w=", "WindowsEqualize", desc = "均分窗口" }, + }, + config = function() + vim.o.winwidth = 10 + vim.o.winminwidth = 10 + vim.o.equalalways = false + require("windows").setup({ + animation = { enable = true, duration = 150 }, + autowidth = { enable = true }, + }) + end, + }, + + -- 会话管理 + { + "folke/persistence.nvim", + event = "BufReadPre", + opts = { + dir = vim.fn.expand(vim.fn.stdpath("state") .. "/sessions/"), + options = { "buffers", "curdir", "tabpages", "winsize", "help", "globals", "skiprtp" }, + pre_save = nil, + }, + keys = { + { "qs", function() require("persistence").load() end, desc = "恢复上次会话" }, + { "ql", function() require("persistence").load({ last = true }) end, desc = "恢复最后会话" }, + { "qd", function() require("persistence").stop() end, desc = "不保存当前会话" }, + }, + }, + + -- 键位映射管理 + { + "mrjones2014/legendary.nvim", + keys = { + { "k", "Legendary", desc = "键位映射查找器" }, + }, + opts = { + include_builtin = true, + include_legendary_cmds = true, + extensions = { + which_key = { auto_register = true }, + smart_splits = { auto_register = true }, + }, + }, + }, + + -- AI 补全集成 + { + "zbirenbaum/copilot.lua", + cmd = "Copilot", + event = "InsertEnter", + config = function() + require("copilot").setup({ + panel = { + enabled = true, + auto_refresh = true, + keymap = { + jump_prev = "[[", + jump_next = "]]", + accept = "", + refresh = "gr", + open = "" + }, + layout = { + position = "bottom", -- | top | left | right + ratio = 0.4 + }, + }, + suggestion = { + enabled = true, + auto_trigger = true, + debounce = 75, + keymap = { + accept = "", + accept_word = "", + accept_line = "", + next = "", + prev = "", + dismiss = "", + }, + }, + filetypes = { + yaml = false, + markdown = false, + help = false, + gitcommit = false, + gitrebase = false, + hgcommit = false, + svn = false, + cvs = false, + ["."] = false, + }, + copilot_node_command = 'node', -- Node.js 版本 + server_opts_overrides = {}, + }) + end, + }, +} \ No newline at end of file diff --git a/nvim/lua/plugins/wakatime.lua b/nvim/lua/plugins/wakatime.lua deleted file mode 100644 index fd064e4..0000000 --- a/nvim/lua/plugins/wakatime.lua +++ /dev/null @@ -1,4 +0,0 @@ -return { - "wakatime/vim-wakatime", - event = "InsertEnter", -} diff --git a/nvim/lua/plugins/which-key.lua b/nvim/lua/plugins/which-key.lua new file mode 100644 index 0000000..40ce64f --- /dev/null +++ b/nvim/lua/plugins/which-key.lua @@ -0,0 +1 @@ +return {"folke/which-key.nvim", opts={}} \ No newline at end of file