diff --git a/nvim/.config/nvim/ftplugin/gdscript.lua b/nvim/.config/nvim/ftplugin/gdscript.lua new file mode 100644 index 0000000..a10eb19 --- /dev/null +++ b/nvim/.config/nvim/ftplugin/gdscript.lua @@ -0,0 +1 @@ +vim.keymap.set("n", "rp", "GodotRunProject", { buffer = true, desc = "Godot: run project" }) diff --git a/nvim/.config/nvim/lazy-lock.json b/nvim/.config/nvim/lazy-lock.json index 1aca9ce..269a9bc 100644 --- a/nvim/.config/nvim/lazy-lock.json +++ b/nvim/.config/nvim/lazy-lock.json @@ -1,27 +1,31 @@ { - "auto-session": { "branch": "main", "commit": "62437532b38495551410b3f377bcf4aaac574ebe" }, - "barbar.nvim": { "branch": "master", "commit": "539d73def39c9172b4d4d769f14090e08f37b29d" }, + "auto-session": { "branch": "main", "commit": "3e145ee9af42eb6764908a1a481f53fe7f0bdbe5" }, + "barbar.nvim": { "branch": "master", "commit": "a4bef5b4fc1f064f2f673172252028eae18191c9" }, "blink.cmp": { "branch": "main", "commit": "78336bc89ee5365633bcf754d93df01678b5c08f" }, - "claudecode.nvim": { "branch": "main", "commit": "432121f0f5b9bda041030d1e9e83b7ba3a93dd8f" }, - "conform.nvim": { "branch": "master", "commit": "086a40dc7ed8242c03be9f47fbcee68699cc2395" }, - "fzf-lua": { "branch": "main", "commit": "9f0432fdd7825ab163520045831a40b6df82ea28" }, - "gitsigns.nvim": { "branch": "main", "commit": "0d797daee85366bc242580e352a4f62d67557b84" }, + "claudecode.nvim": { "branch": "main", "commit": "102d835c964069c9c5e37abaf05ae4f9c3ee6f00" }, + "conform.nvim": { "branch": "master", "commit": "619363c30309d29ffa631e67c8183f2a72caa373" }, + "fzf-lua": { "branch": "main", "commit": "fea9eedc6894c44d44cbb772a5cd11c93b82d7a1" }, + "gitsigns.nvim": { "branch": "main", "commit": "dd3f588bacbeb041be6facf1742e42097f62165d" }, + "godotdev.nvim": { "branch": "master", "commit": "ad3881a4da12ed9e4a1032fa920d872ff6dd9c49" }, "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, "lazygit.nvim": { "branch": "main", "commit": "a04ad0dbc725134edbee3a5eea29290976695357" }, - "leap.nvim": { "branch": "main", "commit": "b960d5038c5c505c52e56a54490f9bbb1f0e6ef6" }, - "lualine.nvim": { "branch": "master", "commit": "8811f3f3f4dc09d740c67e9ce399e7a541e2e5b2" }, - "mason-lspconfig.nvim": { "branch": "main", "commit": "25f609e7fca78af7cede4f9fa3af8a94b1c4950b" }, - "mason.nvim": { "branch": "main", "commit": "b03fb0f20bc1d43daf558cda981a2be22e73ac42" }, + "leap.nvim": { "branch": "main", "commit": "59d70b1bdf8e76e0637e6ebcc150fb6767f67fc5" }, + "lualine.nvim": { "branch": "master", "commit": "131a558e13f9f28b15cd235557150ccb23f89286" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "7b01e2974a47d489bb92f47a41e4c0088ea8f86e" }, + "mason.nvim": { "branch": "main", "commit": "bb639d4bf385a4d89f478b83af4d770be05ab7eb" }, "nvim-cmp": { "branch": "main", "commit": "85bbfad83f804f11688d1ab9486b459e699292d6" }, - "nvim-lspconfig": { "branch": "master", "commit": "bedca8b426b2fee0ccac596d167d71bbe971253f" }, + "nvim-dap": { "branch": "master", "commit": "531771530d4f82ad2d21e436e3cc052d68d7aebb" }, + "nvim-dap-ui": { "branch": "master", "commit": "1a66cabaa4a4da0be107d5eda6d57242f0fe7e49" }, + "nvim-lspconfig": { "branch": "master", "commit": "9573948c38bfabeec353ae7dd7d3ffec4c506a6b" }, "nvim-navic": { "branch": "master", "commit": "f5eba192f39b453675d115351808bd51276d9de5" }, "nvim-treesitter": { "branch": "main", "commit": "4916d6592ede8c07973490d9322f187e07dfefac" }, - "nvim-web-devicons": { "branch": "master", "commit": "95b7a002d5dba1a42eb58f5fac5c565a485eefd0" }, - "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, - "snacks.nvim": { "branch": "main", "commit": "ad9ede6a9cddf16cedbd31b8932d6dcdee9b716e" }, - "tiny-inline-diagnostic.nvim": { "branch": "main", "commit": "57a0eb84b2008c76e77930639890d9874195b1e1" }, + "nvim-web-devicons": { "branch": "master", "commit": "dfbfaa967a6f7ec50789bead7ef87e336c1fa63c" }, + "plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" }, + "snacks.nvim": { "branch": "main", "commit": "882c996cf28183f4d63640de0b4c02ec886d01f2" }, + "teamtype-nvim": { "branch": "main", "commit": "799402fc3c49118e4703bc48f379ea6930824dab" }, + "tiny-inline-diagnostic.nvim": { "branch": "main", "commit": "6bdbc9a2f5a846ff5fc55a998ff97c0e2968b7e5" }, "vgit.nvim": { "branch": "main", "commit": "7e147e8cb2f160ae3c8d353005666f636d34acb2" }, "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" }, - "yazi.nvim": { "branch": "main", "commit": "172bd64a4c2d3adbe2e0ef56289f47ffe139ca55" }, + "yazi.nvim": { "branch": "main", "commit": "81097571080ce0c5ab9e0311ed8ad03ff080ef47" }, "yuck.vim": { "branch": "master", "commit": "9b5e0370f70cc30383e1dabd6c215475915fe5c3" } } diff --git a/nvim/.config/nvim/lua/autocmds.lua b/nvim/.config/nvim/lua/autocmds.lua index 485d70c..2b88049 100644 --- a/nvim/.config/nvim/lua/autocmds.lua +++ b/nvim/.config/nvim/lua/autocmds.lua @@ -32,6 +32,112 @@ autocmd("TermOpen", { command = "startinsert" }) +-- godotdev.nvim manages the gdscript LSP (client "godot_editor") with its own on_attach. +-- Registered here (startup) so it's ready before the LSP attaches -- when opening +-- `nvim foo.gd` directly, FileType fires before UIEnter, meaning the LSP can attach +-- before lspconfig.lua ever loads via "User FilePost". +autocmd("LspAttach", { + callback = function(args) + local client = vim.lsp.get_client_by_id(args.data.client_id) + if not client or client.name ~= "godot_editor" then return end + + local ok, navic = pcall(require, "nvim-navic") + if ok and client.server_capabilities.documentSymbolProvider then + navic.attach(client, args.buf) + end + + local map = vim.keymap.set + local bufnr = args.buf + local function opts(desc) return { buffer = bufnr, desc = "LSP " .. desc } end + map("n", "gD", vim.lsp.buf.declaration, opts "Go to declaration") + map("n", "gd", vim.lsp.buf.definition, opts "Go to definition") + map("n", "gi", vim.lsp.buf.implementation, opts "Go to implementation") + map("n", "gr", vim.lsp.buf.references, opts "Show references") + map("n", "sh", vim.lsp.buf.signature_help, opts "Show signature help") + map("n", "D", vim.lsp.buf.type_definition, opts "Go to type definition") + map("n", "ra", vim.lsp.buf.rename, opts "Rename symbol") + map({ "n", "v" }, "ca", vim.lsp.buf.code_action, opts "Code action") + map("n", "[d", vim.diagnostic.goto_prev, opts "Go to previous diagnostic") + map("n", "]d", vim.diagnostic.goto_next, opts "Go to next diagnostic") + map("n", "q", vim.diagnostic.setloclist, opts "Set loclist") + end, +}) + +-- The godotdev "godot_editor" LSP connects over TCP to the running Godot editor, +-- so its socket dies on every project reload. Re-attach on insert mode transitions +-- (and a delayed retry while still typing) so a reload never needs a Neovim restart. +local godot_reconnect_group = vim.api.nvim_create_augroup("godot_lsp_reconnect", { clear = true }) + +local function reconnect_godot_lsp(bufnr) + if not vim.api.nvim_buf_is_valid(bufnr) then return end + if vim.bo[bufnr].filetype ~= "gdscript" then return end + if next(vim.lsp.get_clients({ name = "godot_editor", bufnr = bufnr })) then return end + local config = vim.lsp.config["gdscript"] + if config then + vim.lsp.start(config, { bufnr = bufnr }) + end +end + +autocmd({ "InsertEnter", "InsertLeave" }, { + group = godot_reconnect_group, + pattern = "*.gd", + callback = function(args) + reconnect_godot_lsp(args.buf) + end, +}) + +autocmd("InsertEnter", { + group = godot_reconnect_group, + pattern = "*.gd", + callback = function(args) + local bufnr = args.buf + vim.defer_fn(function() + if vim.api.nvim_get_mode().mode:sub(1, 1) == "i" then + reconnect_godot_lsp(bufnr) + end + end, 1500) + end, +}) + +-- godotdev's run console appends output without scrolling. Attach to the console +-- buffer to tail new output, but only while the cursor sits at the bottom so +-- scrolling up to read earlier output is not interrupted. +local godot_console_group = vim.api.nvim_create_augroup("godot_console", { clear = true }) + +local function follow_godot_console(bufnr) + if vim.b[bufnr].godot_console_attached then return end + vim.b[bufnr].godot_console_attached = true + + vim.api.nvim_buf_attach(bufnr, false, { + on_lines = function(_, buf, _, firstline) + if not vim.api.nvim_buf_is_valid(buf) then return true end + vim.schedule(function() + if not vim.api.nvim_buf_is_valid(buf) then return end + local last = vim.api.nvim_buf_line_count(buf) + for _, win in ipairs(vim.fn.win_findbuf(buf)) do + if vim.api.nvim_win_is_valid(win) and vim.api.nvim_win_get_cursor(win)[1] >= firstline then + vim.api.nvim_win_set_cursor(win, { last, 0 }) + end + end + end) + end, + on_detach = function() + if vim.api.nvim_buf_is_valid(bufnr) then + vim.b[bufnr].godot_console_attached = nil + end + end, + }) +end + +autocmd("BufWinEnter", { + group = godot_console_group, + callback = function(args) + if vim.api.nvim_buf_get_name(args.buf) == "godotdev://console" then + follow_godot_console(args.buf) + end + end, +}) + -- User event that loads after UIEnter + only if file buf is there -- This is used by plugins for lazy loading via "User FilePost" event autocmd({ "UIEnter", "BufReadPost", "BufNewFile" }, { diff --git a/nvim/.config/nvim/lua/configs/fzf.lua b/nvim/.config/nvim/lua/configs/fzf.lua index c8684c2..ab05d78 100644 --- a/nvim/.config/nvim/lua/configs/fzf.lua +++ b/nvim/.config/nvim/lua/configs/fzf.lua @@ -47,6 +47,7 @@ require("fzf-lua").setup({ file_icons = true, git_icons = false, rg_opts = "--column --line-number --no-heading --color=always --smart-case --max-columns=4096 -e", + rg_glob = true, }, oldfiles = { prompt = "History❯ ", diff --git a/nvim/.config/nvim/lua/configs/lspconfig.lua b/nvim/.config/nvim/lua/configs/lspconfig.lua index b40537d..e886fea 100644 --- a/nvim/.config/nvim/lua/configs/lspconfig.lua +++ b/nvim/.config/nvim/lua/configs/lspconfig.lua @@ -65,7 +65,24 @@ local servers = { capabilities = capabilities, }, clangd = { + cmd = { + "clangd", + "--background-index", + "--clang-tidy", + "--suggest-missing-includes", + "--all-scopes-completion", + "--completion-style=detailed", + "--header-insertion=never", -- Godot headers use explicit includes + "--pch-storage=memory", + }, filetypes = { "c", "cpp", "objc", "objcpp" }, + root_markers = { + "compile_commands.json", + ".clangd", + "SConstruct", + "CMakeLists.txt", + ".git", + }, on_attach = on_attach, capabilities = capabilities, }, @@ -87,9 +104,10 @@ local servers = { ron_lsp = { cmd = { "ron-lsp" }, filetypes = { "ron" }, - root_dir = function(fname) + root_dir = function(bufnr, on_dir) local util = require("lspconfig.util") - return util.root_pattern("Cargo.toml", ".git")(fname) or vim.uv.cwd() + local fname = vim.api.nvim_buf_get_name(bufnr) + on_dir(util.root_pattern("Cargo.toml", ".git")(fname) or vim.uv.cwd()) end, on_attach = on_attach, capabilities = capabilities, diff --git a/nvim/.config/nvim/lua/mappings.lua b/nvim/.config/nvim/lua/mappings.lua index d55b2f8..839ad02 100644 --- a/nvim/.config/nvim/lua/mappings.lua +++ b/nvim/.config/nvim/lua/mappings.lua @@ -91,6 +91,10 @@ map("n", "gt", function() fzf.git_status() end, { desc = "Git status" }) map("n", "fh", function() fzf.help_tags() end, { desc = "Help tags" }) map("n", "ma", function() fzf.marks() end, { desc = "Marks" }) +-- Snacks picker (command palette, fuzzel-style) +map("n", "p", function() Snacks.picker.commands() end, { desc = "Command palette" }) +map("n", "fk", function() Snacks.picker.keymaps() end, { desc = "Find keymaps" }) + -- LSP map('n', 'fs', function() fzf.lsp_document_symbols() end, { desc = 'Document symbols' }) map('n', 'fd', function() fzf.diagnostics_document({ severity_limit = vim.diagnostic.severity.ERROR }) end, { desc = "Buffer diagnostics" }) diff --git a/nvim/.config/nvim/lua/plugins/coding.lua b/nvim/.config/nvim/lua/plugins/coding.lua index 0fa46cc..37fef9c 100644 --- a/nvim/.config/nvim/lua/plugins/coding.lua +++ b/nvim/.config/nvim/lua/plugins/coding.lua @@ -106,6 +106,7 @@ return { formatters_by_ft = { wgsl = { 'wgslfmt' }, wesl = { 'wgslfmt' }, + gdscript = { 'gdscript_formatter' }, }, formatters = { wgslfmt = { @@ -113,6 +114,12 @@ return { args = { '-' }, stdin = true, }, + -- gdscript-formatter modifies the file in-place; no --reorder-code flag + gdscript_formatter = { + command = 'gdscript-formatter', + args = { '$FILENAME' }, + stdin = false, + }, }, }, }, diff --git a/nvim/.config/nvim/lua/plugins/tools.lua b/nvim/.config/nvim/lua/plugins/tools.lua index 7e5bcc7..033d419 100644 --- a/nvim/.config/nvim/lua/plugins/tools.lua +++ b/nvim/.config/nvim/lua/plugins/tools.lua @@ -99,4 +99,35 @@ return { require("configs.claudecode") end }, + + -- Teamtype - jump to cursor and follow + { + "teamtype/teamtype-nvim", + keys = { + { "ej", "TeamtypeJumpToCursor" }, + { "ef", "TeamtypeFollow" }, + }, + lazy = false, + }, + + -- Godot + { + 'Mathijs-Bakker/godotdev.nvim', + ft = { "gdscript", "gdresource", "gdshader" }, + dependencies = { + 'mfussenegger/nvim-dap', + 'rcarriga/nvim-dap-ui', + 'nvim-treesitter/nvim-treesitter', + }, + config = function() + require("godotdev").setup({ + formatter = false, + run = { + console = { + enabled = true, + }, + }, + }) + end, + }, } diff --git a/nvim/.config/nvim/lua/plugins/ui.lua b/nvim/.config/nvim/lua/plugins/ui.lua index 3144e50..888ea84 100644 --- a/nvim/.config/nvim/lua/plugins/ui.lua +++ b/nvim/.config/nvim/lua/plugins/ui.lua @@ -56,6 +56,7 @@ return { enabled = true, timeout = 6000, }, + picker = { enabled = true }, quickfile = { enabled = false }, statuscolumn = { enabled = false }, words = { enabled = false },