eXist-aware completion, hover, parameter hints & exist: resource handling#12
Merged
Conversation
…orrupted
The exist: URL connection fetched resources via the JSON envelope and re-encoded
the text content as UTF-8, which corrupts binary resources — so images referenced
from an Author-mode document showed "Unsupported image format". Read via the
path-in-URL streaming endpoint (GET /api/db/resource/{path}) instead, returning
the resource's raw bytes and the server's Content-Type. ExistClient gains
getResourceBytes; 404 still maps to FileNotFoundException for the Missing-File
flow.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…opened Auto-validation pushed results unconditionally, so opening/validating a problem-free exist: XQuery popped up an empty "eXist-db" Results tab. Only push when there are problems (or to clear ones previously shown). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Trigger eXist-aware completion with Ctrl+Space and Cmd/Ctrl+Alt+Slash (bound on each text editor as it opens / switches to Text mode). - Two-pane completion popup like Oxygen's built-in: the list shows the name with a kind icon (function/variable), and a side panel shows the selected proposal's signature and documentation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…longer executed Reading every exist: resource via the raw streaming endpoint broke .xq/.xqm: that endpoint forwards to eXist's REST servlet, which executes an XQuery main module (HTTP 500) or rejects a library module instead of returning source. Use the JSON envelope's UTF-8 content for text resources (correct source) and the raw-bytes endpoint only when the resource is flagged binary. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a live type-to-filter field to the eXist completion popup (eXide behavior): the field is seeded with the local name already typed before the caret, and narrows the proposal list by local-name prefix as you type. Down/Up steer the list, Enter accepts, Escape closes — all while the field keeps focus. Also bind the completion/run shortcuts on the WHEN_ANCESTOR_OF_FOCUSED_ COMPONENT input map in addition to WHEN_FOCUSED, in case Oxygen delegates focus to a child of the text component (helps Ctrl+Space reach us where it isn't already consumed at the OS level), and keep the run/completion shortcuts scoped to XQuery editors only so they don't shadow Ctrl+Space in XML and other editors. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the two editor entries ("Run in Results View (eXist)", "Run
Current Editor (eXist)") and the toolbar button with a single
"Evaluate Query with eXist-db" action that routes results to the
destination chosen in Configure eXist-db Connections (browse vs. new
editor). The action — and thus the toolbar button and menu entry — is
enabled only when running makes sense: the active editor is an XQuery
editor, or it has a text selection (tracked via a caret listener and
editor activation). Cmd/Ctrl+Enter is rebound to it.
Also rename the "eXist Completion" menu entry to "Content Completion
(eXist-db)", and make ExistAutoValidator.isXQuery public so the action
can reuse the XQuery-type check.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…point eXist stores XQuery modules as binary documents, so the JSON envelope's `binary` flag is true for .xq/.xqm even though their content is textual source. The previous fix branched on `binary` alone and so fetched them from the raw streaming endpoint — which *executes* the module on GET (HTTP 500: "No function call details… Library Module", or running a main module) instead of returning its source. Branch on whether the mime-type is textual instead: read XQuery/XML/JSON/ text from the JSON envelope's content, and fetch only genuinely-binary resources (images, PDFs, fonts) as raw bytes. Adds MimeTypes.isTextual and falls back to the extension's mime-type when the server omits one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…mpletion
Accepting e.g. util:wait inserts util:wait() but left the caret after the
closing paren. Drop the caret just inside the parentheses (template-style)
when the inserted text contains "(", so the user can type arguments
straight away; non-function proposals still leave the caret at the end.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- "Evaluate Query with eXist-db" -> "Evaluate Query (eXist-db)" - "Go to Definition (eXist)" -> "Go to Definition (eXist-db)" - "eXist Quick Documentation" -> "Function Documentation (eXist-db)" (it shows eXist's hover signature + docs for the symbol under the caret) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Override F1 in XQuery editors to show eXist's function documentation for the symbol under the caret, instead of Oxygen's default F1 (which opens the XQuery help page in a browser). - Render the hover as a small HTML card — a bold monospace signature above a sans-serif description — replacing the plain text area, closer to eXide's inline F1 doc. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…pload Binary resources (images, PDFs, fonts) were round-tripped through the JSON envelope's text content, corrupting them. Centralize a binary-correct read in ExistClient.readResource (raw bytes for genuinely-binary types, UTF-8 content for textual ones — including XQuery, which eXist flags as binary but whose source must not run through the module-executing streaming endpoint), and add ExistClient.putResourceBytes (a binary-safe streaming PUT). Apply both to: - Download to ~/Downloads (was writing text bytes for binaries), - cross-server drag-and-drop copy (was round-tripping through text), - file upload (previously skipped binary files entirely — now stored). ExistURLConnection now reuses readResource, deduplicating the open path. Verified end-to-end: a PNG round-trips byte-identical and .xqm still opens as source. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The input-map binding couldn't beat Oxygen's global F1=Help menu accelerator. Use a KeyEventDispatcher, which sees the key before menu accelerators: when an XQuery editor's text component is focused, F1 fires eXist Function Documentation and the event is consumed so Help doesn't also open; otherwise F1 falls through to Oxygen unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nature-help)
Consume existdb-openapi #44's richer language-service shapes:
- Hover `contents` is now LSP MarkupContent ({kind:"markdown", value}). Parse
the Markdown and render it as a rich card via a new dependency-free
MarkdownRenderer (fenced code → monospace signature, **bold** sections,
`-` bullets, inline `code`), so Function Documentation shows the full
Parameters / Returns the server provides — replacing the hand-rolled
flat-text formatting.
- Add ExistClient.signatureHelp + a SignatureHelpAction "Parameter Hints
(eXist-db)": a non-focus-stealing popup showing the enclosing call's
signature with the active parameter bolded. It pops automatically as you
type "(", ",", ")" and can be re-summoned via Cmd/Ctrl+Shift+Space or the
context menu.
Verified against the integration server (#42 + #44 on :18081): hover
renders the full card; signature-help tracks the active parameter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Render the hover's signature/code block as a wrapping monospace block and disable the popup's horizontal scrollbar, so a long signature reflows to the popup width instead of spilling off the right edge. - Use "eXist-db" (not "eXist") in the user-facing status/error messages for hover, completion, and query results, matching the menu/UI naming. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
existdb-openapi #45 returns function completions as LSP snippets
(insertTextFormat 2), e.g. util:log(${1:$priority}, ${2:$message}). Add a
dependency-free SnippetExpander that expands ${n:default}/${n}/$n/choices
and the \$ \} \\ escapes, and have completion insert the expanded text and
select the first argument so the user can type over it — instead of
inserting the raw ${...} markers. Non-snippet proposals keep the prior
caret-inside-parens behavior. Full Tab-cycling between stops is a later
enhancement.
ExistClient.Completion now carries insertTextFormat (with isSnippet()).
Verified against the integration server (#42 + #44 + #45 on :18081).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The signature-help popup was positioned above the caret's line, so a call on the first line (e.g. typing util:log( at the top of a document) put the hint off-screen above the editor — it appeared to do nothing. Fall back to below the caret line when the above position would be above the component's top edge. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…edback The signature-help hint was wired to hide on the editor's focusLost — but the popup itself can take focus when shown, so the editor lost focus and the hint hid itself the instant it appeared (nothing visible). Remove that self-dismissing listener; the hint is already re-evaluated/closed on the next relevant keystroke. Also give the manual trigger (menu / shortcut) status feedback — "no function call at the caret", a connect prompt, or the error — so an empty result no longer looks like a no-op. The auto-trigger while typing stays silent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Swing's default <code> renders smaller than the 11px body text, so in the
variable-type hover card ("$x as xs:integer") the surrounding "as" looked
oversized. Render inline `code` as an explicit 11px monospace span so the
sizes match.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
signature-help needs the exact 0-based column (the position right after the
call's "("), but Oxygen's getColumnOfOffset()-1 produced an off-by-one, so
the server found no enclosing call and returned null ("no function call at
the caret") — even though the same text resolved fine when called directly.
Hover tolerated the error by snapping to the surrounding token; signature-
help doesn't. Compute line/column directly from the caret offset and text
instead.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…Xist-db)" The action shows hover docs for any symbol (a function's signature, a variable's type — LSP textDocument/hover), not just functions, so the narrower name was misleading. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…cus is lost The signature-help popup is a heavyweight, always-on-top window, and with the focus-loss listener gone it never dismissed — it lingered above other windows after the caret moved off the function. Restore dismissal: a caret listener re-evaluates while a hint is up (refreshing the active parameter and closing when the caret leaves the call), and a focus listener hides it when the editor loses focus — ignoring transient focus loss (to a popup/ menu) so the hint can't dismiss itself. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Set each action's accelerator so the contextual menu displays its shortcut (completion advertises the reliable ⌥⌘/, since macOS eats ⌃Space), and order the entries by the typical flow while writing a query: Content Completion, Parameter Hints, Hover Documentation, Go to Definition, Evaluate Query. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The component focus listener ignores transient focus loss (so the popup can't self-dismiss), but switching apps (e.g. Apple menu → About This Mac) is exactly a transient loss, so the hint lingered above other apps. Also hide when the editor's top-level window loses focus — a precise signal for leaving the window/app that a non-focusable popup doesn't trigger on its own appearance. The window-focus listener is attached while a hint is shown and removed when it hides. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
[This PR was co-authored with Claude Code. -Joe]
Summary
The eXist-aware language-service layer for XQuery editors — content completion, function documentation, query evaluation — plus correct, lossless reading and writing of
exist:resources (the fix that makes opening.xq/.xqmwork and stops binary corruption). Stacked on the pane-polish PR; GitHub will retarget this tomainonce that merges.What changed
exist:resource reading & writing (text vs binary)binaryflag is true for.xq/.xqmeven though their content is text. Reading those from the raw streaming endpoint executed the module on GET (the "No function call details… Library Module" / OPERATION 500s). Resources are now read by whether their mime-type is textual (application/xquery,text/*, XML/JSON): text comes from the JSON envelope's UTF-8 content, and only genuinely-binary types (images, PDFs, fonts) are fetched as raw bytes.ExistClient.readResource(raw bytes for binary, UTF-8 content for text) and a binary-safe streaming PUT (putResourceBytes) fix three paths that previously round-tripped binaries through text and corrupted them: download to~/Downloads, cross-server drag-and-drop copy, and file upload (which used to skip binary files entirely — they now upload). Verified end-to-end: a PNG round-trips byte-identical and.xqmopens as intact source.exist:XQuery file is opened.Content completion
util:→ allutil:functions, thenw→util:wait). Down/Up steer, Enter accepts, Escape closes.util:log(${1:$priority}, ${2:$message})); accepting one inserts the expanded call and selects the first argument to type over (a dependency-freeSnippetExpanderhandles${n:default}/${n}/$n/choices and\$ \} \\). Plain (non-snippet) proposals fall back to dropping the caret inside().Query evaluation
Function documentation (F1) — rich, from LSP Markdown hover
KeyEventDispatcherthat fires only while an XQuery editor is focused and otherwise leaves F1 to Oxygen.MarkupContent(Markdown) hover: a monospace signature, the description, a Parameters list (each$name(type)— doc), and Returns:. A small dependency-freeMarkdownRendererconverts the Markdown to the Swing HTML the popup shows; long signatures wrap rather than scroll. Also covers variable references (e.g.$x→xs:integer) via #44's variable-type hover. (Function hover covers eXist extension modules —util:,xmldb:, imported DB modules — not built-infn:.)Parameter hints (signature-help)
/api/langservice/signature-help. It pops automatically as you type(,,,)(advancing the highlight, closing when you leave the call) and can be re-summoned via Cmd/Ctrl+Shift+Space or the context menu.Menu labels
Test plan
mvn test— 78 unit tests (incl.MimeTypes.isTextualtext/binary, hover Markdown parsing, signature-help parsing,MarkdownRenderer,SnippetExpander).xq/.xqmopen as source; PNG download/upload/copy round-trips byte-identical; hover renders the full Parameters/Returns card and variable types; signature-help tracks the active parameter (incl. mid-typing and overloads); completions expand snippetsutil:log(and leaves Help elsewhere); hover on a$varshows its type; parameter hints pop while typing a call; binary image opens/downloads intactDependency / coordination
fn:functions is a known upstream item; the plugin degrades gracefully (shows nothing rather than erroring).