From 5409755b71f8ece8025bfe9440318734d952acab Mon Sep 17 00:00:00 2001 From: Andy Bunce Date: Wed, 8 Oct 2025 22:12:48 +0100 Subject: [PATCH] [add] completion typedefs --- webapp/lsp/etc/capabilities.json | 4 +- webapp/lsp/jsonrpc.xqm | 4 +- webapp/lsp/lsp-text.xqm | 4 +- webapp/lsp/lsp-typedefs.xqm | 233 ++++++++++++++++++++- webapp/lsp/providers/completions.xqm | 7 + webapp/static/clients/codemirror/grail.css | 4 + 6 files changed, 250 insertions(+), 6 deletions(-) create mode 100644 webapp/lsp/providers/completions.xqm diff --git a/webapp/lsp/etc/capabilities.json b/webapp/lsp/etc/capabilities.json index 2b4887f..ba6a2d3 100644 --- a/webapp/lsp/etc/capabilities.json +++ b/webapp/lsp/etc/capabilities.json @@ -14,7 +14,7 @@ ] }, "hoverProvider": true, - "documentSymbolProvider": false, + "documentSymbolProvider": true, "documentRangeFormattingProvider": false, "colorProvider": false, "foldingRangeProvider": false, @@ -22,7 +22,7 @@ "documentLinkProvider": {}, "serverInfo": { "name": "XQuery 4.0b Language Server", - "version": "0.0.1" + "version": "0.0.2" } } } \ No newline at end of file diff --git a/webapp/lsp/jsonrpc.xqm b/webapp/lsp/jsonrpc.xqm index e6df36f..4898e68 100644 --- a/webapp/lsp/jsonrpc.xqm +++ b/webapp/lsp/jsonrpc.xqm @@ -90,8 +90,8 @@ as map(*) } }; -(:~ rpc response to $json msg :) -declare function rpc:result($json as map(*),$result) +(:~ rpc response to $json msg, if result empty just acknowledge :) +declare function rpc:result($json as map(*),$result:=()) as map(*) { map{ diff --git a/webapp/lsp/lsp-text.xqm b/webapp/lsp/lsp-text.xqm index 18eee32..bd0e60d 100644 --- a/webapp/lsp/lsp-text.xqm +++ b/webapp/lsp/lsp-text.xqm @@ -8,6 +8,7 @@ import module namespace rpc = 'rpc' at 'jsonrpc.xqm'; import module namespace lspt = 'lsp-typedefs' at 'lsp-typedefs.xqm'; import module namespace pos="lsp/position" at "position.xqm"; import module namespace syms="lsp/symbols" at "providers/documentSymbols.xqm"; +import module namespace comp = 'lsp-completions' at "providers/completions.xqm"; declare variable $lsp-text:methods:=map{ "textDocument/didOpen": lsp-text:didOpen#1, @@ -61,7 +62,8 @@ function lsp-text:completion($json as map(*)) as map(*)? { let $doc:=$json?params?textDocument?uri - let $result:=() + let $context:=$json?params?context (:{"triggerCharacter":":","triggerKind":2.0e0}:) + let $result:=comp:list($context) return rpc:result($json,$result) }; diff --git a/webapp/lsp/lsp-typedefs.xqm b/webapp/lsp/lsp-typedefs.xqm index 96e4897..aebced9 100644 --- a/webapp/lsp/lsp-typedefs.xqm +++ b/webapp/lsp/lsp-typedefs.xqm @@ -108,5 +108,236 @@ declare record lspt:Diagnostic( code? as xs:string, source as xs:string:="xquery" ); - declare type lspt:TraceValue as enum( 'off' , 'messages' , 'verbose'); + +(: -----------------completions ------------------:) + +(: + The kind of a completion entry. :) + +declare variable $lspt:CompletionItemKindMap:= { + "Text": 1, + "Method": 2, + "Function": 3, + "Constructor": 4, + "Field": 5, + "Variable": 6, + "Class": 7, + "Interface": 8, + "Module": 9, + "Property": 10, + "Unit": 11, + "Value": 12, + "Enum": 13, + "Keyword": 14, + "Snippet": 15, + "Color": 16, + "File": 17, + "Reference": 18, + "Folder": 19, + "EnumMember": 20, + "Constant": 21, + "Struct": 22, + "Event": 23, + "Operator": 24, + "TypeParameter": 25 +}; + +declare type lspt:CompletionItemKind as xs:integer; + +(: 1=Completion was triggered by typing an identifier (24x7 code + complete), manual invocation (e.g Ctrl+Space) or via API. + 2=Completion was triggered by a trigger character specified by + the `triggerCharacters` properties of the `CompletionRegistrationOptions`. + 3=Completion was re-triggered as the current completion list is incomplete. + :) +declare type lspt:CompletionTriggerKind as xs:integer(: 1 | 2 | 3 :); + +(: +export interface CompletionItem { + + /** + * The label of this completion item. + * + * The label property is also by default the text that + * is inserted when selecting this completion. + * + * If label details are provided the label itself should + * be an unqualified name of the completion item. + */ + label: string; + + /** + * Additional details for the label + * + * @since 3.17.0 + */ + labelDetails?: CompletionItemLabelDetails; + + + /** + * The kind of this completion item. Based of the kind + * an icon is chosen by the editor. The standardized set + * of available values is defined in `CompletionItemKind`. + */ + kind?: CompletionItemKind; + + /** + * Tags for this completion item. + * + * @since 3.15.0 + */ + tags?: CompletionItemTag[]; + + /** + * A human-readable string with additional information + * about this item, like type or symbol information. + */ + detail?: string; + + /** + * A human-readable string that represents a doc-comment. + */ + documentation?: string | MarkupContent; + + /** + * Indicates if this item is deprecated. + * + * @deprecated Use `tags` instead if supported. + */ + deprecated?: boolean; + + /** + * Select this item when showing. + * + * *Note* that only one completion item can be selected and that the + * tool / client decides which item that is. The rule is that the *first* + * item of those that match best is selected. + */ + preselect?: boolean; + + /** + * A string that should be used when comparing this item + * with other items. When omitted the label is used + * as the sort text for this item. + */ + sortText?: string; + + /** + * A string that should be used when filtering a set of + * completion items. When omitted the label is used as the + * filter text for this item. + */ + filterText?: string; + + /** + * A string that should be inserted into a document when selecting + * this completion. When omitted the label is used as the insert text + * for this item. + * + * The `insertText` is subject to interpretation by the client side. + * Some tools might not take the string literally. For example + * VS Code when code complete is requested in this example + * `con` and a completion item with an `insertText` of + * `console` is provided it will only insert `sole`. Therefore it is + * recommended to use `textEdit` instead since it avoids additional client + * side interpretation. + */ + insertText?: string; + + /** + * The format of the insert text. The format applies to both the + * `insertText` property and the `newText` property of a provided + * `textEdit`. If omitted defaults to `InsertTextFormat.PlainText`. + * + * Please note that the insertTextFormat doesn't apply to + * `additionalTextEdits`. + */ + insertTextFormat?: InsertTextFormat; + + /** + * How whitespace and indentation is handled during completion + * item insertion. If not provided the client's default value depends on + * the `textDocument.completion.insertTextMode` client capability. + * + * @since 3.16.0 + * @since 3.17.0 - support for `textDocument.completion.insertTextMode` + */ + insertTextMode?: InsertTextMode; + + /** + * An edit which is applied to a document when selecting this completion. + * When an edit is provided the value of `insertText` is ignored. + * + * *Note:* The range of the edit must be a single line range and it must + * contain the position at which completion has been requested. + * + * Most editors support two different operations when accepting a completion + * item. One is to insert a completion text and the other is to replace an + * existing text with a completion text. Since this can usually not be + * predetermined by a server it can report both ranges. Clients need to + * signal support for `InsertReplaceEdit`s via the + * `textDocument.completion.completionItem.insertReplaceSupport` client + * capability property. + * + * *Note 1:* The text edit's range as well as both ranges from an insert + * replace edit must be a [single line] and they must contain the position + * at which completion has been requested. + * *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range + * must be a prefix of the edit's replace range, that means it must be + * contained and starting at the same position. + * + * @since 3.16.0 additional type `InsertReplaceEdit` + */ + textEdit?: TextEdit | InsertReplaceEdit; + + /** + * The edit text used if the completion item is part of a CompletionList and + * CompletionList defines an item default for the text edit range. + * + * Clients will only honor this property if they opt into completion list + * item defaults using the capability `completionList.itemDefaults`. + * + * If not provided and a list's default range is provided the label + * property is used as a text. + * + * @since 3.17.0 + */ + textEditText?: string; + + /** + * An optional array of additional text edits that are applied when + * selecting this completion. Edits must not overlap (including the same + * insert position) with the main edit nor with themselves. + * + * Additional text edits should be used to change text unrelated to the + * current cursor position (for example adding an import statement at the + * top of the file if the completion item will insert an unqualified type). + */ + additionalTextEdits?: TextEdit[]; + + /** + * An optional set of characters that when pressed while this completion is + * active will accept it first and then type that character. *Note* that all + * commit characters should have `length=1` and that superfluous characters + * will be ignored. + */ + commitCharacters?: string[]; + + /** + * An optional command that is executed *after* inserting this completion. + * *Note* that additional modifications to the current document should be + * described with the additionalTextEdits-property. + */ + command?: Command; + + /** + * A data entry field that is preserved on a completion item between + * a completion and a completion resolve request. + */ + data?: LSPAny; +:) +declare record lspt:CompletionItem( + label as xs:string, + kind? as lspt:CompletionItemKind +); \ No newline at end of file diff --git a/webapp/lsp/providers/completions.xqm b/webapp/lsp/providers/completions.xqm new file mode 100644 index 0000000..005132e --- /dev/null +++ b/webapp/lsp/providers/completions.xqm @@ -0,0 +1,7 @@ +module namespace comp = 'lsp-completions'; + +(: (:{"triggerCharacter":":","triggerKind":2.0e0}:):) +declare function comp:list($context as map(*)){ + message($context,"context: "), + () +}; \ No newline at end of file diff --git a/webapp/static/clients/codemirror/grail.css b/webapp/static/clients/codemirror/grail.css index 3fca926..53ed78a 100644 --- a/webapp/static/clients/codemirror/grail.css +++ b/webapp/static/clients/codemirror/grail.css @@ -63,6 +63,10 @@ form header { overflow: auto; } + ::backdrop { + backdrop-filter: blur(2px); + } + @media (max-width: 600px) { grid-template-columns: 100%; grid-template-rows: auto;