From a5e8bbeb9d79d905a193e95a39acd29bc37e6c66 Mon Sep 17 00:00:00 2001 From: Tom van der Lee Date: Wed, 16 Sep 2026 08:47:13 +0200 Subject: Updated dotfiles --- neovim/.config/nvim/README.md | 135 +++++++++++++++- neovim/.config/nvim/lazy-lock.json | 25 +-- neovim/.config/nvim/lua/config/autocmds.lua | 43 +++++ neovim/.config/nvim/lua/config/dap_node.lua | 88 +++++++++++ neovim/.config/nvim/lua/config/keymaps.lua | 12 ++ neovim/.config/nvim/lua/config/options.lua | 6 + neovim/.config/nvim/lua/config/project_run.lua | 151 ++++++++++++++++++ neovim/.config/nvim/lua/plugins/claude-code.lua | 1 + neovim/.config/nvim/lua/plugins/colorscheme.lua | 8 + neovim/.config/nvim/lua/plugins/dap-python.lua | 71 +++++++++ neovim/.config/nvim/lua/plugins/dap.lua | 181 ++++++++++++++++++++++ neovim/.config/nvim/lua/plugins/editing.lua | 10 -- neovim/.config/nvim/lua/plugins/fuzzyfinder.lua | 36 ++++- neovim/.config/nvim/lua/plugins/git.lua | 5 +- neovim/.config/nvim/lua/plugins/indent-detect.lua | 8 + neovim/.config/nvim/lua/plugins/langs.lua | 14 -- neovim/.config/nvim/lua/plugins/overseer.lua | 57 +++++++ neovim/.config/nvim/lua/plugins/statusline.lua | 24 +-- neovim/.config/nvim/lua/plugins/toggleterm.lua | 18 +++ neovim/.config/nvim/lua/plugins/which-key.lua | 17 ++ neovim/.config/nvim/nvim.log | 6 + 21 files changed, 849 insertions(+), 67 deletions(-) create mode 100644 neovim/.config/nvim/lua/config/dap_node.lua create mode 100644 neovim/.config/nvim/lua/config/project_run.lua create mode 100644 neovim/.config/nvim/lua/plugins/dap-python.lua create mode 100644 neovim/.config/nvim/lua/plugins/dap.lua create mode 100644 neovim/.config/nvim/lua/plugins/indent-detect.lua delete mode 100644 neovim/.config/nvim/lua/plugins/langs.lua create mode 100644 neovim/.config/nvim/lua/plugins/overseer.lua create mode 100644 neovim/.config/nvim/lua/plugins/toggleterm.lua create mode 100644 neovim/.config/nvim/lua/plugins/which-key.lua create mode 100644 neovim/.config/nvim/nvim.log (limited to 'neovim/.config') diff --git a/neovim/.config/nvim/README.md b/neovim/.config/nvim/README.md index 5092af0..0e50788 100644 --- a/neovim/.config/nvim/README.md +++ b/neovim/.config/nvim/README.md @@ -15,6 +15,8 @@ lua/config/ Everything that isn't a plugin declaration options.lua vim.opt settings (search, undo, whitespace display, ...) keymaps.lua Global keymaps not owned by a specific plugin autocmds.lua Global autocmds not owned by a specific plugin + project_run.lua Helper for project-local run/debug configs (see below) + dap_node.lua Node/js-debug-adapter wiring for nvim-dap (see below) lazy.lua Bootstraps lazy.nvim and points it at lua/plugins/ lua/plugins/ One file per plugin (or small plugin group), each returning a lazy.nvim plugin spec (or list of specs) @@ -34,18 +36,23 @@ such tables) and it's included on next launch. | File | Plugin(s) | Purpose | |---|---|---| | `colorscheme.lua` | vim-janah | Color scheme, falls back to `desert` if it fails to load | -| `statusline.lua` | vim-airline, vim-airline-themes, tmuxline.vim | Status/tab line | +| `statusline.lua` | lualine.nvim | Status line | | `filetree.lua` | neo-tree.nvim | File explorer sidebar with git-status colors (`e` to toggle) | -| `fuzzyfinder.lua` | ctrlp.vim | Fuzzy file finder (ripgrep-backed if `rg` is on PATH) | -| `editing.lua` | nerdcommenter, quick-scope | Comment toggling, `f`/`F`/`t`/`T` target highlighting | -| `git.lua` | vim-fugitive, vim-signify | `:Git` commands, git-diff gutter signs | +| `fuzzyfinder.lua` | telescope.nvim, telescope-ui-select.nvim | Fuzzy file finder (``), live grep (`fg`), buffers (`fb`); also overrides `vim.ui.select` globally so overseer's/dap's pickers are Telescope windows | +| `editing.lua` | quick-scope | `f`/`F`/`t`/`T` target highlighting (comment toggling is Neovim's built-in `gc`/`gcc`) | +| `git.lua` | vim-fugitive, gitsigns.nvim | `:Git` commands, git-diff gutter signs | | `ale.lua` | ALE | Linters/fixers only — `g:ale_disable_lsp = 1` so it doesn't fight the LSP client's diagnostics/hover/go-to-def | -| `langs.lua` | vim-ansible-yaml, vim-terraform | Only loaded if `ansible`/`terraform` is on PATH (lazy.nvim `cond`) | | `claude-code.lua` | claude-code.nvim (+ plenary.nvim) | `:ClaudeCode` and friends | +| `toggleterm.lua` | toggleterm.nvim | Scratch terminal toggle — ``, vertical split on the right matching claude-code.nvim's placement/ratio | | `treesitter.lua` | nvim-treesitter (`main` branch) | Parser installs + syntax highlighting | | `autopairs.lua` | nvim-autopairs, nvim-ts-autotag | Auto-close brackets/quotes/HTML+JSX tags | | `completion.lua` | blink.cmp (+ friendly-snippets) | Completion popup, Tab-to-accept (`super-tab` preset) | | `lsp.lua` | nvim-lspconfig, mason.nvim, mason-lspconfig.nvim | Installs & enables language servers, wires blink.cmp's capabilities into them | +| `dap.lua` | nvim-dap, nvim-dap-ui, nvim-dap-virtual-text, mason-nvim-dap.nvim | Debugger core + UI, installs debug adapters via Mason (`d*`) | +| `dap-python.lua` | nvim-dap-python | Python launch configs, wired to Mason's debugpy install | +| `overseer.lua` | overseer.nvim | Save/run/rerun arbitrary run configurations for any language (`r*`) | +| `which-key.lua` | which-key.nvim | Keymap discoverability popup; labels the `d`/`r`/etc. groups | +| `indent-detect.lua` | guess-indent.nvim | Detects each buffer's real indentation and matches shiftwidth/tabstop to it | ## Language servers @@ -59,6 +66,112 @@ hover) come from Neovim's built-in default LSP keymaps (`:help lsp-defaults`) once a server attaches — `grn`, `gra`, `grr`, `gri`, `gO`, `K`, ``. No extra plugin or keymap needed for these. +## Debugging + +Python and Node.js (JavaScript/TypeScript), via `nvim-dap` + `nvim-dap-ui`. +The `debugpy` and `js-debug-adapter` adapters are installed and kept up to +date by Mason (via `mason-nvim-dap.nvim`, the DAP equivalent of +`mason-lspconfig.nvim`), so `:Mason` shows them alongside the language +servers. Keymaps live under `d` — `db` to set a breakpoint, +`dc` to start/continue (picks a registered config from any window, +not just the source buffer; resumes in place if a session is already stopped +at a breakpoint), `do`/`di`/`dO` to step over/into/out, `dt` +to terminate, `du` to reopen the UI if you close it manually (it +opens/closes itself automatically around a session). Press `d` and +wait to see the full list via which-key. + +Python's adapter/config setup lives in `lua/plugins/dap-python.lua`, wrapping +the `nvim-dap-python` plugin. Node's lives in `lua/config/dap_node.lua` +instead — there's no maintained `nvim-dap-python`-style plugin for it (the +community option, `nvim-dap-vscode-js`, expects an older, manually-built +vscode-js-debug layout that doesn't match what Mason's `js-debug-adapter` +package installs), so that file resolves the Mason install path directly and +registers the `pwa-node` adapter + default `javascript`/`typescript`/ +`javascriptreact`/`typescriptreact` configs itself. It's called eagerly from +`dap.lua`'s own `config()` rather than being its own `lua/plugins/*` entry, +since it isn't an installable plugin — same reasoning as +`lua/config/project_run.lua`. + +Adding another language later (e.g. C/C++ via `codelldb`) means adding its +adapter to `dap.lua`'s `ensure_installed`, and either writing its own +`dap-.lua` plugin file (if a wrapper plugin exists, following the +`dap-python.lua` pattern) or a `lua/config/dap_.lua` module called +from `dap.lua`'s `config()` (if not, following the `dap_node.lua` pattern) — +including `lazy = false` on `dap.lua` itself either way, so the adapter is +registered from startup rather than only after a buffer of that filetype is +opened (the `dc` picker works from any window, so it can't rely on +that to lazy-trigger the adapter). + +`overseer.lua` sets `dap = true`, which patches `nvim-dap` so a debug +configuration can set `preLaunchTask`/`postDebugTask` to the name of an +overseer task (or `"${defaultBuildTask}"` for whichever task is tagged +`BUILD`) — useful for "build, then debug" workflows once a compiled +language is added; not needed for plain Python/Node scripts. + +## Run configurations + +`overseer.nvim` provides PyCharm-style saved/rerunnable run configurations +for any language or toolchain (shell commands, npm scripts, make, cargo, +python scripts, ...) — it isn't tied to LSP/DAP language support. Keymaps +live under `r` — `rr` to run a task (prompts for a template +or a raw command), `rl` to rerun the last task, `ro` to +toggle the task list/output window, `rq` for quick actions +(restart/stop/dispose) on a selected task. Press `r` and wait to see +the full list via which-key. + +`overseer.lua`'s `component_aliases.default` adds the `open_output` +component (`on_start = "always"`, `focus = false`) on top of overseer's own +defaults, so starting *any* task — custom, `.nvim.lua`-declared, or +auto-detected (npm/make/etc.) — docks its output automatically instead of +running silently until you manually `ro`. + +## Project-local run/debug configs + +A project can drop a `.nvim.lua` anywhere in its directory tree and have it +auto-sourced (after a one-time `:help :trust` prompt — it runs arbitrary +Lua, so trust it deliberately, not reflexively). This is the PyCharm-style +"named configuration" mechanism, without adopting any other editor's file +format. + +This is **not** core Vim/Neovim `'exrc'` (deliberately left off in +options.lua) — `exrc` only checks the literal cwd once at startup, so it +misses a project's `.nvim.lua` whenever Neovim didn't happen to start with +cwd exactly there. Instead, an autocmd in `lua/config/autocmds.lua` searches +*upward* from cwd on `VimEnter`/`DirChanged` (stopping at `$HOME`, same +nearest-ancestor pattern LSP root-dir detection uses) and reads the file via +`vim.secure.read` — the same trust mechanism `exrc` itself uses, so `:trust` +still manages the allowlist unchanged, it's just found reliably regardless +of how you opened Neovim. + +`lua/config/project_run.lua` gives that file one call per config that +registers both a `rr` run task and a matching `dc` debug +config from the *same* declaration, instead of repeating the command across +two separate files: + +```lua +-- /.nvim.lua +require("config.project_run").python({ + name = "Run app", + program = vim.fn.getcwd() .. "/main.py", + args = { "--flag" }, -- optional, shared by both run and debug +}) + +require("config.project_run").node({ + name = "Run app", + program = vim.fn.getcwd() .. "/index.js", -- or npmScript = "dev" for `npm run dev` + args = { "--flag" }, -- optional, shared by both run and debug +}) +``` + +`dap.lua` and `overseer.lua` are both `lazy = false` specifically so this +works immediately when the autocmd sources the file, rather than needing +the plugins already triggered by a keymap first. + +(`nvim-dap` and `overseer.nvim` also natively read `.vscode/launch.json` and +`.vscode/tasks.json` respectively, if you'd rather use that ecosystem's +format for some reason — but `project_run.lua` is the recommended path here +since it states each command once.) + ## Adding a new plugin Drop a new file in `lua/plugins/` (or add to an existing group file if it @@ -74,6 +187,18 @@ return { Restart Neovim (or `:Lazy sync`) to install it, then commit the updated `lazy-lock.json` alongside your change. +If a plugin backs a keymap or command meant to work from any window — not +scoped to a particular filetype/buffer, like the run/debug pickers, the +fuzzy finder, or the file explorer — set `lazy = false` rather than gating +it behind `ft`/`event`, even though lazy.nvim would otherwise recommend one. +A trigger tied to "some buffer of type X was opened" silently breaks the +moment the keymap fires before that's happened (this bit `dap-python.lua`: +it lazy-loaded on `ft = "python"`, so debugging broke whenever `dc` +was pressed before any `.py` buffer had been opened this session). Plain +per-buffer editing conveniences (`autopairs.lua`'s `InsertEnter`, +`ale.lua`'s `BufReadPre`, `which-key.lua`'s `VeryLazy`) don't have this +problem and can stay lazy. + ## Relationship to Vim Vim and Neovim used to share one `vimrc` (`has('nvim')` branches handled the diff --git a/neovim/.config/nvim/lazy-lock.json b/neovim/.config/nvim/lazy-lock.json index 6ac90ec..fd32868 100644 --- a/neovim/.config/nvim/lazy-lock.json +++ b/neovim/.config/nvim/lazy-lock.json @@ -2,26 +2,33 @@ "ale": { "branch": "master", "commit": "e1789bc54483d76ac9ddb40b633d1645c8281914" }, "blink.cmp": { "branch": "main", "commit": "78336bc89ee5365633bcf754d93df01678b5c08f" }, "claude-code.nvim": { "branch": "main", "commit": "55c0cb59828fbc3bec744288286a46f5d5750b83" }, - "ctrlp.vim": { "branch": "master", "commit": "0065942ef13ce28293e2b26cb622d035da050b44" }, "friendly-snippets": { "branch": "main", "commit": "b4d01b0fdf3c9a549961c2f9ffe8dc09be166219" }, + "gitsigns.nvim": { "branch": "main", "commit": "f2421c550618d257048afa650413d9e542ddbe67" }, + "guess-indent.nvim": { "branch": "main", "commit": "84a4987ff36798c2fc1169cbaff67960aed9776f" }, "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, - "mason-lspconfig.nvim": { "branch": "main", "commit": "b5576cd62899a1a478d0e67ef3d378ee55dba82d" }, + "lualine.nvim": { "branch": "master", "commit": "221ce6b2d999187044529f49da6554a92f740a96" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "77e06f7d2fc127e6ef0a720b59acbc50757cff19" }, + "mason-nvim-dap.nvim": { "branch": "main", "commit": "9a10e096703966335bd5c46c8c875d5b0690dade" }, "mason.nvim": { "branch": "main", "commit": "2a6940af80375532e5e9e7c1f2fc6319a1b7a69d" }, "neo-tree.nvim": { "branch": "v3.x", "commit": "1a14083046d96e88e361d1da00761c40d45012f3" }, - "nerdcommenter": { "branch": "master", "commit": "a462bbda1e26f44fb3d3eb9d9d1c6a07aa98e665" }, "nui.nvim": { "branch": "main", "commit": "10fc361835c856ba4233ef5ea135b919bf3dce97" }, "nvim-autopairs": { "branch": "master", "commit": "430522f95fe4fb7c511ec64f8c1a90cc6a66c05c" }, + "nvim-dap": { "branch": "master", "commit": "cfa2d58f4537aca6ca83e2de1a0d9f1491121264" }, + "nvim-dap-python": { "branch": "master", "commit": "1808458eba2b18f178f990e01376941a42c7f93b" }, + "nvim-dap-ui": { "branch": "master", "commit": "cc9dd33aade7f20bae414d0cba163bc60d4d4b43" }, + "nvim-dap-virtual-text": { "branch": "master", "commit": "fbdb48c2ed45f4a8293d0d483f7730d24467ccb6" }, "nvim-lspconfig": { "branch": "master", "commit": "ac9d2f7c4757db6320cab6697fe73e5e8adb2457" }, - "nvim-treesitter": { "branch": "main", "commit": "d4d59cb369da46b95699bd2200efbcffc6dadb3b" }, + "nvim-nio": { "branch": "master", "commit": "edcc181a875301dd21840189aa2f2f9ad69fc172" }, + "nvim-treesitter": { "branch": "main", "commit": "9a168f6357ed21c3a636e1727bc7d382abc451b8" }, "nvim-ts-autotag": { "branch": "main", "commit": "88c1453db4ba7dd24131086fe51fdf74e587d275" }, "nvim-web-devicons": { "branch": "master", "commit": "5f032a85be210cd1c6ac98861eb3b187ff3bd5eb" }, + "overseer.nvim": { "branch": "master", "commit": "a93d9f6d6defdac4bcd6d2c8ba988650e42e0a0e" }, "plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" }, "quick-scope": { "branch": "master", "commit": "6cee1d9e0b9ac0fbffeb538d4a5ba9f5628fabbc" }, - "tmuxline.vim": { "branch": "master", "commit": "4119c553923212cc67f4e135e6f946dc3ec0a4d6" }, - "vim-airline": { "branch": "master", "commit": "ae24f4aca06731d5d7224df1fc5415975331b214" }, - "vim-airline-themes": { "branch": "master", "commit": "77aab8c6cf7179ddb8a05741da7e358a86b2c3ab" }, - "vim-ansible-yaml": { "branch": "master", "commit": "a6f92d17ff01b2e63d6c9fdbb7f7e13c7fd41d14" }, + "telescope-ui-select.nvim": { "branch": "master", "commit": "6e51d7da30bd139a6950adf2a47fda6df9fa06d2" }, + "telescope.nvim": { "branch": "master", "commit": "40aedd8a68c78a656a10a8d62d80c54af59420fb" }, + "toggleterm.nvim": { "branch": "main", "commit": "9a88eae817ef395952e08650b3283726786fb5fb" }, "vim-fugitive": { "branch": "master", "commit": "3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0" }, "vim-janah": { "branch": "master", "commit": "3b8ae976987b6ade2abeac25f0208e8bc90d7138" }, - "vim-signify": { "branch": "master", "commit": "3b5ae37eb2b77c3ae58d60dfdc3fc30258078663" } + "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" } } diff --git a/neovim/.config/nvim/lua/config/autocmds.lua b/neovim/.config/nvim/lua/config/autocmds.lua index 7bc4f6b..e9ebe04 100644 --- a/neovim/.config/nvim/lua/config/autocmds.lua +++ b/neovim/.config/nvim/lua/config/autocmds.lua @@ -13,6 +13,49 @@ vim.api.nvim_create_autocmd("BufWritePre", { callback = strip_trailing_whitespace, }) +-- Project-local config: search upward from cwd for a .nvim.lua, the same +-- nearest-ancestor pattern LSP root-dir detection uses, so it's found +-- regardless of exactly which subdirectory Neovim's cwd is or how you got +-- there (:cd, opening a file, session restore, ...) - unlike core 'exrc' +-- (deliberately left off in options.lua), which only ever checks the +-- literal cwd once at startup. +local sourced_project_configs = {} + +local function source_project_config() + local found = vim.fs.find(".nvim.lua", { + upward = true, + path = vim.fn.getcwd(), + stop = vim.env.HOME, + })[1] + if not found or sourced_project_configs[found] then + return + end + + -- vim.secure.read is the same trust mechanism 'exrc' itself uses: prompts + -- on first encounter, honors ~/.local/state/nvim/trust, :trust still + -- manages the allowlist unchanged. Returns nil (no prompt shown again) + -- for a file previously denied. + local content = vim.secure.read(found) + if not content then + return + end + sourced_project_configs[found] = true + + local chunk, load_err = load(content, "@" .. found) + if not chunk then + vim.notify("Error loading " .. found .. ":\n" .. load_err, vim.log.levels.ERROR) + return + end + local ok, run_err = pcall(chunk) + if not ok then + vim.notify("Error running " .. found .. ":\n" .. run_err, vim.log.levels.ERROR) + end +end + +vim.api.nvim_create_autocmd({ "VimEnter", "DirChanged" }, { + callback = source_project_config, +}) + -- Note: the colorscheme (with its "desert" fallback) is applied from -- lua/plugins/colorscheme.lua's own `config` function, not here — under -- lazy.nvim that's the natural place to react to "the plugin is now loaded". diff --git a/neovim/.config/nvim/lua/config/dap_node.lua b/neovim/.config/nvim/lua/config/dap_node.lua new file mode 100644 index 0000000..0fb6890 --- /dev/null +++ b/neovim/.config/nvim/lua/config/dap_node.lua @@ -0,0 +1,88 @@ +-- JavaScript/TypeScript launch configs, wired to the js-debug-adapter +-- (Microsoft's vscode-js-debug, bundled by Mason as a standalone +-- multi-session DAP server) that dap.lua's mason-nvim-dap ensure_installed +-- installs. +-- +-- There's no nvim-dap-python equivalent for this: the one community plugin +-- for it (mxsdev/nvim-dap-vscode-js) hardcodes the older +-- `out/src/vsDebugServer.js` vscode-js-debug build layout, which doesn't +-- match what Mason's js-debug-adapter package actually installs +-- (`js-debug/src/dapDebugServer.js`) - so this resolves the Mason path +-- directly instead, same approach as dap-python.lua's debugpy_path. +-- +-- Lives under lua/config/ rather than lua/plugins/ (and is required +-- eagerly from dap.lua's config()) because it isn't an installable plugin +-- itself, just adapter/config wiring - same reason project_run.lua lives +-- here instead of there. +-- +-- js-debug-adapter is a multi-session server: debugging a script that +-- spawns a worker thread arrives as a `startDebugging` reverse request +-- rather than a second top-level session. nvim-dap's core (dap/session.lua) +-- already handles that natively, so no extra plugin is needed for it either. +local M = {} + +local function configurations() + return { + { + type = "pwa-node", + request = "launch", + name = "Launch file", + program = "${file}", + cwd = "${workspaceFolder}", + }, + { + type = "pwa-node", + request = "attach", + name = "Attach to process", + processId = require("dap.utils").pick_process, + cwd = "${workspaceFolder}", + }, + } +end + +function M.setup() + local registry = require("mason-registry") + local pkg = registry.get_package("js-debug-adapter") + + local function register() + local entrypoint = pkg:get_install_path() .. "/js-debug/src/dapDebugServer.js" + + require("dap").adapters["pwa-node"] = { + type = "server", + host = "localhost", + port = "${port}", + executable = { + command = "node", + args = { entrypoint, "${port}" }, + }, + } + + local dap = require("dap") + for _, filetype in ipairs({ "javascript", "typescript", "javascriptreact", "typescriptreact" }) do + dap.configurations[filetype] = configurations() + end + end + + if pkg:is_installed() then + register() + else + -- Same reasoning as dap-python.lua: dap.lua's mason-nvim-dap + -- ensure_installed triggers the install, but that's async - on a fresh + -- machine (or before it finishes) the entrypoint doesn't exist on disk + -- yet, so wire up the adapter once the install actually completes + -- instead of pointing it at a path that isn't there yet. + vim.notify( + "js-debug-adapter not installed yet - dap.lua's ensure_installed should be" + .. " installing it now (check :Mason); run :MasonInstall js-debug-adapter" + .. " if it doesn't show up there. Debugging will work once it's done.", + vim.log.levels.WARN + ) + registry:on("package:install:success", function(installed_pkg) + if installed_pkg.name == "js-debug-adapter" then + register() + end + end) + end +end + +return M diff --git a/neovim/.config/nvim/lua/config/keymaps.lua b/neovim/.config/nvim/lua/config/keymaps.lua index 66e97a0..65e3236 100644 --- a/neovim/.config/nvim/lua/config/keymaps.lua +++ b/neovim/.config/nvim/lua/config/keymaps.lua @@ -14,6 +14,18 @@ map("t", "", [[k]]) map("t", "", [[h]]) map("t", "", [[l]]) +-- Copy to clipboard +map("v", "y", '"+y') +map("n", "Y", '"+yg_') +map("n", "y", '"+y') +map("n", "yy", '"+yy') + +-- Paste from clipboard +map("n", "p", '"+p') +map("n", "P", '"+P') +map("v", "p", '"+p') +map("v", "P", '"+P') + -- Never use the arrow keys for _, key in ipairs({ "", "", "", "" }) do map({ "n", "i" }, key, "") diff --git a/neovim/.config/nvim/lua/config/options.lua b/neovim/.config/nvim/lua/config/options.lua index be614e1..1282850 100644 --- a/neovim/.config/nvim/lua/config/options.lua +++ b/neovim/.config/nvim/lua/config/options.lua @@ -34,3 +34,9 @@ opt.hlsearch = true opt.incsearch = true opt.ignorecase = true opt.smartcase = true + +-- Project-local config (.nvim.lua) is handled by a custom autocmd in +-- autocmds.lua instead of the core 'exrc' option: 'exrc' only checks the +-- literal cwd at startup, once, so it misses a project's .nvim.lua whenever +-- Neovim didn't start with cwd exactly there. Leave 'exrc' off to avoid +-- double-sourcing the same file via both mechanisms. diff --git a/neovim/.config/nvim/lua/config/project_run.lua b/neovim/.config/nvim/lua/config/project_run.lua new file mode 100644 index 0000000..40c1795 --- /dev/null +++ b/neovim/.config/nvim/lua/config/project_run.lua @@ -0,0 +1,151 @@ +-- Single-source-of-truth helper for project-local run/debug configs, meant +-- to be called once per config from a project's `.nvim.lua` (requires +-- `opt.exrc` - see options.lua - and trusting the file once via +-- `:help :trust`). One call registers both an overseer run task and a +-- matching nvim-dap debug config, so a project states its command once +-- instead of repeating it across a separate run-file and debug-file. +-- +-- Example .nvim.lua (script invocation): +-- require("config.project_run").python({ +-- name = "Run app", +-- program = vim.fn.getcwd() .. "/main.py", +-- args = { "--flag" }, -- optional, shared by both run and debug +-- }) +-- +-- Example .nvim.lua (module invocation, `python -m `): +-- require("config.project_run").python({ +-- name = "Run app", +-- module = "fastapi", +-- args = { "dev", "app" }, +-- }) +-- +-- This shows "Run app" in the rr picker (plain execution) and in +-- the dc picker (same script/module, under debugpy, breakpoints +-- included). If /.venv exists, both get VIRTUAL_ENV/PATH pointed at +-- it, same as `uv run` (or `source .venv/bin/activate`) would - and the +-- debug config additionally gets pythonPath set to that venv's interpreter, +-- since debugpy runs the script with the literal interpreter it's told +-- rather than resolving `python3` via PATH. +-- +-- Example .nvim.lua (Node, script invocation): +-- require("config.project_run").node({ +-- name = "Run app", +-- program = vim.fn.getcwd() .. "/index.js", +-- args = { "--flag" }, -- optional, shared by both run and debug +-- }) +-- +-- Example .nvim.lua (Node, `npm run