Skip to content

feat: discovery-first tool resolution (make Mason optional)#21

Open
charliie-dev wants to merge 4 commits into
mainfrom
feat/discovery-first-tooling
Open

feat: discovery-first tool resolution (make Mason optional)#21
charliie-dev wants to merge 4 commits into
mainfrom
feat/discovery-first-tooling

Conversation

@charliie-dev

Copy link
Copy Markdown
Owner

Feasibility POC — RFC ayamir/nvimdots#1293

Implements the "separate tool discovery from tool installation" idea from this comment: Mason becomes one installer backend, not a hard requirement. On FreeBSD/NixOS/etc. — where Mason's prebuilt binaries don't run — system-provided tools are used directly, with no manual symlinking and no startup notification spam.

No new toggle, no OS detection. Behaviour is driven purely by availability.

Resolution model (per tool)

1. on $PATH (system / Mason) ─────────► use it
2. not on $PATH, Mason has a package ─► install, use next launch
3. neither ───────────────────────────► aggregate into ONE "please install" warning

Applied to LSP, DAP, formatters, and linters. conform/nvim-lint already resolve from $PATH, so only their install gating changed.

Changes

Area File What
Helper modules/utils/tools.lua (new) $PATH check, Mason spec.bin resolver, per-subsystem warning aggregator (one message, not N)
LSP mason-lspconfig.lua, lsp.lua, settings.lua Cascade resolver driven by lsp_deps; external_lsp_deps merged into lsp_deps (auto-classified via the mason-lspconfig mapping — no more deciding which list a server goes in)
Formatter/Linter mason.lua Skip install when the package's binary is already on $PATH
DAP dap/init.lua Self-drive over dap_deps instead of mason-nvim-dap's installed-only handler gating

settings.lua

  • lsp_deps: absorbs nixd / nil_ls / shuck
  • external_lsp_deps: removed
  • formatter_deps / linter_deps / dap_deps / treesitter_deps: unchanged

Verification

  • stylua + selene: clean.
  • Headless API probe (14/14): confirmed mason-registry.is_installed, mason-lspconfig lspconfig_to_package, vim.lsp.config[name].cmd[1] (incl. nil_lsnil), pkg.spec.bin, and all mason-nvim-dap.mappings.*.
  • Integration: opening a Lua file attaches lua_ls via the new resolver, no errors.

Known POC limitations

  • DAP $PATH detection relies on the Mason package's declared binaries (nvim-dap has no uniform command registry); adapters with an explicit client config resolve their own binary via vim.fn.exepath.
  • A server whose nvim-lspconfig cmd is a function (rare) can't be $PATH-probed; it falls back to the Mason-package check.
  • Not yet tested on an actual BSD/NixOS host — that's the next feasibility step.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a discovery-first tool resolution model so that tools already available on $PATH (system-provided or Mason-provided) are used directly, while Mason becomes an optional installer backend rather than a hard runtime gate. This supports environments like NixOS/FreeBSD where Mason-installed binaries may be unavailable or undesirable.

Changes:

  • Add shared helpers for $PATH probing, Mason spec.bin extraction, and aggregated “missing tools” warnings.
  • Rework LSP and DAP setup to be driven by desired dependency lists with discovery-first resolution and deferred installs.
  • Update Mason bootstrap for formatters/linters to only install when the tool isn’t already on $PATH, aggregating missing-tool warnings.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
