diff --git a/lua/keymaps.lua b/lua/keymaps.lua index 149e93d..836d712 100644 --- a/lua/keymaps.lua +++ b/lua/keymaps.lua @@ -11,8 +11,12 @@ map("v", ">", ">gv", { desc = "Indent and keep selection" }) map("n", "J", "mzJ`z", { desc = "Join lines without moving cursor" }) -map("n", "ss", [[:%s/\<\>//gI]], - { desc = "Replace word cursor is on globally" }) +map( + "n", + "ss", + [[:%s/\<\>//gI]], + { desc = "Replace word cursor is on globally" } +) map("v", "ss", ":s/\\%V", { desc = "Search and replace in visual selection" }) -- general @@ -23,10 +27,13 @@ map("v", "<", "u", function() - vim.cmd.packadd("nvim.undotree") - require("undotree").open() + vim.cmd.packadd("nvim.undotree") + require("undotree").open() end, { desc = "Toggle Builtin Undotree" }) +map("n", "", "w", { desc = "Save file" }) +map("n", "", "%y+", { desc = "Copy whole file" }) + map("t", "", "", { desc = "Escape termainl" }) map("n", "tt", ":term", { desc = "Open new terminal" }) @@ -38,46 +45,46 @@ map("n", "[", ":tabprevious", { desc = "Previous tab" }) -- yank path map("n", "yp", function() - local path = vim.fn.expand("%") - vim.fn.setreg("+", path) - vim.notify("Copied relative path: " .. path, vim.log.levels.INFO) + local path = vim.fn.expand("%") + vim.fn.setreg("+", path) + vim.notify("Copied relative path: " .. path, vim.log.levels.INFO) end, { desc = "Yank relative file path" }) map("n", "yP", function() - local path = vim.fn.expand("%:p") - vim.fn.setreg("+", path) - vim.notify("Copied absolute path: " .. path, vim.log.levels.INFO) + local path = vim.fn.expand("%:p") + vim.fn.setreg("+", path) + vim.notify("Copied absolute path: " .. path, vim.log.levels.INFO) end, { desc = "Yank absolute file path" }) -- buffer map("n", "x", function() - local buf = vim.api.nvim_get_current_buf() - if vim.bo[buf].modified then - vim.ui.select({ "Yes", "No" }, { - prompt = "Buffer has unsaved changes. Close without saving?", - format_item = function(item) - return item - end, - }, function(choice) - if choice == "Yes" then - vim.api.nvim_buf_delete(buf, { force = true }) - end - end) - else - vim.cmd.bdelete() - end + local buf = vim.api.nvim_get_current_buf() + if vim.bo[buf].modified then + vim.ui.select({ "Yes", "No" }, { + prompt = "Buffer has unsaved changes. Close without saving?", + format_item = function(item) + return item + end, + }, function(choice) + if choice == "Yes" then + vim.api.nvim_buf_delete(buf, { force = true }) + end + end) + else + vim.cmd.bdelete() + end end, { desc = "Close current buffer" }) map("n", "bn", "enew", { desc = "Buffer new" }) map("n", "bo", function() - local current = vim.api.nvim_get_current_buf() - local skipped_ft = { "NvimTree", "oil", "aerial" } - for _, buf in ipairs(vim.api.nvim_list_bufs()) do - if buf ~= current and vim.api.nvim_buf_is_loaded(buf) then - local ft = vim.bo[buf].filetype - if not vim.tbl_contains(skipped_ft, ft) then - vim.api.nvim_buf_delete(buf, { force = true }) - end - end - end + local current = vim.api.nvim_get_current_buf() + local skipped_ft = { "NvimTree", "oil", "aerial" } + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + if buf ~= current and vim.api.nvim_buf_is_loaded(buf) then + local ft = vim.bo[buf].filetype + if not vim.tbl_contains(skipped_ft, ft) then + vim.api.nvim_buf_delete(buf, { force = true }) + end + end + end end, { desc = "Close other buffers" }) diff --git a/lua/lsp.lua b/lua/lsp.lua index d2a2f5d..71ed5f7 100644 --- a/lua/lsp.lua +++ b/lua/lsp.lua @@ -2,93 +2,95 @@ local lazy = require("lazy") -- conform.nvim - BufWritePre 懒加载 local function setup_conform() - local function biome_or_prettier() - 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 } - end - return { "prettier" } - end + local function biome_or_prettier() + 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 } + end + return { "prettier" } + end - require("conform").setup({ - formatters_by_ft = { - lua = { "stylua" }, - go = { "gofumpt", "goimports" }, - javascript = biome_or_prettier, - typescript = biome_or_prettier, - javascriptreact = biome_or_prettier, - typescriptreact = biome_or_prettier, - json = biome_or_prettier, - css = { "prettier" }, - html = { "prettier" }, - markdown = { "prettier" }, - toml = { "taplo" }, - }, - format_on_save = function(bufnr) - if vim.b[bufnr].autoformat == false or vim.g.autoformat == false then - return nil - end - return { timeout_ms = 500, lsp_fallback = true } - end, - }) + require("conform").setup({ + formatters_by_ft = { + lua = { "stylua" }, + go = { "gofumpt", "goimports" }, + javascript = biome_or_prettier, + typescript = biome_or_prettier, + javascriptreact = biome_or_prettier, + typescriptreact = biome_or_prettier, + json = biome_or_prettier, + css = { "prettier" }, + html = { "prettier" }, + markdown = { "prettier" }, + toml = { "taplo" }, + }, + format_on_save = function(bufnr) + if vim.b[bufnr].autoformat == false or vim.g.autoformat == false then + return nil + end + return { timeout_ms = 500, lsp_fallback = true } + end, + }) end -lazy.on_event("conform", "BufWritePre", "*", function(args) - setup_conform() - -- 首次保存时手动触发格式化(setup 注册的 autocmd 不会在同一次事件中生效) - if vim.b[args.buf].autoformat ~= false and vim.g.autoformat ~= false then - require("conform").format({ bufnr = args.buf, timeout_ms = 500, lsp_fallback = true }) - end +lazy.on_event("conform", "BufWritePre", "*", function() + setup_conform() + -- conform 的 setup 注册了 BufWritePre,但新 autocmd 不会在同一次事件中触发 + -- 所以这里手动调用 format 补偿第一次保存 + local bufnr = vim.api.nvim_get_current_buf() + if vim.b[bufnr].autoformat ~= false and vim.g.autoformat ~= false then + require("conform").format({ bufnr = bufnr, timeout_ms = 500, lsp_fallback = true }) + end end) -- mason + LSP 配置延迟到 VimEnter,避免启动时加载 lazy.on_event("lsp", "VimEnter", "*", function() - require("mason").setup() + require("mason").setup() - local capabilities = vim.lsp.protocol.make_client_capabilities() - capabilities = vim.tbl_deep_extend("force", capabilities, require("mini.completion").get_lsp_capabilities()) + local capabilities = vim.lsp.protocol.make_client_capabilities() + capabilities = vim.tbl_deep_extend("force", capabilities, require("mini.completion").get_lsp_capabilities()) - vim.lsp.config("*", { capabilities = capabilities }) + vim.lsp.config("*", { capabilities = capabilities }) - vim.lsp.config("lua_ls", { - settings = { - Lua = { - diagnostics = { globals = { "vim" } }, - }, - }, - }) + vim.lsp.config("lua_ls", { + settings = { + Lua = { + diagnostics = { globals = { "vim" } }, + }, + }, + }) - vim.lsp.enable({ - "html", - "cssls", - "gopls", - "vtsls", - "rust_analyzer", - "lua_ls", - "taplo", - "svelte", - "dartls", - "kotlin_lsp", - }) + vim.lsp.enable({ + "html", + "cssls", + "gopls", + "vtsls", + "rust_analyzer", + "lua_ls", + "taplo", + "svelte", + "dartls", + "kotlin_lsp", + }) end) -- LSP keymaps vim.keymap.set("n", "gd", vim.lsp.buf.definition, { desc = "Go to definition" }) vim.keymap.set("n", "gh", vim.lsp.buf.hover, { desc = "Hover" }) vim.keymap.set("n", "fm", function() - lazy.load("conform", setup_conform) - require("conform").format({ lsp_fallback = true }) + lazy.load("conform", setup_conform) + require("conform").format({ lsp_fallback = true }) end, { desc = "Format buffer" }) vim.keymap.set("n", "df", vim.diagnostic.open_float, { desc = "Show line diagnostics" }) vim.keymap.set("n", "ca", vim.lsp.buf.code_action, { desc = "Code action" }) local diagnostic_goto = function(next, severity) - return function() - vim.diagnostic.jump({ - count = (next and 1 or -1) * vim.v.count1, - severity = severity and vim.diagnostic.severity[severity] or nil, - float = true, - }) - end + return function() + vim.diagnostic.jump({ + count = (next and 1 or -1) * vim.v.count1, + severity = severity and vim.diagnostic.severity[severity] or nil, + float = true, + }) + end end vim.keymap.set("n", "]d", diagnostic_goto(true), { desc = "Next Diagnostic" }) diff --git a/lua/options.lua b/lua/options.lua index 1c1a0a0..3e6c579 100644 --- a/lua/options.lua +++ b/lua/options.lua @@ -38,10 +38,10 @@ vim.opt.signcolumn = "yes" vim.opt.termguicolors = true vim.api.nvim_create_autocmd("TextYankPost", { - desc = "Highlight when yanking (copying) text", - callback = function() - vim.hl.on_yank() - end, + desc = "Highlight when yanking (copying) text", + callback = function() + vim.hl.on_yank() + end, }) vim.opt.foldlevel = 99 -- 打开文件时默认展开所有折叠 diff --git a/lua/pack.lua b/lua/pack.lua index ddd0b28..a31bb7d 100644 --- a/lua/pack.lua +++ b/lua/pack.lua @@ -1,196 +1,208 @@ local lazy = require("lazy") vim.pack.add({ - "https://github.com/nvim-mini/mini.nvim", - "https://github.com/rafamadriz/friendly-snippets", - { src = "https://github.com/nvim-treesitter/nvim-treesitter", branch = "main" }, - "https://github.com/neovim/nvim-lspconfig", - "https://github.com/mason-org/mason.nvim", - "https://github.com/stevearc/conform.nvim", - "https://github.com/tpope/vim-fugitive", + "https://github.com/nvim-mini/mini.nvim", + "https://github.com/rafamadriz/friendly-snippets", + { src = "https://github.com/nvim-treesitter/nvim-treesitter", branch = "main" }, + "https://github.com/neovim/nvim-lspconfig", + "https://github.com/mason-org/mason.nvim", + "https://github.com/stevearc/conform.nvim", + "https://github.com/tpope/vim-fugitive", }) -- mini.files - 按键触发 lazy.on_keys("files", "-", "n", function() - require("mini.files").setup({ - mappings = { - go_in = "", - go_in_plus = "L", - go_out = "_", - go_out_plus = "H", - }, - }) + require("mini.files").setup({ + mappings = { + go_in = "", + go_in_plus = "L", + go_out = "_", + go_out_plus = "H", + }, + }) end, function() - require("mini.files").open() + require("mini.files").open() end, { desc = "Toggle mini file explorer" }) lazy.on_keys("files", "-", "n", function() - require("mini.files").setup({ - mappings = { - go_in = "", - go_in_plus = "L", - go_out = "_", - go_out_plus = "H", - }, - }) + require("mini.files").setup({ + mappings = { + go_in = "", + go_in_plus = "L", + go_out = "_", + go_out_plus = "H", + }, + }) end, function() - local MiniFiles = require("mini.files") - MiniFiles.open(vim.api.nvim_buf_get_name(0), false) - MiniFiles.reveal_cwd() + local MiniFiles = require("mini.files") + MiniFiles.open(vim.api.nvim_buf_get_name(0), false) + MiniFiles.reveal_cwd() end, { desc = "Toggle into currently opened file" }) -- mini.notify - 启动时加载 lazy.load("notify", function() - require("mini.notify").setup({ - content = { - format = function(notif) - return notif.msg - end, - }, - }) + require("mini.notify").setup({ + content = { + format = function(notif) + return notif.msg + end, + }, + }) end) -- mini.cmdline - 启动时加载 lazy.load("cmdline", function() - require("mini.cmdline").setup({ - autocorrect = { enable = false }, - }) + require("mini.cmdline").setup({ + autocorrect = { enable = false }, + }) end) -- mini.surround - BufReadPost lazy.on_event("surround", "BufReadPost", "*", function() - require("mini.surround").setup() + require("mini.surround").setup() end) -- mini.pick + mini.extra - 按键触发 local load_pick = function() - lazy.load("pick", function() - require("mini.pick").setup() - end) - lazy.load("extra", function() - require("mini.extra").setup() - end) + lazy.load("pick", function() + require("mini.pick").setup() + end) + lazy.load("extra", function() + require("mini.extra").setup() + end) end lazy.on_keys("pick", "ff", "n", load_pick, function() - require("mini.pick").builtin.files() + require("mini.pick").builtin.files() end, { desc = "Mini File Picker" }) lazy.on_keys("pick", "fw", "n", load_pick, function() - require("mini.pick").builtin.grep({ pattern = vim.fn.expand("") }) -end, { desc = "Grep word/Search word" }) - -lazy.on_keys("pick", "vh", "n", load_pick, function() - require("mini.pick").builtin.help() -end, { desc = "Mini Help" }) + require("mini.pick").builtin.grep_live() +end, { desc = "Live grep in project" }) lazy.on_keys("pick", "ds", "n", load_pick, function() - require("mini.extra").pickers.diagnostic() + require("mini.extra").pickers.diagnostic() end, { desc = "Mini Picker Diagnostics" }) lazy.on_keys("pick", "sk", "n", load_pick, function() - require("mini.extra").pickers.keymaps() + require("mini.extra").pickers.keymaps() end, { desc = "Search keymaps" }) +lazy.on_keys("pick", "fa", "n", load_pick, function() + require("mini.pick").builtin.cli({ command = { "rg", "--files", "--hidden", "--no-ignore", "--color=never" } }) +end, { desc = "Find all files (including hidden/ignored)" }) + +lazy.on_keys("pick", "fh", "n", load_pick, function() + require("mini.pick").builtin.help() +end, { desc = "Search help tags" }) + +lazy.on_keys("pick", "fo", "n", load_pick, function() + require("mini.extra").pickers.oldfiles() +end, { desc = "Search oldfiles" }) + +lazy.on_keys("pick", "fz", "n", load_pick, function() + require("mini.extra").pickers.buf_lines({ scope = "current" }) +end, { desc = "Search in current buffer" }) + -- mini.completion - InsertEnter lazy.on_event("completion", "InsertEnter", "*", function() - require("mini.completion").setup({ - lsp_completion = { - auto_setup = true, - }, - }) + require("mini.completion").setup({ + lsp_completion = { + auto_setup = true, + }, + }) end) -- mini.snippets - InsertEnter lazy.on_event("snippets", "InsertEnter", "*", function() - local MiniSnippets = require("mini.snippets") - MiniSnippets.setup({ - snippets = { - MiniSnippets.gen_loader.from_lang(), - }, - }) - MiniSnippets.start_lsp_server({ match = false }) + local MiniSnippets = require("mini.snippets") + MiniSnippets.setup({ + snippets = { + MiniSnippets.gen_loader.from_lang(), + }, + }) + MiniSnippets.start_lsp_server({ match = false }) end) -- mini.diff - BufReadPost lazy.on_event("diff", "BufReadPost", "*", function() - require("mini.diff").setup({ - source = require("mini.diff").gen_source.git({ index = false }), - }) + require("mini.diff").setup({ + source = require("mini.diff").gen_source.git({ index = false }), + }) end) -- vim-fugitive - 按键触发 lazy.on_keys("fugitive", "gg", "n", nil, function() - vim.cmd("tabnew | Git | only") + vim.cmd("tabnew | Git | only") end, { desc = "Fugitive Full Page New Tab" }) lazy.on_keys("fugitive", "gd", "n", nil, function() - vim.cmd("Gvdiffsplit") + vim.cmd("Gvdiffsplit") end, { desc = "Git diff split" }) -- mini.pick buffer picker (telescope buffers equivalent) lazy.on_keys("pick", "", "n", load_pick, function() - local MiniPick = require("mini.pick") + local MiniPick = require("mini.pick") - 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 + 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 - pcall(vim.api.nvim_buf_delete, bufnr, { force = true }) + pcall(vim.api.nvim_buf_delete, bufnr, { force = true }) - 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 + 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 - 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) + 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) - 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 + 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 - 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 = "", func = delete_buf }, - }, - }) + 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 = "", func = delete_buf }, + }, + }) end, { desc = "Buffers" }) -- mini.pick filetype picker lazy.on_keys("pick", "ft", "n", load_pick, function() - local MiniPick = require("mini.pick") - local filetypes = vim.fn.getcompletion("", "filetype") - MiniPick.start({ - source = { - name = "Filetypes", - items = filetypes, - choose = function(item) - vim.bo.filetype = item - end, - }, - }) + local MiniPick = require("mini.pick") + local filetypes = vim.fn.getcompletion("", "filetype") + MiniPick.start({ + source = { + name = "Filetypes", + items = filetypes, + choose = function(item) + vim.bo.filetype = item + end, + }, + }) end, { desc = "Change filetype" })