(: Store for XQuery document data , type, text,uri on save parse is created and stored data is stored in webSocket attributes @author Andy Bunce :) module namespace docs="lsp/docs"; import module namespace p="xq4" at "xq4.xqm"; import module namespace pos="lsp/position" at "position.xqm"; import module namespace rpc = 'rpc' at 'jsonrpc.xqm'; import module namespace lsp-diags = 'lsp-diags' at 'lsp-diags.xqm'; (: save $textDocument data as session $socket properties @return uri :) declare function docs:open( $socket as xs:string, $params as map(*) ) as xs:string { let $text as xs:string:=$params?textDocument?text let $uri:=$params?textDocument?uri let $files:=ws:get($socket,"files",{}) let $files:=if(map:contains($files,$uri)) then $files else let $uuid:=random:uuid() return map:put($files,$uri,{ "textDocument": "file-" || $uuid, "parse": "parse-" || $uuid }) let $keys:=$files($uri) return ( ws:set($socket,"files",$files), ws:set($socket,$keys?textDocument,$params?textDocument), $uri ) }; (: change $textDocument data as session $socket properties @return uri :) declare function docs:change( $socket as xs:string, $params as map(*) ) as xs:string { let $uri:=$params?textDocument?uri let $key:=docs:key($socket,$uri,"textDocument") let $file:=if(exists($key)) then ws:get($socket,$key) else error(xs:QName("docs:change"), "no file" || $uri) let $ver:=$params?textDocument?version let $IGNORE_VER:=true() let $text:=if($IGNORE_VER or $ver eq 1+ $file?version) then pos:apply-changes($file?text,$params?contentChanges) else error(xs:QName("docs:change"),`badver got {$ver} expecting: {1+ $file?version}`) let $file:=$file=>map:put("version",$ver)=>map:put("text",$text) return ( ws:set($socket,$key,$file) , $uri) }; (:~ close a file :) declare function docs:close($socket as xs:string,$uri as xs:string) as map(*){ let $files:=ws:get($socket,"files",{}) return if(map:contains($files,$uri)) then let $props:=$files($uri) return ( map:items($props)!ws:delete($socket,.), ws:set($socket,"files",map:remove($files,$uri)) ) else () }; (:~ list of all files :) declare function docs:list($socket as xs:string) as xs:string*{ ws:get($socket,"files",{})=>map:keys() }; (: document info :) declare type docs:Property as enum( "textDocument", "parse" ); (: get $property key for $file from session $socket :) declare function docs:key( $socket as xs:string, $file as xs:string, $property as docs:Property ) as xs:string? { ws:get($socket,"files")($file)($property) }; (: get $property key for $file from session $socket :) declare function docs:get( $socket as xs:string, $file as xs:string, $property as docs:Property ) as item()? { ws:get($socket, docs:key($socket,$file,$property) ) }; (:~ generate XML parse, save it and publish diagnostics :) declare function docs:parse( $socket as xs:string, $file as xs:string )as map(*)? { let $text:=docs:get($socket,$file,"textDocument")?text let $xml:= p:parse-Module($text)=>prof:time("⏱️ p:parse-Module " || $file) return ( ws:set($socket,docs:key($socket,$file,"parse"),$xml), lsp-diags:publish($file, $text, $xml) ) };