[mod] improve logging
This commit is contained in:
parent
279b1ee189
commit
00aed821e1
12 changed files with 89 additions and 48 deletions
12
README.md
12
README.md
|
@ -1,12 +1,14 @@
|
||||||
Work in progress.
|
Work in progress.
|
||||||
|
|
||||||
An attempt to write a [Language Server Protocol](https://en.wikipedia.org/wiki/Language_Server_Protocol) server for and in XQuery 4.0. It uses the [BaseX websocket](https://docs.basex.org/main/WebSockets) feature.
|
An attempt to write a [Language Server Protocol](https://en.wikipedia.org/wiki/Language_Server_Protocol) server for and in XQuery 4.0. It tracks the draft specifications at https://qt4cg.org/
|
||||||
|
It written for BaseX 12.0 and uses the [BaseX websocket](https://docs.basex.org/main/WebSockets) feature.
|
||||||
|
|
||||||
# Demo
|
# Demo
|
||||||
1. Requires `Docker` or `Podman` on the local machine.
|
The demos expect `Docker` or `Podman` on the local machine. This is only a requirement for the demos.
|
||||||
2. Clone this repo
|
|
||||||
3. Run `docker compose up -d` The LSP server shall now running on port 3000 (edit `compose.yaml` to change port)
|
1 Clone this repo
|
||||||
4. In a browser navigate to `http://localhost:3000/static/clients/codemirror/` to see the CodeMirror 6 demo.
|
2. Run `docker compose up -d` The LSP server shall now running on port 3000 (edit `compose.yaml` to change port)
|
||||||
|
3. In a browser navigate to `http://localhost:3000/static/clients/codemirror/` to see the CodeMirror 6 demo.
|
||||||
|
|
||||||
In principle, the LSP can be used in any environment that can make use of a LSP server accessed via a websocket.
|
In principle, the LSP can be used in any environment that can make use of a LSP server accessed via a websocket.
|
||||||
## LSP Server
|
## LSP Server
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
xquery version '4.0';
|
xquery version '4.0';
|
||||||
(:~ Symbols from XQuery source file :)
|
(:~ Symbols from XQuery source file :)
|
||||||
module namespace syms="lsp/symbols";
|
module namespace syms="lsp/symbols";
|
||||||
|
|
||||||
|
import module namespace lspt = 'lsp-typedefs' at "lsp-typedefs.xqm";
|
||||||
import module namespace pos="lsp/position" at "position.xqm";
|
import module namespace pos="lsp/position" at "position.xqm";
|
||||||
|
|
||||||
|
(:~ symbols :)
|
||||||
|
declare function syms:list()
|
||||||
|
as map(*){
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -39,9 +39,17 @@ as map(*)?
|
||||||
declare
|
declare
|
||||||
function rpc:reply($json as map(*))
|
function rpc:reply($json as map(*))
|
||||||
as empty-sequence() {
|
as empty-sequence() {
|
||||||
let $f :=$rpc:Methods?($json?method)
|
let $f :=(void(trace($json,"➡️")),$rpc:Methods?($json?method))
|
||||||
let $response := $f!.($json)
|
let $response := $f!.($json)
|
||||||
return $response!ws:send(.=>trace("REPLY: "),ws:id())
|
return $response!rpc:send(.)
|
||||||
|
};
|
||||||
|
|
||||||
|
(:~ send with logging :)
|
||||||
|
declare
|
||||||
|
function rpc:send($msg as map(*))
|
||||||
|
as empty-sequence()
|
||||||
|
{
|
||||||
|
ws:send($msg =>trace("⬅️"),ws:id())
|
||||||
};
|
};
|
||||||
|
|
||||||
(:~ canned initialize response :)
|
(:~ canned initialize response :)
|
||||||
|
@ -59,6 +67,7 @@ function rpc:method-initialized($json as map(*))
|
||||||
as empty-sequence()
|
as empty-sequence()
|
||||||
{
|
{
|
||||||
ws:set(ws:id(),"initialized", true())
|
ws:set(ws:id(),"initialized", true())
|
||||||
|
(: ,rpc:later(5000,"rpc:show-message","This is a test async message 5secs after initialized",ws:id()) :)
|
||||||
};
|
};
|
||||||
|
|
||||||
(:~ unknown method response :)
|
(:~ unknown method response :)
|
||||||
|
@ -106,3 +115,30 @@ declare function rpc:error($message as xs:string,$json as map(*))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(:~ window/showMessage :)
|
||||||
|
declare function rpc:show-message($msg as xs:string)
|
||||||
|
as map(*)
|
||||||
|
{
|
||||||
|
{"jsonrpc": "2.0",
|
||||||
|
"method":"window/showMessage",
|
||||||
|
"params":{"type":3, "message": $msg}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(:~ send message after delay :)
|
||||||
|
declare function rpc:later($msdelay as xs:integer,$fn as xs:string ,$arg, $wsid as xs:string)
|
||||||
|
{
|
||||||
|
let $xq:=`import module namespace rpc = 'rpc' at 'jsonrpc.xqm';
|
||||||
|
declare variable $msdelay external;
|
||||||
|
declare variable $fn external;
|
||||||
|
declare variable $arg external;
|
||||||
|
declare variable $wsid external;
|
||||||
|
|
||||||
|
prof:sleep($msdelay),
|
||||||
|
ws:send(function-lookup(xs:QName($fn),1)($arg),$wsid)
|
||||||
|
`
|
||||||
|
let $bindings:={"msdelay": $msdelay,"wsid": $wsid, "fn": $fn,"arg":$arg}
|
||||||
|
let $opts:={"cache": true(),"base-uri": static-base-uri()}
|
||||||
|
return job:eval($xq, $bindings,$opts)=>void()
|
||||||
|
};
|
2
webapp/lsp/later.xq
Normal file
2
webapp/lsp/later.xq
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
import module namespace rpc = 'rpc' at 'jsonrpc.xqm';
|
||||||
|
rpc:later(1000,"rpc:show-message","Hello","sock")
|
|
@ -1,10 +1,5 @@
|
||||||
module namespace lsp-diags = 'lsp-diags';
|
module namespace lsp-diags = 'lsp-diags';
|
||||||
|
(:~ codemirror
|
||||||
import module namespace lspt = 'lsp-typedefs' at "lsp-typedefs.xqm";
|
|
||||||
import module namespace pos="lsp/position" at "position.xqm";
|
|
||||||
|
|
||||||
declare type lsp-diags:ParseResult as element(Module|ERROR);
|
|
||||||
(:~
|
|
||||||
from: number The start position of the relevant text.
|
from: number The start position of the relevant text.
|
||||||
to: number The end position. May be equal to from, though actually covering text is preferable.
|
to: number The end position. May be equal to from, though actually covering text is preferable.
|
||||||
severity: "error" | "hint" | "info" | "warning" The severity of the problem. This will influence how it is displayed.
|
severity: "error" | "hint" | "info" | "warning" The severity of the problem. This will influence how it is displayed.
|
||||||
|
@ -13,21 +8,14 @@ source?: string An optional source string indicating where the diagnostic is
|
||||||
message: string The message associated with this diagnostic.
|
message: string The message associated with this diagnostic.
|
||||||
renderMessage?: fn(view: EditorView) → Node An optional custom rendering function that displays the message as a DOM node.
|
renderMessage?: fn(view: EditorView) → Node An optional custom rendering function that displays the message as a DOM node.
|
||||||
actions?: readonly Action[] An optional array of actions that can be taken on this diagnostic.
|
actions?: readonly Action[] An optional array of actions that can be taken on this diagnostic.
|
||||||
:)
|
:)
|
||||||
declare record lsp-diags:nostic(
|
import module namespace lspt = 'lsp-typedefs' at "lsp-typedefs.xqm";
|
||||||
range as lspt:Range,
|
import module namespace pos="lsp/position" at "position.xqm";
|
||||||
severity as xs:integer, (: enum('error', 'hint', 'info', 'warning') :)
|
|
||||||
message as xs:string,
|
declare type lsp-diags:ParseResult as element(Module|ERROR);
|
||||||
code? as xs:string,
|
|
||||||
source as xs:string:="xquery"
|
|
||||||
);
|
|
||||||
|
|
||||||
declare variable $lsp-diags:severities:={
|
|
||||||
'error':1,
|
|
||||||
'hint':4,
|
|
||||||
'info':3,
|
|
||||||
'warning':2
|
|
||||||
};
|
|
||||||
|
|
||||||
declare function lsp-diags:publish(
|
declare function lsp-diags:publish(
|
||||||
$uri as xs:string,
|
$uri as xs:string,
|
||||||
|
@ -60,7 +48,7 @@ as map(*)*{
|
||||||
let $e:= number($xml/@e)-1
|
let $e:= number($xml/@e)-1
|
||||||
return (
|
return (
|
||||||
(: mark error :)
|
(: mark error :)
|
||||||
lsp-diags:nostic(lspt:Range(pos:toPosition($text, $b),
|
lspt:diagnostic(lspt:Range(pos:toPosition($text, $b),
|
||||||
pos:toPosition($text, $e)),
|
pos:toPosition($text, $e)),
|
||||||
1,
|
1,
|
||||||
$dmesg,'XPST0003'),
|
$dmesg,'XPST0003'),
|
||||||
|
@ -68,7 +56,7 @@ as map(*)*{
|
||||||
(:mark after error:)
|
(:mark after error:)
|
||||||
if($e ge string-length($text))
|
if($e ge string-length($text))
|
||||||
then ()
|
then ()
|
||||||
else lsp-diags:nostic(lspt:Range(pos:toPosition($text, $e +1 ),
|
else lspt:diagnostic(lspt:Range(pos:toPosition($text, $e +1 ),
|
||||||
pos:toPosition($text, $last)),
|
pos:toPosition($text, $last)),
|
||||||
2,
|
2,
|
||||||
"Unparsed due to previous parser error.",
|
"Unparsed due to previous parser error.",
|
||||||
|
|
|
@ -23,13 +23,8 @@ function lsp-text:hover($json as map(*))
|
||||||
as map(*)
|
as map(*)
|
||||||
{
|
{
|
||||||
let $r:= [
|
let $r:= [
|
||||||
`markdown here, this is **bold**.
|
`At { pos:ln-col($json?params?position) }, uri: {$json?params?textDocument?uri},
|
||||||
|
[path](https://quodatum.github.io/basex-xqparse/i-BaseX.xhtml#EQName)`
|
||||||
A [link](http://google.com)
|
|
||||||
|
|
||||||
The last line.`
|
|
||||||
,
|
|
||||||
`A hover at { pos:ln-col($json?params?position) } uri: {$json?params?textDocument?uri} `
|
|
||||||
]
|
]
|
||||||
return rpc:result({"contents":$r},$json)
|
return rpc:result({"contents":$r},$json)
|
||||||
};
|
};
|
||||||
|
|
|
@ -94,4 +94,19 @@ declare variable $lspt:SymbolKindMap :={
|
||||||
'TypeParameter': 26
|
'TypeParameter': 26
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare variable $lspt:DiagnosticSeverityKinds:={
|
||||||
|
'error':1,
|
||||||
|
'warning':2,
|
||||||
|
'info':3,
|
||||||
|
'hint':4
|
||||||
|
};
|
||||||
|
|
||||||
|
declare record lspt:diagnostic(
|
||||||
|
range as lspt:Range,
|
||||||
|
severity as xs:integer, (: enum('error', 'hint', 'info', 'warning') :)
|
||||||
|
message as xs:string,
|
||||||
|
code? as xs:string,
|
||||||
|
source as xs:string:="xquery"
|
||||||
|
);
|
||||||
|
|
||||||
declare type lspt:TraceValue as enum( 'off' , 'messages' , 'verbose');
|
declare type lspt:TraceValue as enum( 'off' , 'messages' , 'verbose');
|
||||||
|
|
|
@ -13,9 +13,7 @@ function lsp-ws:error($error) {
|
||||||
trace($error,"ERR ")
|
trace($error,"ERR ")
|
||||||
};
|
};
|
||||||
|
|
||||||
(:~
|
(:~ Creates a WebSocket connection. :)
|
||||||
: Creates a WebSocket connection. Registers the user and notifies all clients.
|
|
||||||
:)
|
|
||||||
declare
|
declare
|
||||||
%ws:connect('/lsp')
|
%ws:connect('/lsp')
|
||||||
function lsp-ws:connect() as empty-sequence() {
|
function lsp-ws:connect() as empty-sequence() {
|
||||||
|
|
|
@ -14,6 +14,7 @@ as lspt:num
|
||||||
let $off:=if($pos?line eq 0)
|
let $off:=if($pos?line eq 0)
|
||||||
then 0
|
then 0
|
||||||
else $nl[$pos?line]
|
else $nl[$pos?line]
|
||||||
|
let $_:=substring($text,$off+1,1)=>string-to-codepoints()=>trace("LF? ")
|
||||||
return $off+$pos?character
|
return $off+$pos?character
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ declare function pos:toPosition($text as xs:string,
|
||||||
$index as lspt:num
|
$index as lspt:num
|
||||||
)
|
)
|
||||||
as lspt:Position {
|
as lspt:Position {
|
||||||
let $nl:= if($index=>trace("IN ") gt string-length($text)=>trace("L "))
|
let $nl:= if($index gt string-length($text))
|
||||||
then error(xs:QName("pos:range"),`out of range: index={$index},length={string-length($text)}`)
|
then error(xs:QName("pos:range"),`out of range: index={$index},length={string-length($text)}`)
|
||||||
else index-of(string-to-codepoints($text),10)
|
else index-of(string-to-codepoints($text),10)
|
||||||
let $line:=pos:lineAt($nl,$index)
|
let $line:=pos:lineAt($nl,$index)
|
||||||
|
|
|
@ -22,19 +22,16 @@ body {
|
||||||
grid-template-rows: min-content min-content 1fr min-content;
|
grid-template-rows: min-content min-content 1fr min-content;
|
||||||
gap: 1px;
|
gap: 1px;
|
||||||
|
|
||||||
* {
|
|
||||||
padding: 0px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item{
|
.navbar * {
|
||||||
padding: 0px 9px;
|
box-sizing: content-box;
|
||||||
margin: 0px 3px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set editor dimensions */
|
/* Set editor dimensions */
|
||||||
#editor {
|
#editor {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height:80cqh;
|
height:75cqh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stretch editor to fit inside its containing div */
|
/* Stretch editor to fit inside its containing div */
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Add table
Reference in a new issue