Skip to content

Wire LSP features: hover, go-to-definition, completions, symbols, outline#17

Closed
joewiz wants to merge 13 commits intoui-review-polishfrom
feature/lsp-integration
Closed

Wire LSP features: hover, go-to-definition, completions, symbols, outline#17
joewiz wants to merge 13 commits intoui-review-polishfrom
feature/lsp-integration

Conversation

@joewiz
Copy link
Copy Markdown
Owner

@joewiz joewiz commented Mar 13, 2026

Summary

Wires eXist-db's lsp:* XQuery module into the eXide frontend, adding five LSP-backed features. Depends on the feature/lsp-module branch in eXist-db/exist.

  • Hover tooltips — CM6 hoverTooltip extension calls lsp:hover() and renders function signatures and documentation when hovering over XQuery symbols
  • Go-to-definition — replaces AST-based lookup with lsp:definition() for accurate jump-to-source including imported modules
  • Function completions — replaces the old GET endpoint with lsp:completions() which includes user-defined local functions; prefix-filtered server-side; CM6 snippet templates generated from parameter names
  • Navigate → Symbollsp:symbols() powers the Quick Picker symbol list (Ctrl+Shift+O)
  • Outline panel — populated via lsp:symbols() with atomic assignment to prevent race-condition duplicates; click handler fixed to use editorUtils.gotoLine() with correct row/column; outline now activates correctly when split-pane mode is restored from localStorage

What Changed

  • modules/api/query.xqm — four new endpoints: POST /api/query/hover, POST /api/query/definition, POST /api/query/completions, POST /api/query/symbols
  • modules/api.json — OpenAPI routes for the four new endpoints
  • src/lsp-hover.js (new) — CM6 hoverTooltip extension; fetches hover data, renders signature + description
  • resources/css/lsp-hover.css (new) — tooltip styles with dark-mode support
  • src/editor.js — registers LspHover.extension() in the CM6 extension list
  • tools/bundle-cm6.js — exports hoverTooltip from the CM6 bundle
  • scripts/bundle.js — includes lsp-hover.js in the esbuild entry
  • index.html.tmpl — loads lsp-hover.css
  • src/xquery-helper.jsgotoDefinition uses lsp:definition(); gotoSymbol uses lsp:symbols(); createOutline uses lsp:symbols() with regex fallback on failure
  • src/xquery-completion.jsfetchFunctionCompletions calls POST /api/query/completions
  • src/outline.js — click handler uses editorUtils.gotoLine() with LSP row/column; removed redundant doc.functions = [] reset
  • src/preferences.js — activates outline in applyPreferences() when split-pane is restored from localStorage

Prerequisites

eXist-db must have the feature/lsp-module branch deployed, which provides lsp:hover, lsp:definition, lsp:completions, lsp:symbols, and lsp:diagnostics.

Test Plan

  • Hover over a function name → tooltip shows signature and documentation
  • Go to Definition on a local function → cursor jumps to declaration
  • Ctrl+Space mid-function-name → completions include built-ins and user-defined local functions
  • Navigate → Symbol (Ctrl+Shift+O) → all declared functions and variables listed
  • Outline panel (tabbed mode) → functions appear after clicking the outline tab
  • Outline panel (split-pane mode) → functions appear on startup without clicking the tab
  • Clicking an outline item → cursor jumps to correct line and column
  • No duplicate entries in outline after document save/validate
  • All features degrade gracefully when LSP module is not available

🤖 Generated with Claude Code

joewiz and others added 3 commits March 12, 2026 23:39
Registers four new POST routes under /api/query/ backed by the
lsp:* XQuery module added to eXist-db in feature/lsp-module:

- POST /api/query/hover       — function signature + docs at position
- POST /api/query/definition  — declaration location for symbol at position
- POST /api/query/completions — full-document completion list with CM6
                                snippet templates, filtered by prefix
- POST /api/query/symbols     — declared functions and variables with
                                line/column positions

query:compile already used lsp:diagnostics(); hover and definition
cast JSON number values to xs:integer before passing to lsp:hover()
and lsp:definition(). query:make-snippet() generates CM6 ${N:$param}
templates from LSP detail strings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hover tooltip (mouse hover over XQuery symbols):
- src/lsp-hover.js: new CM6 hoverTooltip extension; fetches
  /api/query/hover and renders signature + description
- tools/bundle-cm6.js: export hoverTooltip from CM6 bundle
- scripts/bundle.js: include lsp-hover.js in eXide bundle
- src/editor.js: register LspHover.extension() in buildExtensions()
- index.html.tmpl, resources/css/lsp-hover.css: tooltip styles

Go-to-definition (F3 / Navigate → Go to Definition):
- src/xquery-helper.js gotoDefinition(): POST /api/query/definition,
  jump to returned line/column; fall back to AST lookup on failure

Navigate → Symbol (symbol quick-picker):
- src/xquery-helper.js gotoSymbol(): POST /api/query/symbols,
  populate QuickPicker with compiler-accurate positions, jump on select;
  fall back to doc.functions on network error

Completions (Ctrl+Space):
- src/xquery-completion.js fetchFunctionCompletions(): POST
  /api/query/completions with full document text instead of GET
  /api/editor/completions with prefix+imports; server returns items
  including user-defined local functions alongside built-ins

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use lsp:symbols() to populate the outline instead of regex parsing,
  falling back to regex if the server call fails
