feat: add live-cycling LSP completion
This commit is contained in:
+13
-5
@@ -69,6 +69,7 @@ The built-in `gt`/`gb` sequences move to the first/last line in Normal and Visua
|
||||
| Normal | `follow_link` |
|
||||
| Normal | `jump_back`, `jump_forward` |
|
||||
| Normal | `lsp.definition`, `lsp.diagnostics`, `lsp.hover` |
|
||||
| Insert | `lsp.completion` |
|
||||
| Normal | `search`, `paste_before`, `paste_after` |
|
||||
| Normal | `paste_system_before`, `paste_system_after` |
|
||||
| Normal, Visual | `select`, `select_linewise`, `search_next`, `search_previous` |
|
||||
@@ -127,7 +128,7 @@ config.bind "ctrl+h", nil, mode: config.modes.tree
|
||||
|
||||
Ctrl+h is **not** a Backspace alias or default deletion key in any mode. Raw Ctrl+h (0x08) and Backspace (DEL/0x7f) are distinct, as are CSI-u events. In the tree it navigates in NORMAL and INSERT without deleting query text; it never deletes file-buffer Insert text by default. Explicit `config.core.backspace` bindings remain available if desired.
|
||||
|
||||
Ctrl+j is distinct from Enter: in the TUI's raw mode, LF is Ctrl+j and CR is Enter; CSI-u control events also work. No enhanced-terminal negotiation is required. Ctrl+m remains an Enter alias. Outside lists, existing editing bindings are unchanged: Ctrl+k still clones above in Normal/Visual, and explicit Ctrl+j defaults insert a newline in Insert or submit Command/Search prompts. Enter and Ctrl+j can now be rebound independently.
|
||||
Ctrl+j is distinct from Enter: in the TUI's raw mode, LF is Ctrl+j and CR is Enter; CSI-u control events also work. No enhanced-terminal negotiation is required. Ctrl+m remains an Enter alias. Outside completion and selection lists, Ctrl+k still clones above in Normal/Visual, and Ctrl+j defaults to newline in Insert or submit in Command/Search. While completion is open, Ctrl+j/k cycles candidates; Enter always closes completion and inserts a newline. Enter and Ctrl+j can be rebound independently outside the completion cycle.
|
||||
|
||||
## Leader key
|
||||
|
||||
@@ -158,6 +159,7 @@ Vamp.configure do |config|
|
||||
config.bind "leader d", config.core.lsp.definition
|
||||
config.bind "leader D", config.core.lsp.diagnostics
|
||||
config.bind "K", config.core.lsp.hover
|
||||
config.bind "ctrl+n", config.core.lsp.completion, mode: config.modes.insert
|
||||
end
|
||||
```
|
||||
|
||||
@@ -169,7 +171,7 @@ Install Solargraph yourself with `gem install solargraph` in the project's Ruby
|
||||
|
||||
**Python (Astral):** install [ty](https://docs.astral.sh/ty/editors/) and [Ruff](https://docs.astral.sh/ruff/editors/setup/) yourself, for example with `uv tool install ty` and `uv tool install ruff`. The Python preset sends the same documents to both servers, uses ty for hover/definition, and merges type errors with Ruff lint diagnostics. Clearing or losing one server preserves the other's diagnostics. Formatting and code actions remain unsupported by Vamp.
|
||||
|
||||
Use `servers` to customize the stack independently; order selects the hover/definition server:
|
||||
Use `servers` to customize the stack independently; order selects the hover/definition/completion server:
|
||||
|
||||
```ruby
|
||||
config.lsp["python"] = {
|
||||
@@ -188,13 +190,13 @@ config.lsp["python"] = {
|
||||
|
||||
**uv remains optional project tooling.** Run project setup/synchronization yourself; [ty discovers an existing `.venv`](https://docs.astral.sh/ty/reference/configuration/#python) without a uv launcher. Vamp neither runs `uv sync` nor changes dependencies/lockfiles. The default ty preset sets `experimental.useUv: "off"` so inherited `TY_UV` cannot enable ty's [experimental environment-management integration](https://docs.astral.sh/ty/reference/editor-settings/). Ruff's initialization options default to `{}`. When replacing ty's initialization options, retain that flag if you want the same policy.
|
||||
|
||||
Servers start lazily only when a matching buffer opens. Extension matching is case-sensitive; if enabled languages overlap, the first language in sorted key order wins. All matching servers in that language run, and the first handles hover/definition, semantic highlighting, and the diagnostic-status command without fallback to sibling servers. Each server/project root gets one worker, with at most 16 configured servers and 16 server/project keys; Python uses two slots. Start vamp from your project root: its startup working directory is the workspace; automatic root discovery is not implemented.
|
||||
Servers start lazily only when a matching buffer opens. Extension matching is case-sensitive; if enabled languages overlap, the first language in sorted key order wins. All matching servers in that language run, and the first handles hover/definition/completion, semantic highlighting, and the diagnostic-status command without fallback to sibling servers. Each server/project root gets one worker, with at most 16 configured servers and 16 server/project keys; Python uses two slots. Start vamp from your project root: its startup working directory is the workspace; automatic root discovery is not implemented.
|
||||
|
||||
See [native LSP architecture](architecture.md#native-lsp) for synchronization and worker behavior.
|
||||
|
||||
`:lsp.definition` or the configured Space d binding requests a definition at the primary caret, once regardless of selection count. Both Location and LocationLink results are supported; multiple results use the first. Local-file navigation reuses loaded buffers without overwriting unsaved text. LSP UTF-16 positions and percent-encoded file URIs are translated to validated grapheme coordinates. Navigation is ignored if its source buffer, revision, caret, or latest request has changed.
|
||||
|
||||
For programmatic bindings, `config.core.lsp` exposes immutable Normal-mode Action objects: `definition`, `diagnostics`, and `hover`. Each routes to the same native implementation as its Ex command; no LSP keys are bound by default. These actions are also available in the command palette. The namespace is distinct from `config.lsp[language_id]` server configuration.
|
||||
For programmatic bindings, `config.core.lsp` exposes immutable Normal-mode Action objects `definition`, `diagnostics`, and `hover`, plus the **Insert-only** `completion` Action. Normal actions route to their corresponding Ex commands and have no default keys. Completion defaults to Insert Ctrl+n; override or disable it using an Insert binding. It requests directly without leaving Insert or committing pending typing; there is no Normal `:lsp.completion` command. These actions are also available in the command palette according to mode eligibility. The namespace is distinct from `config.lsp[language_id]` server configuration.
|
||||
|
||||
Interactive LSP commands use dotted names (`:lsp.hover`, `:lsp.definition`, `:lsp.diagnostics`). The existing whitespace separator keeps the whole dotted name separate from arguments. Current LSP commands take no arguments.
|
||||
|
||||
@@ -204,8 +206,14 @@ Diagnostics appear as severity-colored gutter numbers and text underlines; the p
|
||||
|
||||
Hover accepts plaintext/Markdown MarkupContent and string/code MarkedString forms, including arrays. The popup grows up to 100 columns and 24 rows, clamped to the available document workspace and content height. Multiline content and Markdown markers remain visible, with the same Markdown syntax colors as document buffers; named fenced code blocks use their language's bundled highlighter. Highlighting is cached across scrolling and redraws. Horizontal scrolling exposes long lines without splitting graphemes. Missing/unsupported/invalid hover results report a message without changing text, selections, or undo history. Content is bounded to 4 MiB and terminal controls are sanitized.
|
||||
|
||||
Completion is manual and uses only the primary insertion caret. Ctrl+n requests it; the first candidate replaces text immediately. While the list is open Ctrl+n/Ctrl+j selects next and Ctrl+k previous, including an Original text row that restores the original document and carets. Other keys close it and act normally, with no accept key: Enter inserts a newline, Tab inserts a tab, and Escape returns to Normal keeping the displayed candidate. Secondary carets are translated, not completed independently. Cycling belongs to the pending Insert undo group; repeat records only the final chosen edits. See [editing behavior](editing.md#manual-lsp-completion).
|
||||
|
||||
The first assigned server must advertise a completion provider. Vamp handles item arrays and CompletionList results, plain text, TextEdit, InsertReplaceEdit (using its replacement range), supported edit-range/format/mode defaults, and atomic additionalTextEdits in the same document. Insert-only fallback text replaces the identifier prefix before the caret; `filterText` and stable `sortText`/label ordering are honored. All edit coordinates are validated at UTF-16 and grapheme boundaries against the immutable request document; malformed or overlapping edits report a completion error without retiring a healthy server. Aggregate completion text is bounded to 4 MiB. Pending replies cannot reopen completion after intervening input, source changes, superseding requests, or modal overlays.
|
||||
|
||||
There are no automatic triggers, snippets, commit characters, server commands, indentation adjustment, or completion-item resolve requests. Items requiring snippet expansion, commands, or indentation adjustment are omitted rather than partly applied. Server-specific availability depends on the installed server's advertised capabilities; configuring a preset does not guarantee completion support.
|
||||
|
||||
Semantic highlighting is **enabled automatically** when the first server advertises [LSP semantic tokens](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens). No additional configuration or binding is needed. Full-document requests are preferred; range-only servers receive a whole-document range request. Token colors override Tree-sitter where recognized; unsupported servers, unknown custom token types, missing tokens, and failed replies retain syntax highlighting. Text/path changes clear old semantic colors immediately, and stale replies cannot restore them. Same-text refreshes keep the current overlay until the replacement arrives.
|
||||
|
||||
rust-analyzer and ty support semantic tokens. Solargraph 0.61.0 and Ruff do not; Ruby therefore retains Tree-sitter colors with the Solargraph preset, while Python uses ty's tokens and Ruff's diagnostics. Declaration/definition modifiers use bold, deprecated symbols use strikethrough, and readonly variables/parameters/properties use italics without changing their role's color. Diagnostics, search, selections, and carets retain their existing styling precedence.
|
||||
|
||||
Native LSP currently provides synchronization, diagnostics, go-to-definition, hover, and semantic highlighting—not completion, rename, formatting, code actions, or workspace edits. Semantic token deltas, dynamic registration, and partial-result streaming are not implemented.
|
||||
Native LSP currently provides synchronization, diagnostics, go-to-definition, hover, manual completion, and semantic highlighting—not rename, formatting, code actions, or general workspace edits. Semantic token deltas, dynamic registration, and partial-result streaming are not implemented.
|
||||
|
||||
Reference in New Issue
Block a user