From 77bc1e524c37a6218ad08376d789e8db39a496c4 Mon Sep 17 00:00:00 2001 From: Andy Bunce Date: Tue, 19 Aug 2025 12:43:04 +0100 Subject: [PATCH] [fix] positions --- docs/explore.xqbk | 2 +- test/position-tests.xqm | 17 +++++++++++++++-- test/position.xq | 8 +++----- webapp/lsp/lsp-diags.xqm | 30 +++++++++++++++++------------- webapp/lsp/position.xqm | 6 ++++-- 5 files changed, 40 insertions(+), 23 deletions(-) diff --git a/docs/explore.xqbk b/docs/explore.xqbk index bd9d2ba..88d5072 100644 --- a/docs/explore.xqbk +++ b/docs/explore.xqbk @@ -1 +1 @@ -{"cells":[{"kind":2,"language":"xquery","value":"(:<:)\r\n\r\nimport module namespace docs=\"lsp/docs\" at \"/srv/basex/webapp/lsp/docs.xqm\";"},{"kind":2,"language":"xquery","value":"ws:ids()"},{"kind":2,"language":"xquery","value":"let $sock:=foot(ws:ids())\r\nlet $f:=docs:list($sock)\r\nlet $t:=docs:get($sock,$f,\"textDocument\")\r\nreturn map:put($t,\"text\",substring($t?text,1,15))"},{"kind":2,"language":"xquery","value":"let $sock:=foot(ws:ids())\r\nlet $f:=docs:list($sock)\r\nlet $t:=docs:get($sock,$f,\"parse\")\r\nreturn $t/self::ERROR"},{"kind":2,"language":"xquery","value":"let $sock:=foot(ws:ids())\r\nlet $f:=docs:list($sock)\r\nlet $t:=docs:get($sock,$f,\"textDocument\")?text\r\nreturn $t"}]} \ No newline at end of file +{"cells":[{"kind":2,"language":"xquery","value":"(:<:)\r\n\r\nimport module namespace docs=\"lsp/docs\" at \"/srv/basex/webapp/lsp/docs.xqm\";"},{"kind":2,"language":"xquery","value":"ws:ids()"},{"kind":2,"language":"xquery","value":"let $sock:=foot(ws:ids())\r\nlet $f:=docs:list($sock)\r\nlet $t:=docs:get($sock,$f,\"textDocument\")\r\nreturn map:put($t,\"text\",substring($t?text,1,15))"},{"kind":2,"language":"xquery","value":"let $sock:=foot(ws:ids())\r\nlet $f:=docs:list($sock)\r\nlet $t:=docs:get($sock,$f,\"parse\")\r\nreturn $t/self::ERROR"},{"kind":2,"language":"xquery","value":"let $sock:=foot(ws:ids())\r\nlet $f:=docs:list($sock)\r\nlet $t:=docs:get($sock,$f,\"textDocument\")\r\nreturn $t"}]} \ No newline at end of file diff --git a/test/position-tests.xqm b/test/position-tests.xqm index ba7d314..0f2e535 100644 --- a/test/position-tests.xqm +++ b/test/position-tests.xqm @@ -12,7 +12,7 @@ import module namespace pos="lsp/position" at "../webapp/lsp/position.xqm"; (:~ count lines. :) declare %unit:test function test:line-count() { let $text:=unparsed-text("sample.docs/pdfbox.xqm") - let $nl:= index-of(string-to-codepoints($text),10)=>trace("SSS ") + let $nl:= index-of(string-to-codepoints($text),10) return unit:assert-equals(count($nl),521) }; @@ -23,8 +23,21 @@ declare %unit:test function test:resolvePosition() { return unit:assert-equals($p,18751) }; +(:~ convert position. :) +declare %unit:test("expected", "pos:range") +function test:toPosition() { + let $text:="1+2 a" + return pos:toPosition($text,5) +}; +(:~ convert position. :) +declare %unit:test +function test:toPosition2() { + let $text:="1+2 a" + return unit:assert-equals(pos:toPosition($text,4),{"line":0,"character":4}) +}; + (:~ convert all position. :) -declare %unit:test function test:toPosition() { +declare %unit:test %unit:ignore function test:toPositionAll() { let $text:=unparsed-text("sample.docs/pdfbox.xqm") return for $i in 0 to string-length($text)-1 let $pos:=pos:toPosition($text,$i) diff --git a/test/position.xq b/test/position.xq index b3351f2..a7260d2 100644 --- a/test/position.xq +++ b/test/position.xq @@ -1,7 +1,5 @@ import module namespace pos="lsp/position" at "../webapp/lsp/position.xqm"; - let $text:=unparsed-text("sample.docs/pdfbox.xqm") - let $nl:= index-of(string-to-codepoints($text),10) + let $text:="1+2 a" - return ( - pos:toPosition($text,10744),pos:toPosition($text,10745) - ) \ No newline at end of file + return pos:toPosition($text,5) + \ No newline at end of file diff --git a/webapp/lsp/lsp-diags.xqm b/webapp/lsp/lsp-diags.xqm index 7de6461..f807ea8 100644 --- a/webapp/lsp/lsp-diags.xqm +++ b/webapp/lsp/lsp-diags.xqm @@ -17,7 +17,7 @@ declare record lsp-diags:nostic( range as pos:Range, severity as xs:integer, (: enum('error', 'hint', 'info', 'warning') :) message as xs:string, - code? as xs:string, + code as xs:string, source as xs:string:="xquery" ); @@ -33,10 +33,11 @@ declare function lsp-diags:publish( $text as xs:string, $xml as lsp-diags:ParseResult) as map(*){ +let $_:=trace($xml,"PABLISH ") let $diagnostics:=if($xml/self::ERROR) then array{lsp-diags:parse-error($text, $xml)} else array{ lsp-diags:parse-xquery($text,$xml)} - +let $_:=trace($diagnostics,"PIBLISH ") return {"jsonrpc": "2.0", "method":"textDocument/publishDiagnostics", "params":{"uri": $uri, "diagnostics": $diagnostics} @@ -44,25 +45,28 @@ as map(*){ }; (:~ -syntax error, found '}' while expecting [S,'else'] at line 290, column 3: ...} }; ? return bookmark info for children of $outlineItem as s... - assert.equal(markers[0].code, 'XPST0003', 'parse error'); - assert.equal(markers[1].code, 'XQLT0001', 'previous parse error'); +syntax error, found '}' while expecting [S,'else'] at line 290, column 'XPST0003', 'parse error' +'XQLT0001', 'previous parse error' :) declare function lsp-diags:parse-error($text as xs:string, $xml as element(ERROR)) as map(*)*{ -let $dmesg:=$xml/string() +let $dmesg:=$xml/string()=>trace("parse-error") let $dmesg:=translate($dmesg," ",";") +let $b:=number($xml/@b)-1 +let $e:= number($xml/@e)-1 return ( -lsp-diags:nostic(pos:Range(pos:toPosition($text, $xml/@b), - pos:toPosition($text, $xml/@e)), - $lsp-diags:severities('error'), - $dmesg,code:="XPST0003"), -lsp-diags:nostic(pos:Range(pos:toPosition($text, $xml/@e +1 ), +lsp-diags:nostic(pos:Range(pos:toPosition($text, $b), + pos:toPosition($text, min(($e,string-length($text)-1)))), + 1, + $dmesg,'XPST0003'), +if($e ge string-length($text)) +then () +else lsp-diags:nostic(pos:Range(pos:toPosition($text, $e +1 ), pos:toPosition($text, string-length($text)-1)), - $lsp-diags:severities('warning'), + 2, "Unparsed due to previous parser error.", - code:="XQLT0001") + "XQLT0001") ) }; diff --git a/webapp/lsp/position.xqm b/webapp/lsp/position.xqm index 25553c1..68abf2c 100644 --- a/webapp/lsp/position.xqm +++ b/webapp/lsp/position.xqm @@ -56,7 +56,9 @@ declare function pos:toPosition($text as xs:string, $index as pos:num ) as pos:Position { - let $nl:= index-of(string-to-codepoints($text),10) + let $nl:= if($index=>trace("IN ") ge string-length($text)=>trace("L ")) + then error(xs:QName("pos:range"),"out of range") + else index-of(string-to-codepoints($text),10) let $line:=pos:lineAt($nl,$index) let $off:=if($line eq 0) then 0 @@ -70,7 +72,7 @@ return pos:Position($line, $index - $off) declare function pos:lineAt($nl as xs:integer*,$pos as pos:num) as xs:integer { - if($pos le head($nl)) + if(empty($nl) or $pos le head($nl)) then 0 else if($pos gt foot($nl)) then count($nl)