- Assign doc.functions atomically to prevent duplicates from concurrent
  activate/validate events racing on the async fetch
- Fix outline click handler to use editorUtils.gotoLine() with the
  row/column from lsp:symbols() instead of passing a line number as a
  function name to gotoFunction()
- Activate the outline in applyPreferences() when split-pane mode is
  restored from localStorage, so the pane populates on startup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@joewiz
Copy link
Copy Markdown
Owner Author

joewiz commented Mar 13, 2026

Note on CI failures: This PR requires the lsp:* XQuery module from eXist-db core, added in eXist-db/exist#6130. CI will fail until that PR is merged into develop and a build including it is available. The LSP features have been manually verified end-to-end against a local eXist-db instance with the module deployed.

@joewiz joewiz mentioned this pull request Mar 13, 2026
joewiz and others added 10 commits March 13, 2026 23:47
…ll fixes

- Wire CM6 built-in completion sources for HTML (tag/attribute),
  CSS/Less (property/value), and JavaScript (local variables)
- Add JSON parse linting via jsonParseLinter
- Enable activateOnTyping so completions appear as you type
- Fix blank outline on tab switch by using ensureSyntaxTree to
  force Lezer parse completion, and deferring with requestAnimationFrame
- Fix duplicate outline entries by clearing doc.functions in updateOutline
- Render outline as nested <ul> tree for hierarchical modes (XML, JSON,
  Markdown) with graduated hover shading matching the collections pane
- Make both collections and outline panes horizontally scrollable
- Unify font styling between collections and outline panes
- Scroll to center of viewport when clicking outline items, with
  selection anchored at close tag so full element is highlighted

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add "Autocomplete as you type" checkbox in Editor preferences,
  backed by a CM6 Compartment for live toggling (default: on)
- Fix blank Font dropdown: Default option value now matches the
  stored preference string
- Widen preferences label column to 200px to prevent wrapping on
  longer labels like "Space before self-closing />"
- Replace bare <legend> sub-sections in Prettier fieldset with
  styled <h4 class="pref-subsection"> headings: top border
  separator, left indent, muted color (light + dark mode)
- Add more vertical breathing room between outer fieldsets

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Autocomplete called parseXQuery on every keystroke, which set
doc.lastValidation — tricking the CodeValidator into thinking
the document was already validated. The compile fetch never
re-fired, so server-side errors persisted in the status bar.

Fix: separate parse caching (doc.lastParsed) from validation
freshness (doc.lastValidation). Only the CodeValidator sets
lastValidation after the full parse + compile cycle completes.
Also re-trigger validation when the document changes during an
in-flight compile request.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…allback

- Add Toggle Diagnostics Panel (Cmd+Shift+D) using CM6's lint panel
- Center scroll on gotoLine/gotoDefinition/gotoSymbol navigation
- Add gotoSymbol support to all modes via prototype fallback in exec()
- XML outline now shows XPath signatures with positional predicates
  (e.g., /package/dependency[1]) for unique identification in QuickPicker
- Fetch registered module prefixes from server at startup via
  api/editor/modules instead of hardcoding eXist-db namespaces
- Add client-side hover fallback for local functions/variables when
  lsp:hover() returns nothing
- Add Cmd+Click go-to-definition support

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Brief gold flash on the target line when navigating via
go-to-definition, go-to-symbol, go-to-line, or Cmd+Click.
Uses a CM6 StateField with line decoration and CSS animation
that fades out over 1.2s. Works in both light and dark mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…vigation

24 new E2E tests across 3 specs:

diagnostics_panel_spec (5 tests):
- Opens/toggles lint panel via Navigate menu
- Shows diagnostics for invalid XQuery
- Clears diagnostics when code is fixed
- Error pill disappears after fixing compile errors

native_autocomplete_spec (7 tests):
- HTML tag and attribute completions
- CSS property completions
- JavaScript local variable completions
- JSON parse linting (error/valid)

outline_navigation_spec (12 tests):
- XML nested tree outline with XPath signatures and hints
- XML/JSON gotoSymbol via QuickPicker
- CSS selector and JS function outlines
- Markdown heading outline
- Navigation flash highlight on gotoLine

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…crumb

- Enable highlightSelectionMatches: selecting a word highlights all
  occurrences in the document with a gold background
- Export selectNextOccurrence (Cmd+D) for adding next match to
  multi-cursor selection (already in searchKeymap)
- Add scope breadcrumb in status bar for XQuery mode: shows the
  AST path at the cursor position (e.g., FunctionDecl/FLWORExpr)
- Style selection matches for both light and dark mode

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The outline filter now hides the parent <li> element rather than
the <a> link, so the test assertion needs to check <li> display.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- editor.js: Cmd+Click (Mac) / Ctrl+Click (other) triggers gotoDefinition.
  Pointer cursor shown when modifier key is held.
- xquery-helper.js: when lsp:definition returns a "uri" field (cross-module
  definition), open the target module in a new tab via $doOpenDocument.
- eXide.css: .cm-goto-clickable cursor style.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@joewiz joewiz closed this Mar 15, 2026
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.

1 participant