[mod] symbol ranges

This commit is contained in:
Andy Bunce 2025-10-30 15:36:39 +00:00
parent 2d0ae19026
commit fc56a3d505
5 changed files with 52 additions and 39 deletions

View file

@ -5,7 +5,7 @@ module namespace hnd="lsp/handlers";
(:~ structure returned by tree walkers :)
declare record hnd:Result(
declare record hnd:State(
result as item()*,
skipchildren? as xs:boolean:=false(),
extras?
@ -13,23 +13,23 @@ declare record hnd:Result(
declare type hnd:actionFn as fn(
$parse as element(),
$state as hnd:Result
) as hnd:Result;
$state as hnd:State
) as hnd:State;
declare type hnd:actionMap as map(xs:string,hnd:actionFn);
declare function hnd:walk($parse as element(),
$actions as hnd:actionMap,
$state as hnd:Result )
as hnd:Result
$state as hnd:State )
as hnd:State
{
let $action:=$actions(name($parse))
let $result:= if(exists($action))
let $state:= if(exists($action))
then $action($parse,$state)
else hnd:Result($state)
else $state
return if($result?skipchildren)
then $result
return if($state?skipchildren)
then $state
else fold-left(
$parse/*,$state,
fn($state,$this){hnd:walk($this, $actions, $state)}

View file

@ -35,7 +35,7 @@ function lsp-ws:message(
$message as xs:string
) as empty-sequence() {
let $json := rpc:parse($message=>trace("IN: "))
let $json := rpc:parse($message)
return if(exists($json))
then rpc:reply($json)
else message($message,"bad RPC: ")

View file

@ -66,13 +66,13 @@ as lspt:Diagnostic*
(: test data :)
declare function lsp-diags:parse-xquery($text as xs:string, $parse as element(Module))
as map(*)*{
let $state:= hnd:Result(())
let $state:= hnd:State(())
let $result:= hnd:walk($parse,$lsp-diags:actions,$state)
return $result?result
};
declare function lsp-diags:Module($parse as element(Module),$state as hnd:Result )
as hnd:Result{
declare function lsp-diags:Module($parse as element(Module),$state as hnd:State )
as hnd:State{
let $new:=if(exists($parse/VersionDecl)=>trace("has ver: "))
then ()
else let $text:="dddjjjjjjjjjjjjjjjj"
@ -86,7 +86,10 @@ as hnd:Result{
"No XQuery version declaration present",
"XQLT???")
return (
hnd:Result(($state?result,$new=>trace(" VER ")),true())
$state
=>map:put("result",($state?result,$new=>trace(" VER ")))
=>map:put("skipchildren",true())
,message(name($parse),"Module: ")
)
};

View file

@ -15,9 +15,9 @@ declare variable $syms:actions as hnd:actionMap :={
declare function syms:list($parse as element(),$text as xs:string)
as lspt:DocumentSymbol*{
let $state:= hnd:Result(())
let $result:= hnd:walk($parse,$syms:actions,$state)
return $result?result
let $state:= hnd:State((),false(),{"text":$text})
let $state:= hnd:walk($parse,$syms:actions,$state)
return $state?result
};
(: for testing only:)
@ -33,37 +33,46 @@ as lspt:DocumentSymbol*{
};
(:~ just trace :)
declare function syms:action($parse as element(),$state as hnd:Result )
as hnd:Result{
hnd:Result($state?result,true()) ,message(name($parse),"ACTION: ")
declare function syms:action($parse as element(),$state as hnd:State )
as hnd:State{
$state ,message(name($parse),"ACTION: ")
};
declare function syms:VarDecl($parse as element(VarDecl),$state as hnd:Result )
as hnd:Result{
declare function syms:VarDecl($parse as element(VarDecl),$state as hnd:State )
as hnd:State{
let $name:=syms:localName($parse/VarNameAndType/EQName)
let $length:=string($parse)=>string-length()
let $range:=lspt:Range(lspt:Position(0,0),lspt:Position(0,3))
let $sym:=lspt:DocumentSymbol($name,$lspt:SymbolKindMap('Variable'),$range,$range,"VAR")
return ($state?result,$sym)=>hnd:Result(true())
let $range:=pos:range-from-ast($parse,$state?extras?text)=>trace("POSSSS")
let $full-range:=$range
let $sym:=lspt:DocumentSymbol($name,$lspt:SymbolKindMap('Variable'),$range,$full-range,"VAR")
return $state
=>map:put("result",($state?result,$sym))
=>map:put("skipchildren",true())
};
declare function syms:FunctionDecl($parse as element(FunctionDecl),$state as hnd:Result )
as hnd:Result{
declare function syms:FunctionDecl($parse as element(FunctionDecl),$state as hnd:State )
as hnd:State{
let $name:=syms:localName($parse/UnreservedFunctionEQName)
let $prev:=$state?result[$name eq ?name]
let $range:=pos:range-from-ast($parse,$state?context?text)=>trace("POSSSS")
let $range:=pos:range-from-ast($parse,$state?extras?text)=>trace("POSSSS")
let $full-range:=$range
let $sym:=lspt:DocumentSymbol($name,$lspt:SymbolKindMap('Method'),$range,$full-range,"FUN")
return ($state?result,$sym)=>hnd:Result(true())
return $state
=>map:put("result",($state?result,$sym))
=>map:put("skipchildren",true())
};
declare function syms:NamedRecordTypeDecl($parse as element(NamedRecordTypeDecl), $state as hnd:Result )
as hnd:Result{
declare function syms:NamedRecordTypeDecl($parse as element(NamedRecordTypeDecl), $state as hnd:State )
as hnd:State{
let $name:=syms:localName($parse/EQName)
let $range:=lspt:Range(lspt:Position(0,0),lspt:Position(0,3))
let $sym:=lspt:DocumentSymbol($name,$lspt:SymbolKindMap('TypeParameter'),$range,$range,"--RECORD")
let $range:=pos:range-from-ast($parse,$state?extras?text)=>trace("POSSSS")
let $full-range:=$range
let $sym:=lspt:DocumentSymbol($name,$lspt:SymbolKindMap('TypeParameter'),$range,$full-range,"--RECORD")
=>trace("RECORD")
return ($state?result,$sym)=>hnd:Result(true())
return $state
=>map:put("result",($state?result,$sym))
=>map:put("skipchildren",true())
};
declare function syms:localName($name as xs:string )

View file

@ -3,8 +3,8 @@ const view = new lsp.EditorView({
parent: document.getElementById("editor")
});
let doc = "xquery version '3.1';\n(:~ comment:)\nmodule namespace pdfbox='ns';\n";
var client;
var extLint;
var client; // https://codemirror.net/docs/ref/#lsp-client
var extLsp; // https://codemirror.net/docs/ref/#lsp-client.LSPPlugin
var workspace = {
"file:///some/file.xqm": null
};
@ -74,8 +74,9 @@ $("cmdList").onclick = e => {
$("symList").addEventListener("itemSelected", e => {
const sel = e.detail.selectionRange;
console.log("SYM selection range", sel);
const an = 17 * e.detail.kind
view.dispatch({ selection: { anchor: an, head: an + 34 }, scrollIntoView: true });
const an = extLsp.fromPosition(sel.start)
const hd = extLsp.fromPosition(sel.end)
view.dispatch({ selection: { anchor: an, head: hd}, scrollIntoView: true });
});
$("lint").onclick = async e => {
@ -158,7 +159,7 @@ function connect() {
client.connect(transport);
$("popConnect").hidePopover();
$("tConnect").checked=true;
let extLsp = client.plugin(file, "xquery");
extLsp = client.plugin(file, "xquery");
view.dispatch({
effects: lsp.StateEffect.appendConfig.of(