lua/modules/utils/tools.lua New helper module for executable discovery + aggregated missing-tool warnings.
lua/modules/configs/tool/dap/init.lua Switch DAP setup to discovery-first resolution instead of mason-nvim-dap’s installed-only handler gating.
lua/modules/configs/completion/servers/shuck.lua Update server comment to reflect the new discovery-first resolution model.
lua/modules/configs/completion/mason.lua Only install formatter/linter packages when not already available on $PATH; aggregate missing warnings.
lua/modules/configs/completion/mason-lspconfig.lua Drive LSP setup via discovery-first resolution + deferred installs, using mason-lspconfig mappings.
lua/modules/configs/completion/lsp.lua Remove external_lsp_deps wiring; rely on centralized discovery-first LSP setup.
lua/core/settings.lua Collapse external/system LSP list into unified lsp_deps list with discovery-first semantics.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lua/modules/configs/completion/mason-lspconfig.lua
Comment thread lua/core/settings.lua Outdated
Comment thread lua/modules/configs/tool/dap/init.lua

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Comment thread lua/modules/configs/completion/mason-lspconfig.lua
Comment thread lua/modules/configs/tool/dap/init.lua Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Comment thread lua/modules/configs/tool/dap/init.lua

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Comment thread lua/core/settings.lua Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comment thread lua/modules/utils/tools.lua Outdated
Comment thread lua/modules/configs/tool/dap/init.lua Outdated
Comment thread lua/modules/configs/tool/dap/init.lua Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Comment thread lua/modules/configs/completion/mason-lspconfig.lua
Comment thread lua/modules/configs/completion/mason.lua
Comment thread lua/core/settings.lua Outdated
Comment thread lua/modules/utils/tools.lua Outdated
Comment thread lua/modules/utils/tools.lua Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Comment thread lua/modules/utils/tools.lua Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Comment thread lua/modules/utils/tools.lua

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Comment thread lua/modules/configs/tool/dap/init.lua Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Comment thread lua/modules/utils/tools.lua Outdated
Comment thread lua/modules/configs/tool/dap/init.lua

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Comment thread lua/modules/utils/tools.lua
Comment thread lua/modules/configs/tool/dap/clients/delve.lua Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread lua/modules/configs/tool/dap/clients/delve.lua
@charliie-dev charliie-dev force-pushed the feat/discovery-first-tooling branch from 2c843f0 to b6144a1 Compare July 2, 2026 09:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread lua/core/settings.lua Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Comment thread lua/modules/configs/completion/mason-lspconfig.lua
Comment thread lua/modules/configs/tool/dap/clients/delve.lua Outdated
Comment thread lua/modules/configs/tool/dap/clients/python.lua Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread lua/modules/configs/tool/dap/clients/delve.lua Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread lua/modules/plugins/tool.lua Outdated
Introduce modules/utils/tools.lua: a shared layer that treats Mason as one
installer backend rather than a hard requirement. Provides any_executable
($PATH probe), package_binaries (a package's declared binaries), and
missing_collector — a per-subsystem aggregator that reports tools which could
not be set up in a single deferred warning.

The collector has two buckets: mark (a real tool that isn't available — install
it) and mark_unknown (a name the installer registry doesn't recognize — a typo
or outdated name to fix in config), rendered as separate cause-appropriate
sections. track() performs the async install itself under pcall, so a package
whose install() errors or returns a bad handle is recorded as missing instead
of aborting the caller's resolution loop; its "closed" handler runs on the main
loop via vim.schedule_wrap (Mason fires it from a fast event context) and
pcalls recheck() so a throwing recheck can't leave the warning permanently
suppressed.
Drive LSP server setup discovery-first via the shared tools helper: a server
already on $PATH (system / Nix / Mason) is configured as-is; otherwise Mason
installs it when it ships a package; a name the registry doesn't recognize is
surfaced as an unknown-name config error. Make the mason-registry requires
optional so a Mason-less setup still configures system-provided servers.

Fold external_lsp_deps into lsp_deps (shuck now lives there) and clarify that
nixd / nil_ls are resolved from $PATH first, else Mason-installed, since the
resolver no longer needs a separate "configure but don't install" list.
Only install formatters/linters that aren't already on $PATH, so systems that
provide their own tools (NixOS/BSD) aren't nagged every startup. Unknown Mason
package names (typo / removed) are reported via the collector's mark_unknown
bucket so the warning points at the config, not a manual install.
Resolve debug adapters discovery-first through the shared helper and make the
mason-registry / mason-nvim-dap requires optional, so a Mason-less setup still
configures adapters that resolve their own binary (client configs / $PATH).

Configure an adapter as soon as it has a client config (its own discovery-first
resolver) rather than waiting on the Mason install, so e.g. python debugging via
system debugpy works this session. On a Mason-less setup, best-effort validate a
table adapter's resolved command and surface it as missing if empty/not on $PATH
(e.g. codelldb via vim.fn.exepath). Make the delve client Mason-agnostic: guard
mason-registry, only auto-install when go-debug-adapter is neither installed nor
on $PATH, return after kicking off an install, and error (marking delve missing)
when the bundle or a `node` runtime can't be resolved. Resolve debugpy without
Mason in the python client, probing python interpreters instead of assuming one.
Resolve Mason's install root via mason.settings (with a $MASON fallback) rather
than the env var alone.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants