Initial Neovim config
- Add init.lua entry point - Add lua/ modules: options, keymaps, autocmds, usercmds, pack, treesitter, lsp - Add .gitignore - Add nvim-pack-lock.json for plugin version locking Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
a45929aff6
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.omc/
|
||||
others/
|
||||
9
init.lua
Normal file
9
init.lua
Normal file
@ -0,0 +1,9 @@
|
||||
require("vim._core.ui2").enable({})
|
||||
|
||||
require("options")
|
||||
require("keymaps")
|
||||
require("autocmds")
|
||||
require("usercmds")
|
||||
require("pack")
|
||||
require("treesitter")
|
||||
require("lsp")
|
||||
36
lua/autocmds.lua
Normal file
36
lua/autocmds.lua
Normal file
@ -0,0 +1,36 @@
|
||||
local group = vim.api.nvim_create_augroup("UserAutocmds", { clear = true })
|
||||
|
||||
-- 恢复上次编辑位置
|
||||
vim.api.nvim_create_autocmd("BufReadPost", {
|
||||
group = group,
|
||||
callback = function()
|
||||
local mark = vim.api.nvim_buf_get_mark(0, '"')
|
||||
local row = mark[1]
|
||||
local ft = vim.bo.filetype
|
||||
|
||||
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
|
||||
vim.api.nvim_win_set_cursor(0, mark)
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- 注释延续行为
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
group = group,
|
||||
callback = function()
|
||||
vim.opt_local.formatoptions:remove("o") -- o/O 换行不延续注释
|
||||
vim.opt_local.formatoptions:append("r") -- 回车延续注释
|
||||
end,
|
||||
})
|
||||
|
||||
-- 延迟设置 Treesitter 折叠(避免启动时加载 treesitter 模块)
|
||||
vim.api.nvim_create_autocmd("BufEnter", {
|
||||
group = group,
|
||||
once = true,
|
||||
callback = function()
|
||||
vim.o.foldmethod = "expr"
|
||||
vim.o.foldexpr = "v:lua.vim.treesitter.foldexpr()"
|
||||
end,
|
||||
})
|
||||
154
lua/keymaps.lua
Normal file
154
lua/keymaps.lua
Normal file
@ -0,0 +1,154 @@
|
||||
vim.g.mapleader = " "
|
||||
|
||||
local map = vim.keymap.set
|
||||
|
||||
map("x", "p", [["_dP]], { desc = "Paste over selection without losing yanked text" })
|
||||
-- map({ "n", "v" }, "<leader>d", [["_d]], { desc = "Delete without yanking" })
|
||||
|
||||
map("n", "<Esc>", ":nohl<CR>", { desc = "Clear search highlighting", silent = true })
|
||||
|
||||
map("v", "<", "<gv", { desc = "Unindent and keep selection" })
|
||||
map("v", ">", ">gv", { desc = "Indent and keep selection" })
|
||||
|
||||
map("n", "J", "mzJ`z", { desc = "Join lines without moving cursor" })
|
||||
|
||||
map("n", "<leader>ss", [[:%s/\<<C-r><C-w>\>/<C-r><C-w>/gI<Left><Left><Left>]],
|
||||
{ desc = "Replace word cursor is on globally" })
|
||||
-- search
|
||||
map("v", "<leader>ss", ":s/\\%V", { desc = "Search and replace in visual selection" })
|
||||
|
||||
-- general
|
||||
map("n", "$", "g_")
|
||||
map("v", "$", "g_")
|
||||
map("v", ">", ">gv")
|
||||
map("v", "<", "<gv")
|
||||
|
||||
-- native undotree
|
||||
vim.keymap.set("n", "<leader>u", function()
|
||||
vim.cmd.packadd("nvim.undotree")
|
||||
require("undotree").open()
|
||||
end, { desc = "Toggle Builtin Undotree" })
|
||||
|
||||
map("t", "<C-x>", "<c-\\><c-n>", { desc = "Escape termainl" })
|
||||
map("n", "<leader>tt", ":term<CR>", { desc = "Open new terminal" })
|
||||
|
||||
-- tabs
|
||||
map("n", "<leader>tc", ":tabclose<CR>", { desc = "Close current tab" })
|
||||
map("n", "<leader>tn", ":tabnew<CR>", { desc = "New tab" })
|
||||
map("n", "<leader>]", ":tabnext<CR>", { desc = "Next tab" })
|
||||
map("n", "<leader>[", ":tabprevious<CR>", { desc = "Previous tab" })
|
||||
|
||||
|
||||
-- yank path
|
||||
map("n", "<leader>yp", function()
|
||||
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", "<leader>yP", function()
|
||||
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", "<leader>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
|
||||
end, { desc = "Close current buffer" })
|
||||
map("n", "<leader>bn", "<cmd>enew<CR>", { desc = "Buffer new" })
|
||||
|
||||
map("n", "<leader>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
|
||||
end, { desc = "Close other buffers" })
|
||||
|
||||
-- mini.pick buffer picker (telescope buffers equivalent)
|
||||
map("n", "<leader><leader>", function()
|
||||
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
|
||||
|
||||
-- 先删除 buffer(pcall 保护,避免删除当前窗口 buffer 时出错)
|
||||
pcall(vim.api.nvim_buf_delete, bufnr, { force = true })
|
||||
|
||||
-- 刷新列表:只保留仍然有效的 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,过滤特殊类型和未列出的,按最近使用排序
|
||||
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
|
||||
|
||||
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 = "Buffers" })
|
||||
|
||||
-- mini.pick filetype picker
|
||||
map("n", "<leader>ft", 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,
|
||||
},
|
||||
})
|
||||
end, { desc = "Change filetype" })
|
||||
52
lua/lsp.lua
Normal file
52
lua/lsp.lua
Normal file
@ -0,0 +1,52 @@
|
||||
require("mason").setup()
|
||||
|
||||
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", "<leader>fm", vim.lsp.buf.format, { desc = "Format Local buffer" })
|
||||
vim.keymap.set("n", "df", vim.diagnostic.open_float, { desc = "Show line diagnostics" })
|
||||
vim.keymap.set("n", "<leader>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
|
||||
end
|
||||
|
||||
vim.keymap.set("n", "]d", diagnostic_goto(true), { desc = "Next Diagnostic" })
|
||||
vim.keymap.set("n", "[d", diagnostic_goto(false), { desc = "Prev Diagnostic" })
|
||||
vim.keymap.set("n", "]e", diagnostic_goto(true, "ERROR"), { desc = "Next Error" })
|
||||
vim.keymap.set("n", "[e", diagnostic_goto(false, "ERROR"), { desc = "Prev Error" })
|
||||
vim.keymap.set("n", "]w", diagnostic_goto(true, "WARN"), { desc = "Next Warning" })
|
||||
vim.keymap.set("n", "[w", diagnostic_goto(false, "WARN"), { desc = "Prev Warning" })
|
||||
|
||||
vim.diagnostic.config({ virtual_text = true })
|
||||
|
||||
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("lua_ls", {
|
||||
settings = {
|
||||
Lua = {
|
||||
diagnostics = { globals = { "vim" } },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
vim.lsp.enable({
|
||||
"html",
|
||||
"cssls",
|
||||
"gopls",
|
||||
"vtsls",
|
||||
"rust_analyzer",
|
||||
"lua_ls",
|
||||
"taplo",
|
||||
"svelte",
|
||||
"dartls",
|
||||
"kotlin_lsp"
|
||||
})
|
||||
46
lua/options.lua
Normal file
46
lua/options.lua
Normal file
@ -0,0 +1,46 @@
|
||||
vim.g.netrw_banner = 0
|
||||
|
||||
vim.opt.nu = true
|
||||
vim.opt.relativenumber = true
|
||||
vim.opt.cursorline = true
|
||||
vim.opt.cursorlineopt = "both"
|
||||
vim.opt.autoread = true
|
||||
|
||||
vim.opt.tabstop = 4
|
||||
vim.opt.softtabstop = 4
|
||||
vim.opt.shiftwidth = 4
|
||||
vim.opt.expandtab = true
|
||||
|
||||
vim.opt.smartindent = true
|
||||
vim.opt.inccommand = "split"
|
||||
|
||||
vim.opt.splitbelow = true
|
||||
vim.opt.splitright = true
|
||||
|
||||
vim.opt.ignorecase = true
|
||||
vim.opt.smartcase = true
|
||||
vim.opt.laststatus = 3
|
||||
|
||||
vim.opt.swapfile = false
|
||||
vim.opt.backup = false
|
||||
vim.opt.undodir = vim.fn.stdpath("data") .. "/undodir"
|
||||
vim.opt.undofile = true
|
||||
|
||||
vim.opt.completeopt = "menuone,noselect,fuzzy,nosort"
|
||||
vim.opt.shortmess:append("c")
|
||||
vim.opt.clipboard:append("unnamedplus")
|
||||
vim.opt.isfname:append("@-@")
|
||||
vim.opt.guicursor = ""
|
||||
vim.opt.scrolloff = 8
|
||||
|
||||
vim.opt.colorcolumn = "0"
|
||||
vim.opt.signcolumn = "yes"
|
||||
|
||||
vim.api.nvim_create_autocmd("TextYankPost", {
|
||||
desc = "Highlight when yanking (copying) text",
|
||||
callback = function()
|
||||
vim.hl.on_yank()
|
||||
end,
|
||||
})
|
||||
|
||||
vim.opt.foldlevel = 99 -- 打开文件时默认展开所有折叠
|
||||
91
lua/pack.lua
Normal file
91
lua/pack.lua
Normal file
@ -0,0 +1,91 @@
|
||||
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/tpope/vim-fugitive",
|
||||
})
|
||||
|
||||
-- mini files ----
|
||||
local MiniFiles = require("mini.files")
|
||||
MiniFiles.setup({
|
||||
mappings = {
|
||||
go_in = "<CR>",
|
||||
go_in_plus = "L",
|
||||
go_out = "_",
|
||||
go_out_plus = "H",
|
||||
},
|
||||
})
|
||||
|
||||
vim.keymap.set("n", "<leader>-", "<cmd>lua MiniFiles.open()<CR>", { desc = "Toggle mini file explorer" })
|
||||
vim.keymap.set("n", "-", function()
|
||||
MiniFiles.open(vim.api.nvim_buf_get_name(0), false)
|
||||
MiniFiles.reveal_cwd()
|
||||
end, { desc = "Toggle into currently opened file" })
|
||||
|
||||
---- mini notify ----
|
||||
require("mini.notify").setup({
|
||||
-- only show messages
|
||||
content = {
|
||||
format = function(notif)
|
||||
return notif.msg
|
||||
end,
|
||||
},
|
||||
})
|
||||
|
||||
--- mini cmdline completion ---
|
||||
require("mini.cmdline").setup({
|
||||
autocorrect = { enable = false }
|
||||
})
|
||||
|
||||
--- mini surround ---
|
||||
require("mini.surround").setup()
|
||||
-- Default Keymaps
|
||||
-- | `sa` | Add surrounding or Direct with 'saiw' |
|
||||
-- | `sd` | Delete surrounding |
|
||||
-- | `sr` | Replace surrounding |
|
||||
-- | `sf` | Find surrounding (right) |
|
||||
-- | `sF` | Find surrounding (left) |
|
||||
-- | `sh` | Highlight surrounding |
|
||||
-- | `sn` | Update n_lines |
|
||||
-- | `l` / `n` | as suffix for prev/next |
|
||||
|
||||
--- mini picker ---
|
||||
local MiniPick = require("mini.pick")
|
||||
local MiniExtra = require("mini.extra")
|
||||
MiniPick.setup()
|
||||
MiniExtra.setup()
|
||||
|
||||
-- keymaps
|
||||
vim.keymap.set("n", "<leader>ff", function() MiniPick.builtin.files() end, { desc = "Mini File Picker" })
|
||||
vim.keymap.set("n", "<leader>fw", function() MiniPick.builtin.grep({ pattern = vim.fn.expand("<cword>") }) end, { desc = "Grep word/Search word" })
|
||||
vim.keymap.set("n", "<leader>vh", function() MiniPick.builtin.help() end, { desc = "Mini Help" })
|
||||
|
||||
vim.keymap.set("n", "<leader>ds", function() MiniExtra.pickers.diagnostic() end, { desc = "Mini Picker Diagnostics" })
|
||||
vim.keymap.set("n", "<leader>sk", function() MiniExtra.pickers.keymaps() end, { desc = 'Search keymaps' })
|
||||
|
||||
--- mini completions ---
|
||||
require("mini.completion").setup({
|
||||
lsp_completion = {
|
||||
auto_setup = true,
|
||||
}
|
||||
})
|
||||
|
||||
--- mini snippets ---
|
||||
local MiniSnippets = require("mini.snippets")
|
||||
MiniSnippets.setup({
|
||||
snippets = {
|
||||
MiniSnippets.gen_loader.from_lang(), -- loads friendly-snippets
|
||||
},
|
||||
})
|
||||
MiniSnippets.start_lsp_server({ match = false })
|
||||
|
||||
--- mini diff and fugitive ---
|
||||
local MiniDiff = require("mini.diff")
|
||||
MiniDiff.setup({
|
||||
source = MiniDiff.gen_source.git({ index = false }),
|
||||
})
|
||||
|
||||
vim.keymap.set("n", "<leader>gg", "<cmd>tabnew | Git | only<cr>", { desc = "Fugitive Full Page New Tab" })
|
||||
vim.keymap.set("n", "<leader>gd", "<cmd>Gvdiffsplit<CR>", { desc = "Git diff split", })
|
||||
49
lua/treesitter.lua
Normal file
49
lua/treesitter.lua
Normal file
@ -0,0 +1,49 @@
|
||||
local treesitter = require("nvim-treesitter")
|
||||
|
||||
local ensure_installed = {
|
||||
"lua",
|
||||
"vim",
|
||||
"vimdoc",
|
||||
-- Web
|
||||
"javascript",
|
||||
"typescript",
|
||||
"tsx",
|
||||
"jsdoc",
|
||||
"json",
|
||||
"html",
|
||||
"css",
|
||||
"yaml",
|
||||
-- Backend
|
||||
"c",
|
||||
"rust",
|
||||
"toml",
|
||||
"go",
|
||||
"gomod",
|
||||
"gosum",
|
||||
"gowork",
|
||||
-- Infra
|
||||
"dockerfile",
|
||||
"make",
|
||||
}
|
||||
|
||||
treesitter.install(ensure_installed)
|
||||
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
pattern = "*",
|
||||
callback = function(args)
|
||||
local buf = args.buf
|
||||
local ft = vim.bo[buf].filetype
|
||||
|
||||
local lang = vim.treesitter.language.get_lang(ft)
|
||||
if not lang then
|
||||
return
|
||||
end
|
||||
|
||||
local ok_add = pcall(vim.treesitter.language.add, lang)
|
||||
if not ok_add then
|
||||
return
|
||||
end
|
||||
|
||||
pcall(vim.treesitter.start, buf, lang)
|
||||
end,
|
||||
})
|
||||
21
lua/usercmds.lua
Normal file
21
lua/usercmds.lua
Normal file
@ -0,0 +1,21 @@
|
||||
vim.api.nvim_create_user_command("PackAdd", function(opts)
|
||||
vim.pack.add(opts.fargs)
|
||||
end, { nargs = "+", desc = "Add plugins (:PackAdd user/repo1 user/repo2)" })
|
||||
|
||||
-- Pack Delete and Update cmds are built-in on Nightly 0.13
|
||||
vim.api.nvim_create_user_command("PackDel", function(opts)
|
||||
vim.pack.del(opts.fargs)
|
||||
end, { nargs = "+", desc = "Delete plugins (:PackDel plugin1 plugin2)" })
|
||||
|
||||
vim.api.nvim_create_user_command("PackUpdate", function(opts)
|
||||
-- checks if any argument is passed
|
||||
if opts.args:match("%S") then
|
||||
-- update specific plugins
|
||||
local plugins = vim.split(opts.args, "%s+", { trimempty = true })
|
||||
-- update only specified plugins
|
||||
vim.pack.update(plugins)
|
||||
else
|
||||
-- update all
|
||||
vim.pack.update()
|
||||
end
|
||||
end, { nargs = "*", desc = "Update all plugins or specific ones" })
|
||||
28
nvim-pack-lock.json
Normal file
28
nvim-pack-lock.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"plugins": {
|
||||
"friendly-snippets": {
|
||||
"rev": "6cd7280adead7f586db6fccbd15d2cac7e2188b9",
|
||||
"src": "https://github.com/rafamadriz/friendly-snippets"
|
||||
},
|
||||
"mason.nvim": {
|
||||
"rev": "bb639d4bf385a4d89f478b83af4d770be05ab7eb",
|
||||
"src": "https://github.com/mason-org/mason.nvim"
|
||||
},
|
||||
"mini.nvim": {
|
||||
"rev": "44657837c7338e52727facc85c1d95bec1f6bd7c",
|
||||
"src": "https://github.com/nvim-mini/mini.nvim"
|
||||
},
|
||||
"nvim-lspconfig": {
|
||||
"rev": "6f76a3eeadc2ee235d74cd7d5319e95a261084af",
|
||||
"src": "https://github.com/neovim/nvim-lspconfig"
|
||||
},
|
||||
"nvim-treesitter": {
|
||||
"rev": "4916d6592ede8c07973490d9322f187e07dfefac",
|
||||
"src": "https://github.com/nvim-treesitter/nvim-treesitter"
|
||||
},
|
||||
"vim-fugitive": {
|
||||
"rev": "3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0",
|
||||
"src": "https://github.com/tpope/vim-fugitive"
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user