(: Store for XQuery document data , type, text,uri on save parse is created and stored implementation: data is stored in webSocket @author Andy Bunce :) module namespace docs="lsp/docs"; import module namespace p="xq4" at "xq4.xqm"; declare record docs:Position( (: Line position in a document (zero-based). :) line as xs:integer, (: Character offset on a line in a document (zero-based). :) character as xs:integer ); (: document info :) declare type docs:property as enum( "textDocument", "parse" ); (: get $property for $file from session $socket :) declare function docs:get( $socket as xs:string, $file as xs:string, $property as docs:property ) { let $key:=ws:get($socket,"files")($file)($property) return ws:get($socket,$key) }; (: save $textDocument data as session $socket properties :) declare function docs:save( $socket as xs:string, $textDocument as map(*) ) { let $text as xs:string:=$textDocument?text let $uri:=$textDocument?uri let $files:=ws:get($socket,"files",{}) let $files:=if(map:contains($files,$uri)) then $files else map:put($files,$uri,{ "textDocument":random:uuid(), "parse":random:uuid() }) let $keys:=$files($uri) let $xml:=p:parse-Module($text) return ( ws:set($socket,"files",$files), ws:set($socket,$keys?textDocument,$textDocument), ws:set($socket,$keys?parse,$xml) ) }; declare function docs:resolvePosition(text as xs:string, pos as docs:Position) as xs:integer { let line = 0, off = 0 while (line < pos.line) { let next = text.indexOf("\n", off) if (!next) throw new RangeError("Position out of bounds") off = next + 1 line++ } off += pos.character if (off > string-length($text)) throw new RangeError("Position out of bounds") return off } declare function docs:toPosition($text as xs:string, $pos as xs:integer) as docs:Position { for (let off = 0, line = 0;;) { let next = text.indexOf("\n", off) if (next < 0 || next >= pos) return {line, character: pos - off} off = next + 1 line++ } }