-- ~/.config/nvim/init.lua vim.g.mapleader = " " -- 基础体验 vim.opt.number = true vim.opt.relativenumber = true vim.opt.signcolumn = "yes" vim.opt.termguicolors = true vim.opt.mouse = "a" vim.opt.clipboard = "unnamedplus" vim.opt.updatetime = 250 vim.opt.timeoutlen = 400 -- 缩进(先给一个通用默认) vim.opt.tabstop = 2 vim.opt.shiftwidth = 2 vim.opt.expandtab = true vim.opt.smartindent = true vim.opt.scrolloff = 12 -- 搜索 vim.opt.ignorecase = true vim.opt.smartcase = true vim.opt.hlsearch = true vim.opt.incsearch = true -- 基本按键 vim.keymap.set("n", "w", "w", { desc = "save" }) vim.keymap.set("n", "q", "q", { desc = "quit" }) vim.keymap.set("n", "", "nohlsearch") vim.keymap.set("n", "vs", "vsplit", { desc = "Vertical split" }) vim.keymap.set("n", "hs", "split", { desc = "Horizontal split" }) vim.keymap.set("n", "sx", "close", { desc = "Close split" }) vim.keymap.set("n", "so", "only", { desc = "Only this split" }) vim.keymap.set("i", "jj", function() vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("", true, false, true), "n", false) if vim.bo.modified and vim.bo.buftype == "" and vim.fn.expand("%") ~= "" then vim.cmd("silent update") end end, { noremap = true, silent = true}) vim.keymap.set("i", "", "", { noremap = true, silent = true }) vim.keymap.set("i", "", "", { noremap = true, silent = true }) vim.keymap.set("i", "", "", { noremap = true, silent = true }) vim.keymap.set("i", "", "", { noremap = true, silent = true }) vim.keymap.set("n", "", ":m .+1==", { noremap = true, silent = true }) vim.keymap.set("n", "", ":m .-2==", { noremap = true, silent = true }) vim.keymap.set("v", "", ":m '>+1gv=gv", { noremap = true, silent = true }) vim.keymap.set("v", "", ":m '<-2gv=gv", { noremap = true, silent = true }) vim.keymap.set("n", "tn", "tabnew", { desc = "tabnew" }) -- 切换tab for i = 1, 9 do vim.keymap.set("n", "" .. i, i .. "gt", { desc = "Go to tab " .. i }) end vim.keymap.set("n", "th", "gT", { desc = "Prev tab" }) vim.keymap.set("n", "tl", "gt", { desc = "Next tab" }) -- edit vim config -- vim.keymap.set("n", "ev", function() vim.cmd("edit " .. vim.fn.stdpath("config") .. "/init.lua") end, { desc = "Edit init.lua" }) -- source vim config -- vim.keymap.set("n", "sv", function() vim.cmd("source" .. vim.fn.stdpath("config") .. "/init.lua") vim.notify("init.lua reloaded") end, { desc = "Reload init.lua" }) -- 当前lsp vim.keymap.set("n", "lc", function() print(vim.inspect(vim.lsp.get_clients({ bufnr = 0 }))) end, { desc = "LSP: clients (current buffer)"}) -- 超有用的排错开关:显示报错来源 vim.opt.shortmess:remove("F") vim.diagnostic.config({ virtual_text = false, signs = true, underline = true, update_in_insert = false, severity_sort = true, float = { border = "rounded", source = "if_many"}, }) -- clangd 配置 local caps = vim.lsp.protocol.make_client_capabilities() local ok, cmp_lsp = pcall(require, "cmp_nvim_lsp") if ok then caps = cmp_lsp.default_capabilities(caps) end -- clangd vim.lsp.config("clangd", { capabilities = caps, cmd = { "clangd", "--background-index", "--clang-tidy", "--completion-style=detailed", "--header-insertion=never", "--suggest-missing-includes=false", }, filetypes = { "c", "cpp", "objc", "objcpp", "cuda" }, root_markers = { "compile_commands.json", "compile_flags.txt", ".git", "CMakeLists.txt" }, }) -- Rust vim.lsp.config("rust_analyzer", { capabilities = caps, root_markers = { "Cargo.toml", ".git" }, }) -- Zig vim.lsp.config("zls", { capabilities = caps, root_markers = { "build.zig", "build.zig.zon", ".git"}, }) -- Json vim.lsp.config("jsonls", { capabilities = caps, root_markers = { "package.json", ".git"}, }) -- CMake LSP vim.lsp.config("cmake", { capabilities = caps, cmd = { "cmake-language-server" }, root_markers = { "CMakeLists.txt", ".git" }, filetypes = { "cmake" }, init_options = { buildDirectory = "build", }, }) -- GLSL vim.lsp.config("glslls", { cmd = { vim.fn.expand("glslls"), "--stdin", "--target-env", "opengl4.5" }, filetypes = {"glsl"}, root_markers = { ".git", "." }, }) vim.filetype.add({ extension = { vert = "glsl", frag = "glsl", comp = "glsl", geom = "glsl", tesc = "glsl", tese = "glsl", glsl = "glsl", }, }) -- QML / QMLJS LSP (Qt qmlls) local qml_cmd = vim.fn.exepath("qmlls") if qml_cmd == "" then qml_cmd = vim.fn.exepath("qmlls6") end vim.lsp.config("qmlls", { cmd = { qml_cmd }, filetypes = { "qml", "qmljs" }, root_markers = { ".qmlls.ini", "qmldir", ".git" }, }) -- enable lsp -- vim.lsp.enable({ "clangd", "rust_analyzer", "zls", "jsonls", "glslls", "build", "qmlls"}) -- ===== Auto save on leave ===== vim.api.nvim_create_autocmd({ "BufLeave", "WinLeave", "TabLeave", "InsertLeave", },{ callback = function() if vim.bo.modified and vim.bo.buftype == "" and vim.fn.expand("%") ~= "" then vim.cmd("silent write") end end, }) vim.api.nvim_create_autocmd("LspAttach", { callback = function(args) local buf = args.buf local map = function(mode, lhs, rhs, desc) vim.keymap.set(mode, lhs, rhs, { buffer = buf, desc = desc }) end map("n", "gd", vim.lsp.buf.definition, "Go to definition") map("n", "gr", vim.lsp.buf.references, "References") map("n", "K", vim.lsp.buf.hover, "Hover") map("n", "rn", vim.lsp.buf.rename, "Rename") map("n", "ca", vim.lsp.buf.code_action, "Code Action") map("n", "[d", vim.diagnostic.goto_prev, "Prev diagnostic") map("n", "]d", vim.diagnostic.goto_next, "Next diagnostic") map("n", "e", vim.diagnostic.open_float, "Line diagnostic") end, }) -- === lazy.nvim bootstrap === local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" if not vim.loop.fs_stat(lazypath) then vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", "--branch=stable", lazypath }) end vim.opt.rtp:prepend(lazypath) require("lazy_bootstrap") -- === plugins === require("lazy").setup({ { "tpope/vim-sleuth" }, { "nvim-treesitter/nvim-treesitter", build = ":TSUpdate", config = function() vim.api.nvim_create_autocmd("FileType", { callback = function(args) local ft = vim.bo[args.buf].filetype if ft == "lazy" then return end local lang = vim.treesitter.language.get_lang(ft) if not lang then return end local ok = pcall(vim.treesitter.get_parser, args.buf, lang) if ok then pcall(vim.treesitter.start, args.buf, lang) end end, }) end, }, { "hrsh7th/nvim-cmp", dependencies = { "hrsh7th/cmp-nvim-lsp", "hrsh7th/cmp-buffer", "hrsh7th/cmp-path", "L3MON4D3/LuaSnip", "saadparwaiz1/cmp_luasnip", "rafamadriz/friendly-snippets", }, config = function() local cmp = require("cmp") local luasnip = require("luasnip") require("luasnip.loaders.from_vscode").lazy_load() cmp.setup({ snippet = { expand = function(args) luasnip.lsp_expand(args.body) end, }, mapping = cmp.mapping.preset.insert({ [""] = cmp.mapping.complete(), [""] = cmp.mapping.confirm({ select = true }), [""] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_next_item() elseif luasnip.expand_or_jumpable() then luasnip.expand_or_jump() 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 = { { name = "nvim_lsp"}, { name = "luasnip" }, { name = "path" }, { name = "buffer" }, }, }) end, }, { "stevearc/conform.nvim", opts = { formatters_by_ft = { cpp = { "clang-format" }, c = { "clang-format" }, }, }, config = function(_, opts) require("conform").setup(opts) vim.keymap.set({ "n", "v"}, "f", function() require("conform").format({ lsp_fallback = true }) end, { desc = "Format" }) end, }, { "lewis6991/gitsigns.nvim", config = function() require("gitsigns").setup() end, }, { "nvim-telescope/telescope.nvim", dependencies = { "nvim-lua/plenary.nvim" }, config = function() local telescope = require("telescope") telescope.setup({ defaults = { -- 体验相关 prompt_prefix = "  ", selection_caret = "❯ ", sorting_strategy = "ascending", layout_config = { prompt_position = "top", }, }, }) local builtin = require("telescope.builtin") -- 常用快捷键 vim.keymap.set("n", "ff", builtin.find_files, { desc = "Find files" }) vim.keymap.set("n", "fg", builtin.live_grep, { desc = "Live grep" }) vim.keymap.set("n", "fb", builtin.buffers, { desc = "Buffers" }) vim.keymap.set("n", "fh", builtin.help_tags, { desc = "Help tags" }) vim.keymap.set("n", "fd", builtin.diagnostics,{ desc = "Diagnostics" }) vim.keymap.set("n", "fs", builtin.lsp_document_symbols, { desc = "Symbols (buffer)" }) vim.keymap.set("n", "fS", builtin.lsp_workspace_symbols,{ desc = "Symbols (workspace)" }) end, }, { "echasnovski/mini.pairs", version = false, config = function() require("mini.pairs").setup({ }) end, }, { "folke/tokyonight.nvim", priority = 1000, config = function() vim.cmd.colorscheme("tokyonight") end, }, { "stevearc/dressing.nvim", event = "VeryLazy", config = function() require("dressing").setup({ input = { border = "rounded", }, select = { backend = { "builtin" }, }, }) end, }, { "nvim-neo-tree/neo-tree.nvim", branch = "v3.x", dependencies = { "nvim-lua/plenary.nvim", "nvim-tree/nvim-web-devicons", "MunifTanjim/nui.nvim", }, config = function() require("neo-tree").setup({ close_if_last_window = true, popup_border_style = "rounded", enable_git_status = true, enable_diagnostics = true, window = { position = "left", width = 32, mapping = { ["l"] = "open", ["h"] = "close_node", [""] = "toggle_node", }, }, filesystem = { filtered_items = { visible = true, hide_dotfiles = false, hide_gitignored = false, }, follow_current_file = { enable = true, }, }, }) vim.keymap.set("n", "fe", "Neotree toggle left", { desc = "Explorer (Neo-tree)"}) vim.keymap.set("n", "-", "Neotree toggle left", { desc = "Explorer (Neo-tree)"}) end, }, })