diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 00000000..3f350df2 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,11 @@ +{ + "MD013": false, + "MD012": false, + "MD028": false, + "MD033": false, + "MD034": false, + "MD036": false, + "MD024": false, + "MD041": false, + "MD060": false +} diff --git a/README.md b/README.md index 54386c8e..6f88813b 100644 --- a/README.md +++ b/README.md @@ -1 +1,240 @@ -This was forked from kickstart.nvim initially and all praise to this amazing project for being an amazing starting point +# Neovim Configuration + +This is my personal Neovim configuration, originally forked from [kickstart.nvim](https://github.com/nvim-lua/kickstart.nvim) and expanded into a Windows-first setup. It uses [lazy.nvim](https://github.com/folke/lazy.nvim) for plugin management and is aimed at Unreal Engine and game-development workflows, especially C++ and Python. It also supports general-purpose development in Lua, TypeScript, CSS, and HTML. + +## Managing Plugins + +### Adding a plugin + +Create a new file in `lua/plugins/` that returns a lazy.nvim plugin spec table. Those plugin specs are loaded through `lua/setup/lazy.lua`, so keeping each plugin in its own file is the intended workflow. + +### Removing a plugin + +Delete the plugin file in `lua/plugins/`, empty it, or remove the plugin spec you no longer want. If you want to keep the file around, you can also disable the plugin in place. + +### Disabling a plugin temporarily + +Add `enabled = false` to the plugin spec table. + +```lua +return { + 'plugin/name', + enabled = false, + -- other options... +} +``` + +### Machine-specific paths + +Copy `machine.json.template` to `machine.json` (it is gitignored), then fill in the machine-specific paths for `basedpyright`, `clangd`, and optionally `ue_python`. + +## Keybinds + +Leader key: `` + +### Navigation + +| Key | Mode | Action | +| ------------- | ---- | ---------------------------------------- | +| `\` | n | Open file tree (Neo-tree) | +| `` | n | Move to left split | +| `` | n | Move to lower split | +| `` | n | Move to upper split | +| `` | n | Move to right split | +| `` | n | Resize split left | +| `` | n | Resize split down | +| `` | n | Resize split up | +| `` | n | Resize split right | +| `` | n | Scroll half-page down (centered) | +| `` | n | Scroll half-page up (centered) | +| `n` / `N` | n | Next/prev search result (centered) | +| `]b` / `[b` | n | Next/prev buffer | +| `]d` / `[d` | n | Next/prev diagnostic | +| `]c` / `[c` | n | Next/prev git hunk (in git buffers) | +| `]q` / `[q` | n | Next/prev quickfix item | +| `j` / `k` | n | Move by visual lines when no count given | +| `` | i | Move cursor in insert mode | +| `J` / `K` | v | Move selected lines down/up | + +### Search (Telescope) + +| Key | Action | +| ------------------ | ------------------------------ | +| `sf` | Find files | +| `sg` | Live grep | +| `sw` | Search current word | +| `sd` | Search diagnostics | +| `sh` | Search help tags | +| `sk` | Search keymaps | +| `ss` | Select Telescope picker | +| `sr` | Resume last search | +| `s.` | Recent files | +| `` | Find open buffers | +| `/` | Fuzzy search in current buffer | +| `s/` | Grep in open files | +| `sn` | Search Neovim config files | + +### LSP + +| Key | Action | +| ------------ | ------------------------------------------------------ | +| `grd` | Go to definition (Telescope) | +| `grD` | Go to declaration | +| `grr` | Go to references (Telescope) | +| `gri` | Go to implementation (Telescope) | +| `grt` | Go to type definition (Telescope) | +| `gd` | Go to definition (native) | +| `gO` | Document symbols | +| `gW` | Workspace symbols | +| `K` | Hover documentation | +| `grn` | Rename symbol | +| `n` | Rename symbol | +| `gra` | Code action (n/x) | +| `lh` | Toggle inlay hints (per buffer) | +| `ld` | Toggle diagnostic mode (all lines ↔ current line only) | +| `li` | Toggle inlay hints (global) | +| `q` | Send diagnostics to quickfix list | +| `pi` | Organize imports (Python/basedpyright) | + +### Git + +| Key | Action | +| ------------ | ------------------------- | +| `gs` | Git status (fugitive) | +| `gd` | Git diff split | +| `gb` | Git blame (fugitive) | +| `gl` | Git log | +| `gp` | Git push | +| `hs` | Stage hunk (n/v) | +| `hr` | Reset hunk (n/v) | +| `hS` | Stage buffer | +| `hu` | Undo stage hunk | +| `hR` | Reset buffer | +| `hp` | Preview hunk (popup) | +| `hP` | Preview hunk inline | +| `hb` | Blame line | +| `hd` | Diff against index | +| `hD` | Diff against last commit | +| `tb` | Toggle line blame | +| `tD` | Toggle show deleted lines | +| `tw` | Toggle word diff | + +### Debug (DAP) + +| Key | Action | +| ----------- | -------------------------- | +| `` | Start / Continue | +| `` | Step into | +| `` | Step over | +| `` | Step out | +| `` | Toggle DAP UI | +| `b` | Toggle breakpoint | +| `B` | Set conditional breakpoint | + +### Build (CMake) + +| Key | Action | +| ------------- | -------------- | +| `cmg` | CMake Generate | +| `cmb` | CMake Build | +| `cmr` | CMake Run | +| `cmd` | CMake Debug | +| `cms` | CMake Stop | + +### AI + +| Key | Action | +| ------------ | --------------------------- | +| `cc` | CodeCompanion Chat toggle | +| `ca` | CodeCompanion Actions (n/v) | +| `cd` | Generate docstring (visual) | + +### Toggles & Utilities + +| Key | Action | +| ---------------- | -------------------------------------- | +| `` | Toggle terminal (float) | +| `tf` | Toggle floating terminal | +| `th` | Toggle horizontal terminal | +| `` | Clear search highlight | +| `` | Clear search highlight | +| `jk` | Escape (n/v/i/t) | +| `p` | Paste over selection (v, no overwrite) | +| `d` | Delete to black hole (n/v) | + +### Commands (no keybind, but worth knowing) + +| Command | Action | +| --------------------------------- | ---------------------------------- | +| `:LspRestart ` | Restart a named LSP server | +| `:LspInfo` | Show comprehensive LSP info | +| `:LspStatus` | Show LSP clients on current buffer | +| `:LspCapabilities` | Show LSP capabilities | +| `:LspDiagnostics` | Show diagnostic counts | +| `:Unreal` | Manually initialize Unreal-Nvim | +| `:LspPyrightOrganizeImports` | Organize Python imports | +| `:LspPyrightSetPythonPath ` | Set Python interpreter path | + +## Unreal Engine + +### Auto-initialization + +Unreal-Nvim auto-initializes when opening: + +- `*.uproject`, `*.uplugin`, `*.Build.cs`, `*.Target.cs` +- C/C++ files (`*.cpp`, `*.h`, `*.hpp`, `*.c`) when the cwd contains a `.uproject` +- New C/C++ files created inside a UE project cwd + +If auto-init does not trigger, run `:Unreal` manually. + +### C++ Workflow + +- Open Neovim from the Unreal project root so `clangd` picks up `compile_commands.json` or `compile_flags.txt` +- Use `CMakeGenerate` / `CMakeBuild` (`cmg`, `cmb`) or UBT directly +- Debugging uses the `codelldb` adapter via DAP (`` to start, `b` for breakpoints) +- `clangd` provides completion, hover, and go-to-definition for UE C++ headers +- You can set a machine-specific `clangd` binary path in `machine.json` under the `clangd` key + +### Python (Editor Scripting) + +- Open Neovim from the Unreal project root so Python stub detection works correctly +- `basedpyright` picks up `Intermediate/PythonStub` automatically when Unreal-Nvim is initialized +- Plugin Python paths (`Plugins/*/Content/Python`) are added to `extraPaths` automatically +- Set the UE Python interpreter in `machine.json` under the `ue_python` key +- Use `pi` to organize imports +- Python debugging uses `debugpy` via DAP (``) + +## Troubleshooting + +### LSP not starting + +- Run `:LspInfo` to check whether a client is attached +- Ensure the language server binary is on `PATH` or configured in `machine.json` +- Run `:LspRestart ` to force-restart a specific server + +### Plugins not loading + +- Run `:Lazy` to open the plugin manager UI +- Check `:Lazy log` for errors +- Run `:Lazy sync` to update all plugins + +### machine.json missing + +- Copy `machine.json.template` to `machine.json` and fill in the required paths +- Without it, LSP servers fall back to binaries on `PATH`, which may or may not work on your system + +### Python debugging fails on first launch + +- On first run, Mason installs `debugpy` in the background; Python DAP is wired automatically once installation completes +- If it still fails, restart Neovim and try again + +### Unreal LSP/Python not working + +- Ensure Neovim is opened from the Unreal project root (the directory containing the `.uproject`) +- Run `:Unreal` to manually trigger Unreal-Nvim initialization +- Check that `ue_python` is set in `machine.json` for the correct UE Python interpreter + +### Clangd not finding headers + +- Ensure a `compile_commands.json` or `compile_flags.txt` exists in the project root (generated by CMake or UBT) +- Set the `clangd` path in `machine.json` if you use a custom LLVM build diff --git a/doc/kickstart.txt b/doc/kickstart.txt deleted file mode 100644 index cb87ac3f..00000000 --- a/doc/kickstart.txt +++ /dev/null @@ -1,24 +0,0 @@ -================================================================================ -INTRODUCTION *kickstart.nvim* - -Kickstart.nvim is a project to help you get started on your neovim journey. - - *kickstart-is-not* -It is not: -- Complete framework for every plugin under the sun -- Place to add every plugin that could ever be useful - - *kickstart-is* -It is: -- Somewhere that has a good start for the most common "IDE" type features: - - autocompletion - - goto-definition - - find references - - fuzzy finding - - and hinting at what more can be done :) -- A place to _kickstart_ your journey. - - You should fork this project and use/modify it so that it matches your - style and preferences. If you don't want to do that, there are probably - other projects that would fit much better for you (and that's great!)! - - vim:tw=78:ts=8:ft=help:norl: diff --git a/doc/tags b/doc/tags deleted file mode 100644 index 687ae772..00000000 --- a/doc/tags +++ /dev/null @@ -1,3 +0,0 @@ -kickstart-is kickstart.txt /*kickstart-is* -kickstart-is-not kickstart.txt /*kickstart-is-not* -kickstart.nvim kickstart.txt /*kickstart.nvim* diff --git a/lazy-lock.json b/lazy-lock.json index 1c88a73e..df7df4e4 100644 --- a/lazy-lock.json +++ b/lazy-lock.json @@ -2,11 +2,12 @@ "CopilotChat.nvim": { "branch": "main", "commit": "9fec6c3c2a4069b1f649e116c10e6fbcf1463764" }, "LuaSnip": { "branch": "master", "commit": "5a1e39223db9a0498024a77b8441169d260c8c25" }, "Unreal-Nvim": { "branch": "main", "commit": "b0991bbd83645717cc0b3c98dd1fbf6ee7684c25" }, + "blink-cmp-copilot": { "branch": "main", "commit": "439cff78780c033aa23cf061d7315314b347e3c1" }, "blink.cmp": { "branch": "main", "commit": "451168851e8e2466bc97ee3e026c3dcb9141ce07" }, "cmake-tools.nvim": { "branch": "master", "commit": "906fd4816bf4d588162d5ec78830456f0d969c5f" }, "codecompanion.nvim": { "branch": "main", "commit": "78203ccaa36469b4a212123c7d532e2367ad9dd4" }, "conform.nvim": { "branch": "master", "commit": "086a40dc7ed8242c03be9f47fbcee68699cc2395" }, - "copilot.vim": { "branch": "release", "commit": "a12fd5672110c8aa7e3c8419e28c96943ca179be" }, + "copilot.lua": { "branch": "master", "commit": "e8b9be2e51c393bedc893cef3bd1c5555a4d45f5" }, "diffview.nvim": { "branch": "main", "commit": "4516612fe98ff56ae0415a259ff6361a89419b0a" }, "fidget.nvim": { "branch": "main", "commit": "7fa433a83118a70fe24c1ce88d5f0bd3453c0970" }, "friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" }, @@ -27,7 +28,6 @@ "nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" }, "nvim-autopairs": { "branch": "master", "commit": "59bce2eef357189c3305e25bc6dd2d138c1683f5" }, "nvim-dap": { "branch": "master", "commit": "2a8799ad91a1495c6bdf753f9b2179b3ff0f5bba" }, - "nvim-dap-go": { "branch": "main", "commit": "b4421153ead5d726603b02743ea40cf26a51ed5f" }, "nvim-dap-python": { "branch": "master", "commit": "1808458eba2b18f178f990e01376941a42c7f93b" }, "nvim-dap-ui": { "branch": "master", "commit": "f5b6673f374626515401c5bc51b005f784a4f252" }, "nvim-dap-virtual-text": { "branch": "master", "commit": "fbdb48c2ed45f4a8293d0d483f7730d24467ccb6" }, diff --git a/lsp/basedpyright.lua b/lsp/basedpyright.lua index b8cb037f..578c163f 100644 --- a/lsp/basedpyright.lua +++ b/lsp/basedpyright.lua @@ -1,24 +1,38 @@ +local machine = require('machine') + local function set_python_path(path) local clients = vim.lsp.get_clients { bufnr = vim.api.nvim_get_current_buf(), name = 'basedpyright', } for _, client in ipairs(clients) do + client.config.settings = vim.tbl_deep_extend('force', client.config.settings or {}, { python = { pythonPath = path } }) if client.settings then client.settings.python = vim.tbl_deep_extend('force', client.settings.python or {}, { pythonPath = path }) - else - client.config.settings = vim.tbl_deep_extend('force', client.config.settings, { python = { pythonPath = path } }) end - client.notify('workspace/didChangeConfiguration', { settings = nil }) + client.notify('workspace/didChangeConfiguration', { settings = client.config.settings }) end end +local function is_ue_project() + local ok, unreal_nvim = pcall(require, 'unreal-nvim') + if ok and unreal_nvim.find_uproject and unreal_nvim.find_uproject() then + return true + end + return vim.fn.glob(vim.fn.getcwd() .. '/*.uproject') ~= '' +end + local function get_python_path() local venv_path = os.getenv 'VIRTUAL_ENV' if venv_path then return venv_path .. '/scripts/python.exe' end - return 'C:/Program Files/Epic Games/UE_5.7/Engine/Binaries/ThirdParty/Python3/Win64/python.exe' + if is_ue_project() then + local ue_python = machine.get('ue_python', nil) + if ue_python then return ue_python end + end + local python_on_path = vim.fn.exepath('python') + return python_on_path ~= '' and python_on_path or 'python' end local function get_current_ue_python_stub() @@ -40,13 +54,14 @@ local function get_ue_python_plugins() if ue_project then local ue_folder = ue_project:match '^(.*[\\/])' local ue_plugins = ue_folder .. 'Plugins\\' - local handle = vim.loop.fs_scandir(ue_plugins) + local handle = vim.uv.fs_scandir(ue_plugins) + if not handle then return folders end while true do - local name, t = vim.loop.fs_scandir_next(handle) + local name, t = vim.uv.fs_scandir_next(handle) if not name then break end if t == 'directory' then local plugin_folder = ue_plugins .. name .. '\\Content\\Python' - local stat = vim.loop.fs_stat(plugin_folder) + local stat = vim.uv.fs_stat(plugin_folder) if stat ~= nil and stat.type == 'directory' then table.insert(folders, plugin_folder) end @@ -67,7 +82,7 @@ local function get_extra_paths() end return { - cmd = { 'D:\\language-servers\\basedpyright\\Scripts\\basedpyright-langserver.exe', '--stdio' }, + cmd = { machine.get('basedpyright', vim.fn.exepath('basedpyright-langserver')), '--stdio' }, filetypes = { 'python' }, root_markers = { 'pyproject.toml', @@ -95,7 +110,7 @@ return { autoImportCompletions = true, autoSearchPaths = true, useLibraryCodeForTypes = true, - diagnosticMode = 'workspace', + diagnosticMode = 'openFilesOnly', extraPaths = get_extra_paths(), }, }, @@ -109,10 +124,14 @@ return { } end, { desc = 'Organize Imports' }) - vim.api.nvim_buf_create_user_command(bufnr, 'LspPyrightSetPythonPath', set_python_path, { + vim.api.nvim_buf_create_user_command(bufnr, 'LspPyrightSetPythonPath', function(opts) + set_python_path(opts.args) + end, { desc = 'Reconfigure basedpyright with the provided python path', nargs = 1, complete = 'file', }) + + vim.keymap.set('n', 'pi', 'LspPyrightOrganizeImports', { buffer = bufnr, desc = '[P]ython Organize [I]mports' }) end, } diff --git a/lsp/clangd.lua b/lsp/clangd.lua index 895cabd8..e38bc955 100644 --- a/lsp/clangd.lua +++ b/lsp/clangd.lua @@ -1,3 +1,5 @@ +local machine = require('machine') + local function switch_source_header(bufnr) local method_name = 'textDocument/switchSourceHeader' local client = vim.lsp.get_clients({ bufnr = bufnr, name = 'clangd' })[1] @@ -7,7 +9,8 @@ local function switch_source_header(bufnr) local params = vim.lsp.util.make_text_document_params(bufnr) client.request(method_name, params, function(err, result) if err then - error(tostring(err)) + vim.notify(tostring(err), vim.log.levels.ERROR) + return end if not result then vim.notify 'corresponding file cannot be determined' @@ -26,7 +29,7 @@ local function symbol_info() local win = vim.api.nvim_get_current_win() local params = vim.lsp.util.make_position_params(win, clangd_client.offset_encoding) clangd_client.request('textDocument/symbolInfo', params, function(err, res) - if err or #res == 0 then + if err or not res or #res == 0 then -- Clangd always returns an error, there is not reason to parse it return end @@ -47,7 +50,7 @@ end ---@field offsetEncoding? string return { - cmd = { 'D:\\language-servers\\clangd\\bin\\clangd.exe' }, + cmd = { machine.get('clangd', vim.fn.exepath('clangd')) }, filetypes = { 'c', 'cpp', 'objc', 'objcpp', 'cuda' }, root_markers = { '.clangd', @@ -81,5 +84,9 @@ return { vim.api.nvim_buf_create_user_command(bufnr, 'LspClangdShowSymbolInfo', function() symbol_info() end, { desc = 'Show symbol info' }) + + vim.keymap.set('n', 'ch', function() + switch_source_header(bufnr) + end, { buffer = bufnr, desc = '[C]langd Switch [H]eader/Source' }) end, } diff --git a/lsp/ty.lua b/lsp/ty.lua deleted file mode 100644 index 4c7d0f71..00000000 --- a/lsp/ty.lua +++ /dev/null @@ -1,17 +0,0 @@ --- Get virtual env if active otherwise get the unreal python -local function get_python_path() - local venv_path = os.getenv 'VIRTUAL_ENV' - if venv_path then - return venv_path .. '/scripts/python.exe' - end - return 'C:\\Program Files\\Epic Games\\UE_5.6.0\\Engine\\Binaries\\ThirdParty\\Python3\\Win64\\python.exe' -end - -return { - cmd = { 'D:\\language-servers\\tylsp\\Scripts\\ty', 'server' }, - filetypes = { 'python' }, - root_markers = { 'ty.toml', 'pyproject.toml', '.git' }, - environment = { - python = get_python_path(), - }, -} diff --git a/lsp/typos_lsp.lua b/lsp/typos_lsp.lua deleted file mode 100644 index ad244ddf..00000000 --- a/lsp/typos_lsp.lua +++ /dev/null @@ -1,5 +0,0 @@ -return { - cmd = { 'C:/user_data/language-servers/typos/extension/bundled/typos-lsp.exe' }, - cmd_env = { RUST_LOG = 'error' }, - root_markers = { 'typos.toml', '_typos.toml', '.typos.toml', 'pyproject.toml', 'Cargo.toml' }, -} diff --git a/lua/machine.lua b/lua/machine.lua new file mode 100644 index 00000000..e224a8b6 --- /dev/null +++ b/lua/machine.lua @@ -0,0 +1,30 @@ +-- machine.lua +-- Loads machine-specific paths from machine.json in the config directory. +-- Copy machine.json.template to machine.json and fill in your paths. +local M = {} + +local _cache = nil + +local function load() + local path = vim.fn.stdpath('config') .. '/machine.json' + local f = io.open(path, 'r') + if not f then return {} end + local content = f:read('*a') + f:close() + local ok, data = pcall(vim.fn.json_decode, content) + return (ok and type(data) == 'table') and data or {} +end + +--- Get a machine-specific path by key. +--- Falls back to `fallback` if the key is missing or empty. +---@param key string +---@param fallback string|nil +---@return string|nil +function M.get(key, fallback) + if not _cache then _cache = load() end + local val = _cache[key] + if val and val ~= '' then return val end + return fallback +end + +return M diff --git a/lua/plugins/blink.lua b/lua/plugins/blink.lua index 5ab45486..d11466b9 100644 --- a/lua/plugins/blink.lua +++ b/lua/plugins/blink.lua @@ -23,6 +23,8 @@ return { opts = {}, }, 'folke/lazydev.nvim', + 'zbirenbaum/copilot.lua', + 'giuxtaposition/blink-cmp-copilot', }, opts = { -- 'default' (recommended) for mappings similar to built-in completions (C-y to accept) @@ -38,9 +40,10 @@ return { documentation = { auto_show = false, auto_show_delay_ms = 200 }, }, sources = { - default = { 'lsp', 'path', 'snippets', 'lazydev', 'buffer' }, + default = { 'lsp', 'path', 'snippets', 'lazydev', 'buffer', 'copilot' }, providers = { lazydev = { module = 'lazydev.integrations.blink', score_offset = 100 }, + copilot = { module = 'blink-cmp-copilot', score_offset = 100, async = true }, }, }, snippets = { preset = 'luasnip' }, diff --git a/lua/plugins/cmake-tools.lua b/lua/plugins/cmake-tools.lua index 527190c0..650d3050 100644 --- a/lua/plugins/cmake-tools.lua +++ b/lua/plugins/cmake-tools.lua @@ -2,5 +2,12 @@ return { 'Civitasv/cmake-tools.nvim', dependencies = { 'nvim-lua/plenary.nvim' }, ft = { 'c', 'cpp' }, + keys = { + { 'cmg', 'CMakeGenerate', desc = '[C]Make [G]enerate' }, + { 'cmb', 'CMakeBuild', desc = '[C]Make [B]uild' }, + { 'cmr', 'CMakeRun', desc = '[C]Make [R]un' }, + { 'cmd', 'CMakeDebug', desc = '[C]Make [D]ebug' }, + { 'cms', 'CMakeStop', desc = '[C]Make [S]top' }, + }, opts = {}, } diff --git a/lua/plugins/conform.lua b/lua/plugins/conform.lua index 3fedfa70..275f3a19 100644 --- a/lua/plugins/conform.lua +++ b/lua/plugins/conform.lua @@ -29,7 +29,7 @@ return { lua = { 'stylua' }, c = { 'clang_format' }, cpp = { 'clang_format' }, - python = { 'isort', 'black' }, + python = { 'ruff_format', 'ruff_organize_imports' }, javascript = { 'prettier' }, typescript = { 'prettier' }, javascriptreact = { 'prettier' }, @@ -37,6 +37,7 @@ return { json = { 'prettier' }, html = { 'prettier' }, css = { 'prettier' }, + markdown = { 'prettier' }, }, }, } diff --git a/lua/plugins/copilot-chat.lua b/lua/plugins/copilot-chat.lua index 16e49477..0be736bf 100644 --- a/lua/plugins/copilot-chat.lua +++ b/lua/plugins/copilot-chat.lua @@ -1,7 +1,8 @@ return { 'CopilotC-Nvim/CopilotChat.nvim', + cmd = { 'CopilotChat', 'CopilotChatToggle', 'CopilotChatOpen' }, dependencies = { - 'github/copilot.vim', + 'zbirenbaum/copilot.lua', 'nvim-lua/plenary.nvim', }, opts = { diff --git a/lua/plugins/copilot.lua b/lua/plugins/copilot.lua index 7809aab9..ce6cd954 100644 --- a/lua/plugins/copilot.lua +++ b/lua/plugins/copilot.lua @@ -1,4 +1,10 @@ return { - 'github/copilot.vim', - event = 'InsertEnter', + { + 'zbirenbaum/copilot.lua', + event = 'InsertEnter', + opts = { + suggestion = { enabled = false }, -- handled by blink.cmp + panel = { enabled = false }, + }, + }, } diff --git a/lua/plugins/debug.lua b/lua/plugins/debug.lua index 1e2c9225..af802d77 100644 --- a/lua/plugins/debug.lua +++ b/lua/plugins/debug.lua @@ -22,7 +22,6 @@ return { 'jay-babu/mason-nvim-dap.nvim', -- Add your own debuggers here - 'leoluz/nvim-dap-go', 'theHamsta/nvim-dap-virtual-text', 'mfussenegger/nvim-dap-python', }, @@ -96,10 +95,41 @@ return { -- online, please don't ask me how to install them :) ensure_installed = { -- Update this to ensure that you have the debuggers for the langs you want - 'delve', + 'codelldb', -- C/C++/Unreal Engine debugging + 'debugpy', -- Python debugging }, } + -- Configure Python debugger using Mason-installed debugpy + local function setup_dap_python() + local ok2, reg = pcall(require, 'mason-registry') + if not ok2 then return end + if not reg.is_installed('debugpy') then return end + local debugpy_path = reg.get_package('debugpy'):get_install_path() + -- Windows uses Scripts/, Unix uses bin/ + local python_exec = debugpy_path .. '/venv/Scripts/python.exe' + if vim.fn.filereadable(python_exec) == 0 then + python_exec = debugpy_path .. '/venv/bin/python' + end + require('dap-python').setup(python_exec) + end + + -- Configure immediately if already installed + setup_dap_python() + + -- Also configure when debugpy finishes installing on first run + local ok_reg, reg2 = pcall(require, 'mason-registry') + if ok_reg then + reg2:on('package:install:success', function(pkg) + if pkg.name == 'debugpy' then + vim.schedule(setup_dap_python) + end + end) + end + + -- Configure virtual text for DAP + require('nvim-dap-virtual-text').setup() + -- Dap UI setup -- For more information, see |:help nvim-dap-ui| dapui.setup { @@ -138,13 +168,5 @@ return { dap.listeners.before.event_terminated['dapui_config'] = dapui.close dap.listeners.before.event_exited['dapui_config'] = dapui.close - -- Install golang specific config - require('dap-go').setup { - delve = { - -- On Windows delve must be run attached or it crashes. - -- See https://github.com/leoluz/nvim-dap-go/blob/main/README.md#configuring - detached = vim.fn.has 'win32' == 0, - }, - } end, } diff --git a/lua/plugins/gitsigns.lua b/lua/plugins/gitsigns.lua index cbbd22d2..ca9b055c 100644 --- a/lua/plugins/gitsigns.lua +++ b/lua/plugins/gitsigns.lua @@ -44,9 +44,10 @@ return { map('n', 'hs', gitsigns.stage_hunk, { desc = 'git [s]tage hunk' }) map('n', 'hr', gitsigns.reset_hunk, { desc = 'git [r]eset hunk' }) map('n', 'hS', gitsigns.stage_buffer, { desc = 'git [S]tage buffer' }) - map('n', 'hu', gitsigns.stage_hunk, { desc = 'git [u]ndo stage hunk' }) + map('n', 'hu', gitsigns.undo_stage_hunk, { desc = 'git [u]ndo stage hunk' }) map('n', 'hR', gitsigns.reset_buffer, { desc = 'git [R]eset buffer' }) map('n', 'hp', gitsigns.preview_hunk, { desc = 'git [p]review hunk' }) + map('n', 'hP', gitsigns.preview_hunk_inline, { desc = 'git [P]review hunk inline' }) map('n', 'hb', gitsigns.blame_line, { desc = 'git [b]lame line' }) map('n', 'hd', gitsigns.diffthis, { desc = 'git [d]iff against index' }) map('n', 'hD', function() @@ -54,7 +55,8 @@ return { end, { desc = 'git [D]iff against last commit' }) -- Toggles map('n', 'tb', gitsigns.toggle_current_line_blame, { desc = '[T]oggle git show [b]lame line' }) - map('n', 'tD', gitsigns.preview_hunk_inline, { desc = '[T]oggle git show [D]eleted' }) + map('n', 'tD', gitsigns.toggle_deleted, { desc = '[T]oggle git show [D]eleted' }) + map('n', 'tw', gitsigns.toggle_word_diff, { desc = '[T]oggle git [W]ord diff' }) end, }, }, diff --git a/lua/plugins/lint.lua b/lua/plugins/lint.lua index dec42f09..ecdf36f4 100644 --- a/lua/plugins/lint.lua +++ b/lua/plugins/lint.lua @@ -7,6 +7,7 @@ return { local lint = require 'lint' lint.linters_by_ft = { markdown = { 'markdownlint' }, + python = { 'ruff' }, } -- To allow other plugins to add linters to require('lint').linters_by_ft, diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua index 34e1a13f..e2c8e9bf 100644 --- a/lua/plugins/lsp.lua +++ b/lua/plugins/lsp.lua @@ -11,6 +11,8 @@ return { capabilities = require('blink.cmp').get_lsp_capabilities(), }) + local detach_augroup = vim.api.nvim_create_augroup('kickstart-lsp-detach', { clear = true }) + -- LspAttach: keymaps only. Server setup is handled by vim.lsp.enable in setup/lsp.lua vim.api.nvim_create_autocmd('LspAttach', { group = vim.api.nvim_create_augroup('kickstart-lsp-attach', { clear = true }), @@ -22,13 +24,16 @@ return { map('grn', vim.lsp.buf.rename, '[R]e[n]ame') map('gra', vim.lsp.buf.code_action, '[G]oto Code [A]ction', { 'n', 'x' }) - map('grr', require('telescope.builtin').lsp_references, '[G]oto [R]eferences') - map('gri', require('telescope.builtin').lsp_implementations, '[G]oto [I]mplementation') - map('grd', require('telescope.builtin').lsp_definitions, '[G]oto [D]efinition') + map('grr', function() require('telescope.builtin').lsp_references() end, '[G]oto [R]eferences') + map('gri', function() require('telescope.builtin').lsp_implementations() end, '[G]oto [I]mplementation') + map('grd', function() require('telescope.builtin').lsp_definitions() end, '[G]oto [D]efinition') map('grD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') - map('gO', require('telescope.builtin').lsp_document_symbols, 'Open Document Symbols') - map('gW', require('telescope.builtin').lsp_dynamic_workspace_symbols, 'Open Workspace Symbols') - map('grt', require('telescope.builtin').lsp_type_definitions, '[G]oto [T]ype Definition') + map('gO', function() require('telescope.builtin').lsp_document_symbols() end, 'Open Document Symbols') + map('gW', function() require('telescope.builtin').lsp_dynamic_workspace_symbols() end, 'Open Workspace Symbols') + map('grt', function() require('telescope.builtin').lsp_type_definitions() end, '[G]oto [T]ype Definition') + map('gd', vim.lsp.buf.definition, '[G]oto [D]efinition') + map('K', vim.lsp.buf.hover, 'Hover Documentation') + map('n', vim.lsp.buf.rename, '[R]e[n]ame') local function client_supports_method(client, method, bufnr) if vim.fn.has 'nvim-0.11' == 1 then @@ -47,13 +52,14 @@ return { group = hl_group, callback = vim.lsp.buf.document_highlight, }) - -- vim.api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI' }, { - -- buffer = event.buf, - -- group = hl_group, - -- callback = vim.lsp.buf.clear_references, - -- }) + vim.api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI' }, { + buffer = event.buf, + group = hl_group, + callback = vim.lsp.buf.clear_references, + }) vim.api.nvim_create_autocmd('LspDetach', { - group = vim.api.nvim_create_augroup('kickstart-lsp-detach', { clear = true }), + group = detach_augroup, + buffer = event.buf, callback = function(event2) vim.lsp.buf.clear_references() vim.api.nvim_clear_autocmds { group = 'kickstart-lsp-highlight', buffer = event2.buf } @@ -62,9 +68,9 @@ return { end if client and client_supports_method(client, vim.lsp.protocol.Methods.textDocument_inlayHint, event.buf) then - map('th', function() + map('lh', function() vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled { bufnr = event.buf }) - end, '[T]oggle Inlay [H]ints') + end, '[L]SP Toggle Inlay [H]ints') end end, }) diff --git a/lua/plugins/lualine.lua b/lua/plugins/lualine.lua index bcb64fa0..5b3e4acd 100644 --- a/lua/plugins/lualine.lua +++ b/lua/plugins/lualine.lua @@ -4,7 +4,7 @@ return { -- See `:help lualine.txt` opts = { options = { - icons_enabled = false, + icons_enabled = true, theme = 'gruvbox', component_separators = '|', section_separators = '', diff --git a/lua/plugins/mason.lua b/lua/plugins/mason.lua index d661444e..54768c9b 100644 --- a/lua/plugins/mason.lua +++ b/lua/plugins/mason.lua @@ -28,8 +28,9 @@ return { -- Formatters / linters 'stylua', 'prettier', - 'black', - 'isort', + 'ruff', + 'clang-format', + 'markdownlint', }, } end, diff --git a/lua/plugins/snacks.lua b/lua/plugins/snacks.lua index 072d91e7..3885db58 100644 --- a/lua/plugins/snacks.lua +++ b/lua/plugins/snacks.lua @@ -17,8 +17,8 @@ return { picker = { enabled = true }, quickfile = { enabled = true }, scope = { enabled = true }, - -- scroll = { enabled = true }, - words = { enabled = false }, + scroll = { enabled = false }, + words = { enabled = true }, -- image = { -- enabled = true, -- resolve = function(path, src) diff --git a/lua/plugins/telescope-fuzzy-finder.lua b/lua/plugins/telescope-fuzzy-finder.lua index 1c2ffba9..2137f740 100644 --- a/lua/plugins/telescope-fuzzy-finder.lua +++ b/lua/plugins/telescope-fuzzy-finder.lua @@ -1,6 +1,6 @@ return { 'nvim-telescope/telescope.nvim', - -- event = 'VimEnter', + cmd = { 'Telescope' }, dependencies = { 'nvim-lua/plenary.nvim', { @@ -13,6 +13,45 @@ return { { 'nvim-telescope/telescope-ui-select.nvim' }, { 'nvim-tree/nvim-web-devicons', enabled = vim.g.have_nerd_font }, }, + keys = { + { 'sh', function() require('telescope.builtin').help_tags() end, desc = '[S]earch [H]elp' }, + { 'sk', function() require('telescope.builtin').keymaps() end, desc = '[S]earch [K]eymaps' }, + { 'sf', function() require('telescope.builtin').find_files() end, desc = '[S]earch [F]iles' }, + { 'ss', function() require('telescope.builtin').builtin() end, desc = '[S]earch [S]elect Telescope' }, + { 'sw', function() require('telescope.builtin').grep_string() end, desc = '[S]earch current [W]ord' }, + { 'sg', function() require('telescope.builtin').live_grep() end, desc = '[S]earch by [G]rep' }, + { 'sd', function() require('telescope.builtin').diagnostics() end, desc = '[S]earch [D]iagnostics' }, + { 'sr', function() require('telescope.builtin').resume() end, desc = '[S]earch [R]esume' }, + { 's.', function() require('telescope.builtin').oldfiles() end, desc = '[S]earch Recent Files' }, + { '', function() require('telescope.builtin').buffers() end, desc = '[ ] Find buffers' }, + { + '/', + function() + require('telescope.builtin').current_buffer_fuzzy_find(require('telescope.themes').get_dropdown { + winblend = 10, + previewer = false, + }) + end, + desc = '[/] Search in current buffer', + }, + { + 's/', + function() + require('telescope.builtin').live_grep { + grep_open_files = true, + prompt_title = 'Live Grep in Open Files', + } + end, + desc = '[S]earch [/] in Open Files', + }, + { + 'sn', + function() + require('telescope.builtin').find_files { cwd = vim.fn.stdpath 'config' } + end, + desc = '[S]earch [N]eovim files', + }, + }, config = function() require('telescope').setup { extensions = { @@ -24,35 +63,5 @@ return { pcall(require('telescope').load_extension, 'fzf') pcall(require('telescope').load_extension, 'ui-select') - - local builtin = require 'telescope.builtin' - vim.keymap.set('n', 'sh', builtin.help_tags, { desc = '[S]earch [H]elp' }) - vim.keymap.set('n', 'sk', builtin.keymaps, { desc = '[S]earch [K]eymaps' }) - vim.keymap.set('n', 'sf', builtin.find_files, { desc = '[S]earch [F]iles' }) - vim.keymap.set('n', 'ss', builtin.builtin, { desc = '[S]earch [S]elect Telescope' }) - vim.keymap.set('n', 'sw', builtin.grep_string, { desc = '[S]earch current [W]ord' }) - vim.keymap.set('n', 'sg', builtin.live_grep, { desc = '[S]earch by [G]rep' }) - vim.keymap.set('n', 'sd', builtin.diagnostics, { desc = '[S]earch [D]iagnostics' }) - vim.keymap.set('n', 'sr', builtin.resume, { desc = '[S]earch [R]esume' }) - vim.keymap.set('n', 's.', builtin.oldfiles, { desc = '[S]earch Recent Files' }) - vim.keymap.set('n', '', builtin.buffers, { desc = '[ ] Find buffers' }) - - vim.keymap.set('n', '/', function() - builtin.current_buffer_fuzzy_find(require('telescope.themes').get_dropdown { - winblend = 10, - previewer = false, - }) - end, { desc = '[/] Search in current buffer' }) - - vim.keymap.set('n', 's/', function() - builtin.live_grep { - grep_open_files = true, - prompt_title = 'Live Grep in Open Files', - } - end, { desc = '[S]earch [/] in Open Files' }) - - vim.keymap.set('n', 'sn', function() - builtin.find_files { cwd = vim.fn.stdpath 'config' } - end, { desc = '[S]earch [N]eovim files' }) end, } diff --git a/lua/plugins/treesitter.lua b/lua/plugins/treesitter.lua index 0ff4f27c..a7879b26 100644 --- a/lua/plugins/treesitter.lua +++ b/lua/plugins/treesitter.lua @@ -25,6 +25,10 @@ return { 'tsx', 'json', 'css', + 'glsl', + 'cmake', + 'hlsl', + 'ini', }, auto_install = true, highlight = { diff --git a/lua/plugins/unreal.lua b/lua/plugins/unreal.lua index 6fee07d7..122ecf4f 100644 --- a/lua/plugins/unreal.lua +++ b/lua/plugins/unreal.lua @@ -1,15 +1,42 @@ -- Unreal return { 'PlayKigai/Unreal-Nvim', - -- ft = { 'cpp', 'c', 'h', 'hpp', 'cs', 'ini', 'uproject', 'uplugin' }, cmd = { 'Unreal' }, + init = function() + local group = vim.api.nvim_create_augroup('UnrealAutoInit', { clear = true }) + local initialized = false + + local function try_init() + if initialized then return end + initialized = true + vim.api.nvim_del_augroup_by_id(group) + require('lazy').load { plugins = { 'Unreal-Nvim' } } + require('unreal-nvim').setup({}) + end + + -- Auto-init on explicit UE project/plugin/build files + vim.api.nvim_create_autocmd({ 'BufReadPost', 'BufNewFile' }, { + group = group, + pattern = { '*.uproject', '*.uplugin', '*.Build.cs', '*.Target.cs' }, + callback = try_init, + }) + + -- Auto-init on C++ files when a .uproject exists in cwd (UE source code) + vim.api.nvim_create_autocmd({ 'BufReadPost', 'BufNewFile' }, { + group = group, + pattern = { '*.cpp', '*.h', '*.hpp', '*.c' }, + callback = function() + if vim.fn.glob(vim.fn.getcwd() .. '/*.uproject') ~= '' then + try_init() + end + end, + }) + end, config = function() + -- Plugin is set up by try_init() above; this is only reached when + -- loaded manually via :Unreal or by the auto-init path. vim.api.nvim_create_user_command('Unreal', function() - require('unreal-nvim').setup() - end, {}) - -- require('unreal-nvim').setup { - -- engine_path = "C:\\Program Files\\Epic Games\\UE_5.6.1", -- optional - -- auto_register_clangd = true -- if true, tries to auto-configure clangd for Unreal (needs nvim-lspconfig) - -- } + require('unreal-nvim').setup({}) + end, { desc = 'Manually initialize Unreal-Nvim' }) end, } diff --git a/lua/plugins/which-key.lua b/lua/plugins/which-key.lua index d2333cdc..18fcf1e8 100644 --- a/lua/plugins/which-key.lua +++ b/lua/plugins/which-key.lua @@ -1,6 +1,6 @@ return { 'folke/which-key.nvim', - event = 'VimEnter', + event = 'VeryLazy', opts = { delay = 0, icons = { @@ -40,7 +40,14 @@ return { { 's', group = '[S]earch' }, { 't', group = '[T]oggle' }, { 'h', group = 'Git [H]unk', mode = { 'n', 'v' } }, - { 'b', group = '[B]uild ' }, + { 'b', group = '[B]reakpoint' }, + { 'l', group = '[L]SP' }, + { 'g', group = '[G]it' }, + { 'c', group = '[C]ode / C++' }, + { 'd', group = '[D]ebug' }, + { 'r', group = '[R]un' }, + { 'u', group = '[U]nreal' }, + { 'a', group = '[A]I' }, }, }, } diff --git a/lua/setup/autocmds.lua b/lua/setup/autocmds.lua index ec2eb134..c7b1822c 100644 --- a/lua/setup/autocmds.lua +++ b/lua/setup/autocmds.lua @@ -1,106 +1,14 @@ --- Attach LSP -local lsp_attach_group = vim.api.nvim_create_augroup('kickstart-lsp-attach', { clear = true }) -vim.api.nvim_create_autocmd('LspAttach', { - group = lsp_attach_group, - callback = function(event) - local function map(keys, func, desc, mode) - mode = mode or 'n' - vim.keymap.set(mode, keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc }) - end - - -- Key mappings table: {keys, function, description, [mode]} - local mappings = { - { 'grn', vim.lsp.buf.rename, '[R]e[n]ame' }, - { 'gra', vim.lsp.buf.code_action, '[G]oto Code [A]ction', { 'n', 'x' } }, - { - 'grr', - function() - require('telescope.builtin').lsp_references() - end, - '[G]oto [R]eferences', - }, - { - 'gri', - function() - require('telescope.builtin').lsp_implementations() - end, - '[G]oto [I]mplementation', - }, - { - 'grd', - function() - require('telescope.builtin').lsp_definitions() - end, - '[G]oto [D]efinition', - }, - { 'grD', vim.lsp.buf.declaration, '[G]oto [D]eclaration' }, - { - 'gO', - function() - require('telescope.builtin').lsp_document_symbols() - end, - 'Open Document Symbols', - }, - { - 'gW', - function() - require('telescope.builtin').lsp_dynamic_workspace_symbols() - end, - 'Open Workspace Symbols', - }, - { - 'grt', - function() - require('telescope.builtin').lsp_type_definitions() - end, - '[G]oto [T]ype Definition', - }, - { 'gd', vim.lsp.buf.definition, '[G]oto [D]efinition' }, - { 'K', vim.lsp.buf.hover, 'Hover Documentation' }, - { 'ca', vim.lsp.buf.code_action, 'Code [A]ction' }, - { 'n', vim.lsp.buf.rename, '[R]e[n]ame' }, - } - for _, m in ipairs(mappings) do - map(m[1], m[2], m[3], m[4]) - end - - local function client_supports_method(client, method, bufnr) - if vim.fn.has 'nvim-0.11' == 1 then - return client:supports_method(method, bufnr) - else - return client.supports_method(method, { bufnr = bufnr }) - end - end - - local client = vim.lsp.get_client_by_id(event.data.client_id) - if client and client_supports_method(client, vim.lsp.protocol.Methods.textDocument_documentHighlight, event.buf) then - local highlight_augroup = vim.api.nvim_create_augroup('lsp-highlight', { clear = false }) - vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, { - buffer = event.buf, - group = highlight_augroup, - callback = vim.lsp.buf.document_highlight, - }) - vim.api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI' }, { - buffer = event.buf, - group = highlight_augroup, - callback = vim.lsp.buf.clear_references, - }) - vim.api.nvim_create_autocmd('LspDetach', { - group = vim.api.nvim_create_augroup('lsp-detach', { clear = true }), - callback = function(event2) - vim.lsp.buf.clear_references() - vim.api.nvim_clear_autocmds { group = 'lsp-highlight', buffer = event2.buf } - end, - }) - end - - if client and client_supports_method(client, vim.lsp.protocol.Methods.textDocument_inlayHint, event.buf) then - map('th', function() - vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled { bufnr = event.buf }) - end, '[T]oggle Inlay [H]ints') - end - end, -}) +-- Shader file associations +vim.filetype.add { + extension = { + vert = 'glsl', + frag = 'glsl', + geom = 'glsl', + comp = 'glsl', + tesc = 'glsl', + tese = 'glsl', + }, +} -- Highlight on yank vim.api.nvim_create_autocmd('TextYankPost', { @@ -112,15 +20,29 @@ vim.api.nvim_create_autocmd('TextYankPost', { }) -- Load project-local config +local uv = vim.uv or vim.loop + +local function load_project_config() + local config_file = vim.fn.getcwd() .. '/.nvim.lua' + if vim.fn.filereadable(config_file) ~= 1 then + return + end + + local stat = uv.fs_lstat(config_file) + if not (stat and stat.type == 'file') then + return + end + + local ok, err = pcall(dofile, config_file) + if not ok then + vim.notify('Error loading project config: ' .. err, vim.log.levels.WARN) + end +end + vim.api.nvim_create_autocmd('VimEnter', { desc = 'Load project-local .nvim.lua', group = vim.api.nvim_create_augroup('project-local-config', { clear = true }), - callback = function() - local config_file = vim.fn.getcwd() .. '/.nvim.lua' - if vim.fn.filereadable(config_file) == 1 then - dofile(config_file) - end - end, + callback = load_project_config, }) -- Restore cursor to file position in previous editing session diff --git a/lua/setup/keymap.lua b/lua/setup/keymap.lua index e5e1b403..61d51259 100644 --- a/lua/setup/keymap.lua +++ b/lua/setup/keymap.lua @@ -3,7 +3,7 @@ vim.g.maplocalleader = ' ' vim.g.have_nerd_font = true vim.keymap.set('n', '', 'nohlsearch') -vim.keymap.set('n', 'q', vim.diagnostic.setloclist, { desc = 'Open diagnostic [Q]uickfix list' }) +vim.keymap.set('n', 'q', vim.diagnostic.setqflist, { desc = 'Open diagnostic [Q]uickfix list' }) vim.keymap.set('t', '', '', { desc = 'Exit terminal mode' }) -- Disables as a normal/visual key, so it only works as leader @@ -47,12 +47,14 @@ vim.keymap.set({ 'n', 'v' }, 'd', [["_d]]) -- In insert mode, Ctrl+c acts as . vim.keymap.set('i', '', '') --- Format file or selection using LSP with f. -vim.keymap.set('n', 'f', vim.lsp.buf.format) -vim.keymap.set('v', 'f', vim.lsp.buf.format) +-- Diagnostic navigation +vim.keymap.set('n', ']d', vim.diagnostic.goto_next, { desc = 'Next [D]iagnostic' }) +vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, { desc = 'Previous [D]iagnostic' }) --- Replace word under cursor throughout file. -vim.keymap.set('n', 's', [[:%s/\<\>//gI]]) +-- Buffer navigation +vim.keymap.set('n', ']b', 'bnext', { desc = 'Next [B]uffer' }) +vim.keymap.set('n', '[b', 'bprev', { desc = 'Previous [B]uffer' }) --- Open terminal in vertical split. -vim.keymap.set('n', 'tn', ':vs term://bash') +-- Quickfix navigation +vim.keymap.set('n', ']q', 'cnext', { desc = 'Next [Q]uickfix' }) +vim.keymap.set('n', '[q', 'cprev', { desc = 'Previous [Q]uickfix' }) diff --git a/lua/setup/lazy.lua b/lua/setup/lazy.lua index 7611a8a5..38388d1c 100644 --- a/lua/setup/lazy.lua +++ b/lua/setup/lazy.lua @@ -11,7 +11,14 @@ vim.opt.rtp:prepend(lazypath) require('lazy').setup({ -- Git related plugins - 'sindrets/diffview.nvim', + { + 'sindrets/diffview.nvim', + cmd = { 'DiffviewOpen', 'DiffviewFileHistory', 'DiffviewClose' }, + keys = { + { 'gv', 'DiffviewOpen', desc = '[G]it Diff[V]iew' }, + { 'gh', 'DiffviewFileHistory %', desc = '[G]it File [H]istory' }, + }, + }, -- Detect tabstop and shiftwidth automatically 'tpope/vim-sleuth', diff --git a/lua/setup/lsp.lua b/lua/setup/lsp.lua index 254f8bca..6b0ee43d 100644 --- a/lua/setup/lsp.lua +++ b/lua/setup/lsp.lua @@ -3,7 +3,7 @@ vim.lsp.enable { 'basedpyright', 'clangd', -- 'typos_lsp', - 'ty', + -- 'ty', -- removed: redundant with basedpyright, adds diagnostic noise 'ts_ls', 'cssls', 'html', @@ -12,17 +12,18 @@ vim.lsp.enable { vim.lsp.inlay_hint.enable(true) local virtual_text_mode = nil +local base_virtual_text = { + source = 'if_many', + spacing = 2, + format = function(diagnostic) + return diagnostic.message + end, +} +local diagnostic_underline = { severity = vim.diagnostic.severity.ERROR } vim.diagnostic.config { - virtual_text = { - source = 'if_many', - spacing = 2, - format = function(diagnostic) - return diagnostic.message - end, - current_line = virtual_text_mode, - }, - underline = { severity = vim.diagnostic.severity.ERROR }, + virtual_text = base_virtual_text, + underline = diagnostic_underline, update_in_insert = false, severity_sort = true, float = { @@ -55,10 +56,8 @@ vim.api.nvim_create_user_command('LspToggleDiagnostic', function() else virtual_text_mode = nil vim.diagnostic.config { - virtual_text = { - current_line = virtual_text_mode, - }, - underline = true, + virtual_text = base_virtual_text, + underline = diagnostic_underline, } end end, {}) @@ -79,14 +78,14 @@ local function restart_lsp(client_name) -- 1) Collect buffers that had this client and the client configs to reuse local target = {} -- [bufnr] = client.config - local to_stop = {} -- [client_id] = true + local to_stop = {} -- [client_id] = client for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do if vim.api.nvim_buf_is_loaded(bufnr) then for _, c in ipairs(vim.lsp.get_clients { bufnr = bufnr }) do if c.name == client_name then target[bufnr] = c.config - to_stop[c.id] = true + to_stop[c.id] = c end end end @@ -97,9 +96,9 @@ local function restart_lsp(client_name) return end - -- 2) Stop all those clients (force=true to avoid waiting handshake) - for id in pairs(to_stop) do - vim.lsp.stop_client(id) + -- 2) Stop all those clients (force=true) + for _, client in pairs(to_stop) do + client:stop(true) end -- 3) For each buffer, (re)start using the original config. diff --git a/lua/setup/set.lua b/lua/setup/set.lua index 22fce6ac..93a873d3 100644 --- a/lua/setup/set.lua +++ b/lua/setup/set.lua @@ -1,4 +1,4 @@ -vim.g.nofsync = true +vim.opt.fsync = false -- System Clipboard Integration vim.schedule(function() @@ -10,7 +10,7 @@ vim.opt.nu = true vim.opt.relativenumber = true -- Default terminal to pwsh -vim.opt.shell = vim.fn.executable 'pwsh' and 'pwsh' or 'powershell' +vim.opt.shell = vim.fn.executable('pwsh') == 1 and 'pwsh' or 'powershell' vim.opt.shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command [Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;' vim.opt.shellredir = '-RedirectStandardOutput %s -NoNewWindow -Wait' @@ -27,6 +27,7 @@ vim.cmd 'command! Qw wq' vim.cmd 'command! Q q' -- Save undo history +vim.fn.mkdir(vim.fn.stdpath('data') .. '/undodir', 'p') vim.opt.undodir = vim.fn.stdpath 'data' .. '/undodir' vim.opt.undofile = true @@ -59,7 +60,7 @@ vim.opt.expandtab = true vim.opt.smartindent = true vim.o.autoindent = true -vim.opt.wrap = true +vim.opt.wrap = false -- Disable swap and backup files vim.opt.swapfile = false diff --git a/machine.json b/machine.json new file mode 100644 index 00000000..9e08be5a --- /dev/null +++ b/machine.json @@ -0,0 +1,6 @@ +{ + "_comment": "Machine-specific paths — DO NOT COMMIT. See machine.json.template for the template.", + "basedpyright": "D:\\language-servers\\basedpyright\\Scripts\\basedpyright-langserver.exe", + "clangd": "D:\\language-servers\\clangd\\bin\\clangd.exe", + "ue_python": "C:\\Program Files\\Epic Games\\UE_5.7\\Engine\\Binaries\\ThirdParty\\Python3\\Win64\\python.exe" +} diff --git a/machine.json.template b/machine.json.template new file mode 100644 index 00000000..d4c2de0b --- /dev/null +++ b/machine.json.template @@ -0,0 +1,6 @@ +{ + "_comment": "Copy this file to machine.json and fill in the paths for this machine. machine.json is gitignored.", + "basedpyright": "D:\\language-servers\\basedpyright\\Scripts\\basedpyright-langserver.exe", + "clangd": "D:\\language-servers\\clangd\\bin\\clangd.exe", + "ue_python": "C:\\Program Files\\Epic Games\\UE_5.7\\Engine\\Binaries\\ThirdParty\\Python3\\Win64\\python.exe" +} diff --git a/requirements.md b/requirements.md new file mode 100644 index 00000000..cf707bb0 --- /dev/null +++ b/requirements.md @@ -0,0 +1,387 @@ +# Neovim Configuration Requirements + +## Plugin Manager + +| Plugin | GitHub | +|--------|--------| +| lazy.nvim | https://github.com/folke/lazy.nvim | + +--- + +## Completion + +| Plugin | GitHub | +|--------|--------| +| blink.cmp | https://github.com/saghen/blink.cmp | +| LuaSnip | https://github.com/L3MON4D3/LuaSnip | +| friendly-snippets | https://github.com/rafamadriz/friendly-snippets | +| nvim-autopairs | https://github.com/windwp/nvim-autopairs | + +--- + +## LSP + +| Plugin | GitHub | +|--------|--------| +| nvim-lspconfig | https://github.com/neovim/nvim-lspconfig | +| mason.nvim | https://github.com/mason-org/mason.nvim | +| mason-lspconfig.nvim | https://github.com/mason-org/mason-lspconfig.nvim | +| mason-tool-installer.nvim | https://github.com/WhoIsSethDaniel/mason-tool-installer.nvim | +| lazydev.nvim | https://github.com/folke/lazydev.nvim | +| fidget.nvim | https://github.com/j-hui/fidget.nvim | +| lua-language-server | https://github.com/LuaLS/lua-language-server | +| basedpyright | https://github.com/DetachHead/basedpyright | +| clangd | https://github.com/clangd/clangd | +| typescript-language-server | https://github.com/typescript-language-server/typescript-language-server | +| vscode-langservers-extracted (css-lsp + html-lsp) | https://github.com/hrsh7th/vscode-langservers-extracted | + +--- + +## Formatting & Linting + +| Plugin | GitHub | +|--------|--------| +| conform.nvim | https://github.com/stevearc/conform.nvim | +| nvim-lint | https://github.com/mfussenegger/nvim-lint | +| stylua | https://github.com/JohnnyMorganz/StyLua | +| prettier | https://github.com/prettier/prettier | +| ruff | https://github.com/astral-sh/ruff | +| clang-format | https://github.com/llvm/llvm-project | +| markdownlint | https://github.com/DavidAnson/markdownlint-cli | + +--- + +## Treesitter + +| Plugin | GitHub | +|--------|--------| +| nvim-treesitter | https://github.com/nvim-treesitter/nvim-treesitter | +| nvim-treesitter-context | https://github.com/nvim-treesitter/nvim-treesitter-context | +| nvim-treesitter-textobjects | https://github.com/nvim-treesitter/nvim-treesitter-textobjects | + +--- + +## UI + +| Plugin | GitHub | +|--------|--------| +| gruvbox.nvim | https://github.com/ellisonleao/gruvbox.nvim | +| lualine.nvim | https://github.com/nvim-lualine/lualine.nvim | +| snacks.nvim | https://github.com/folke/snacks.nvim | +| noice.nvim | https://github.com/folke/noice.nvim | +| nvim-notify | https://github.com/rcarriga/nvim-notify | +| nui.nvim | https://github.com/MunifTanjim/nui.nvim | +| neo-tree.nvim | https://github.com/nvim-neo-tree/neo-tree.nvim | +| which-key.nvim | https://github.com/folke/which-key.nvim | +| indent-blankline.nvim | https://github.com/lukas-reineke/indent-blankline.nvim | +| render-markdown.nvim | https://github.com/MeanderingProgrammer/render-markdown.nvim | +| nvim-highlight-colors | https://github.com/brenoprata10/nvim-highlight-colors | +| todo-comments.nvim | https://github.com/folke/todo-comments.nvim | +| log-highlight.nvim | https://github.com/fei6409/log-highlight.nvim | +| nvim-web-devicons | https://github.com/nvim-tree/nvim-web-devicons | + +--- + +## Navigation + +| Plugin | GitHub | +|--------|--------| +| telescope.nvim | https://github.com/nvim-telescope/telescope.nvim | +| telescope-fzf-native.nvim | https://github.com/nvim-telescope/telescope-fzf-native.nvim | +| telescope-ui-select.nvim | https://github.com/nvim-telescope/telescope-ui-select.nvim | +| smart-splits.nvim | https://github.com/mrjones2014/smart-splits.nvim | +| treesj | https://github.com/Wansmer/treesj | + +--- + +## Git + +| Plugin | GitHub | +|--------|--------| +| vim-fugitive | https://github.com/tpope/vim-fugitive | +| gitsigns.nvim | https://github.com/lewis6991/gitsigns.nvim | +| diffview.nvim | https://github.com/sindrets/diffview.nvim | + +--- + +## Editing + +| Plugin | GitHub | +|--------|--------| +| nvim-surround | https://github.com/kylechui/nvim-surround | +| mini.ai | https://github.com/echasnovski/mini.ai | +| vim-sleuth | https://github.com/tpope/vim-sleuth | + +--- + +## Terminal + +| Plugin | GitHub | +|--------|--------| +| toggleterm.nvim | https://github.com/akinsho/toggleterm.nvim | + +--- + +## AI + +| Plugin | GitHub | +|--------|--------| +| copilot.lua | https://github.com/zbirenbaum/copilot.lua | +| blink-cmp-copilot | https://github.com/giuxtaposition/blink-cmp-copilot | +| CopilotChat.nvim | https://github.com/CopilotC-Nvim/CopilotChat.nvim | +| codecompanion.nvim | https://github.com/olimorris/codecompanion.nvim | + +--- + +## Debugging (DAP) + +| Plugin | GitHub | +|--------|--------| +| nvim-dap | https://github.com/mfussenegger/nvim-dap | +| nvim-dap-ui | https://github.com/rcarriga/nvim-dap-ui | +| nvim-nio | https://github.com/nvim-neotest/nvim-nio | +| mason-nvim-dap.nvim | https://github.com/jay-babu/mason-nvim-dap.nvim | +| nvim-dap-python | https://github.com/mfussenegger/nvim-dap-python | +| nvim-dap-virtual-text | https://github.com/theHamsta/nvim-dap-virtual-text | +| codelldb | https://github.com/vadimcn/codelldb | +| debugpy | https://github.com/microsoft/debugpy | + +--- + +## Language Specific + +| Plugin | GitHub | +|--------|--------| +| cmake-tools.nvim | https://github.com/Civitasv/cmake-tools.nvim | +| Unreal-Nvim | https://github.com/PlayKigai/Unreal-Nvim | + +--- + +## Shared Dependencies + +| Plugin | GitHub | +|--------|--------| +| plenary.nvim | https://github.com/nvim-lua/plenary.nvim | + + +## Completion + +| Plugin | GitHub | +|--------|--------| +| blink.cmp | https://github.com/saghen/blink.cmp | +| LuaSnip | https://github.com/L3MON4D3/LuaSnip | +| friendly-snippets | https://github.com/rafamadriz/friendly-snippets | +| nvim-autopairs | https://github.com/windwp/nvim-autopairs | + +--- + +## LSP + +| Plugin | GitHub | +|--------|--------| +| nvim-lspconfig | https://github.com/neovim/nvim-lspconfig | +| mason.nvim | https://github.com/mason-org/mason.nvim | +| mason-lspconfig.nvim | https://github.com/mason-org/mason-lspconfig.nvim | +| mason-tool-installer.nvim | https://github.com/WhoIsSethDaniel/mason-tool-installer.nvim | +| lazydev.nvim | https://github.com/folke/lazydev.nvim | +| fidget.nvim | https://github.com/j-hui/fidget.nvim | + +### LSP Servers (installed via Mason) + +| Server | Language | +|--------|----------| +| lua-language-server | Lua | +| basedpyright | Python | +| clangd | C / C++ | +| typescript-language-server (ts_ls) | TypeScript / JavaScript | +| css-lsp | CSS | +| html-lsp | HTML | + +### LSP Servers — Manual Install (No Mason) + +> Clone or download releases directly from GitHub, build/install per each repo's README, then either put the binary on your `PATH` or set the machine-specific path in `machine.json` for servers that use `lua/machine.lua` (`basedpyright` and `clangd` in the current config). + +| Server | GitHub | Notes | +|--------|--------|-------| +| lua-language-server | https://github.com/LuaLS/lua-language-server | Pre-built releases available; add `bin/` to PATH | +| basedpyright | https://github.com/DetachHead/basedpyright | Install via `pip install basedpyright`; `lsp/basedpyright.lua` can also read the binary path from `machine.json` key `basedpyright` | +| clangd | https://github.com/clangd/clangd | Pre-built releases available; part of LLVM toolchain; `lsp/clangd.lua` can also read the binary path from `machine.json` key `clangd` | +| typescript-language-server | https://github.com/typescript-language-server/typescript-language-server | Requires Node.js; build from source with `npm install` | +| css-lsp + html-lsp | https://github.com/hrsh7th/vscode-langservers-extracted | Both servers come from this single repo; requires Node.js | + +> `:LspRestart` currently does a stop-then-deferred-start cycle and may hit timing issues on some buffers or roots. If a restart looks incomplete, use `:LspStop` and then `:LspStart` separately. + +> `:LspToggleDiagnostic` switches `virtual_text.current_line` and underline state, but custom `virtual_text` settings may need to be re-applied manually after toggling. + +### Formatters & Linters (installed via Mason) + +| Tool | Purpose | +|------|---------| +| stylua | Lua formatter | +| prettier | JS / TS / CSS / HTML formatter | +| ruff | Python formatter / import sorter | +| clang-format | C / C++ formatter | + +### Formatters & Linters — Manual Install (No Mason) + +> Same rule: build from source or grab a release binary, put it on `PATH`. `conform.nvim` and `nvim-lint` will pick it up automatically. + +| Tool | GitHub | Notes | +|------|--------|-------| +| stylua | https://github.com/JohnnyMorganz/StyLua | Pre-built releases available for all platforms | +| prettier | https://github.com/prettier/prettier | Requires Node.js; build from source with `npm install` | +| ruff | https://github.com/astral-sh/ruff | Requires Python; install with `pip install ruff` from source or release | +| clang-format | https://github.com/llvm/llvm-project | Pre-built releases available; part of LLVM toolchain | +| markdownlint | https://github.com/DavidAnson/markdownlint-cli | Requires Node.js; install with `npm install` so `nvim-lint` can lint Markdown | + +### DAP Adapters (installed via Mason) + +| Adapter | GitHub | +|---------|--------| +| codelldb | https://github.com/vadimcn/codelldb | +| debugpy | https://github.com/microsoft/debugpy | + +### DAP Adapters — Manual Install (No Mason) + +> `lua/plugins/debug.lua` configures `mason-nvim-dap.nvim` to install both `codelldb` and `debugpy`. Without Mason, install from GitHub and point `nvim-dap`'s adapter config at the binary. + +| Adapter | GitHub | Notes | +|---------|--------|-------| +| codelldb | https://github.com/vadimcn/codelldb | Pre-built releases available; point `nvim-dap` at the adapter executable if needed | +| debugpy (Python) | https://github.com/microsoft/debugpy | Install with `pip install debugpy`; with Mason, `nvim-dap-python` uses the Mason `debugpy` virtualenv first and falls back to the system Python if the Mason package is missing | + +> Verify that the Python interpreter selected for debugging matches the current workspace, especially when Mason is installed but the project expects a different virtualenv. + +--- + +## Treesitter + +| Plugin | GitHub | +|--------|--------| +| nvim-treesitter | https://github.com/nvim-treesitter/nvim-treesitter | +| nvim-treesitter-context | https://github.com/nvim-treesitter/nvim-treesitter-context | +| nvim-treesitter-textobjects | https://github.com/nvim-treesitter/nvim-treesitter-textobjects | + +--- + +## Formatting & Linting + +| Plugin | GitHub | +|--------|--------| +| conform.nvim | https://github.com/stevearc/conform.nvim | +| nvim-lint | https://github.com/mfussenegger/nvim-lint | + +### Formatters / Linters (installed via Mason) + +| Tool | Purpose | +|------|---------| +| stylua | Lua formatter | +| prettier | JS / TS / CSS / HTML formatter | +| ruff | Python formatter / import sorter | +| clang-format | C / C++ formatter | + +--- + +## UI + +| Plugin | GitHub | +|--------|--------| +| gruvbox.nvim | https://github.com/ellisonleao/gruvbox.nvim | +| lualine.nvim | https://github.com/nvim-lualine/lualine.nvim | +| snacks.nvim | https://github.com/folke/snacks.nvim | +| noice.nvim | https://github.com/folke/noice.nvim | +| nvim-notify | https://github.com/rcarriga/nvim-notify | +| nui.nvim | https://github.com/MunifTanjim/nui.nvim | +| neo-tree.nvim | https://github.com/nvim-neo-tree/neo-tree.nvim | +| which-key.nvim | https://github.com/folke/which-key.nvim | +| indent-blankline.nvim | https://github.com/lukas-reineke/indent-blankline.nvim | +| render-markdown.nvim | https://github.com/MeanderingProgrammer/render-markdown.nvim | +| nvim-highlight-colors | https://github.com/brenoprata10/nvim-highlight-colors | +| todo-comments.nvim | https://github.com/folke/todo-comments.nvim | +| log-highlight.nvim | https://github.com/fei6409/log-highlight.nvim | +| nvim-web-devicons | https://github.com/nvim-tree/nvim-web-devicons | + +--- + +## Navigation + +| Plugin | GitHub | +|--------|--------| +| telescope.nvim | https://github.com/nvim-telescope/telescope.nvim | +| telescope-fzf-native.nvim | https://github.com/nvim-telescope/telescope-fzf-native.nvim | +| telescope-ui-select.nvim | https://github.com/nvim-telescope/telescope-ui-select.nvim | +| smart-splits.nvim | https://github.com/mrjones2014/smart-splits.nvim | +| treesj | https://github.com/Wansmer/treesj | + +--- + +## Git + +| Plugin | GitHub | +|--------|--------| +| vim-fugitive | https://github.com/tpope/vim-fugitive | +| gitsigns.nvim | https://github.com/lewis6991/gitsigns.nvim | +| diffview.nvim | https://github.com/sindrets/diffview.nvim | + +--- + +## Editing + +| Plugin | GitHub | +|--------|--------| +| nvim-surround | https://github.com/kylechui/nvim-surround | +| mini.ai | https://github.com/echasnovski/mini.ai | +| vim-sleuth | https://github.com/tpope/vim-sleuth | + +--- + +## Terminal + +| Plugin | GitHub | +|--------|--------| +| toggleterm.nvim | https://github.com/akinsho/toggleterm.nvim | + +--- + +## AI + +| Plugin | GitHub | +|--------|--------| +| copilot.lua | https://github.com/zbirenbaum/copilot.lua | +| blink-cmp-copilot | https://github.com/giuxtaposition/blink-cmp-copilot | +| CopilotChat.nvim | https://github.com/CopilotC-Nvim/CopilotChat.nvim | +| codecompanion.nvim | https://github.com/olimorris/codecompanion.nvim | + +--- + +## Debugging (DAP) + +| Plugin | GitHub | +|--------|--------| +| nvim-dap | https://github.com/mfussenegger/nvim-dap | +| nvim-dap-ui | https://github.com/rcarriga/nvim-dap-ui | +| nvim-nio | https://github.com/nvim-neotest/nvim-nio | +| mason-nvim-dap.nvim | https://github.com/jay-babu/mason-nvim-dap.nvim | +| nvim-dap-python | https://github.com/mfussenegger/nvim-dap-python | +| nvim-dap-virtual-text | https://github.com/theHamsta/nvim-dap-virtual-text | + +> Current DAP setup auto-installs `codelldb` and `debugpy` through Mason; Python debugging is wired through `nvim-dap-python`, which prefers Mason's `debugpy` environment and falls back to the system Python when the Mason package is unavailable. + +--- + +## Language Specific + +| Plugin | GitHub | +|--------|--------| +| cmake-tools.nvim | https://github.com/Civitasv/cmake-tools.nvim | +| Unreal-Nvim | https://github.com/PlayKigai/Unreal-Nvim | + +> `lua/plugins/unreal.lua` now auto-initializes `Unreal-Nvim` when opening `*.uproject`, `*.uplugin`, `*.Build.cs`, or `*.Target.cs` files, and also when opening C/C++ files inside a working directory that contains a `.uproject`. This covers the common Unreal entry points, but edge cases may still need a manual `:Unreal` command. + +--- + +## Shared Dependencies + +| Plugin | GitHub | +|--------|--------| +| plenary.nvim | https://github.com/nvim-lua/plenary.nvim | diff --git a/tmp/diag_test.lua b/tmp/diag_test.lua new file mode 100644 index 00000000..589387e4 --- /dev/null +++ b/tmp/diag_test.lua @@ -0,0 +1,9 @@ +vim.diagnostic.config({ + virtual_text = { source = 'if_many', spacing = 2, format = function(d) return d.message end, current_line = nil }, + underline = { severity = vim.diagnostic.severity.ERROR }, +}) +vim.diagnostic.config({ virtual_text = { current_line = true }, underline = false }) +local cfg = vim.diagnostic.config() +print(vim.inspect(cfg.virtual_text)) +print(vim.inspect(cfg.underline)) +vim.cmd('qa!')