basex-lsp/webapp/lsp/position.xqm
2025-08-07 12:12:27 +01:00

67 lines
1.9 KiB
Text

(:~
text editing API
:)
module namespace pos="lsp/position";
(:~
@param line Line position in a document (zero-based).
@param character Character offset on a line in a document (zero-based).
:)
declare record pos:Position(
line as xs:integer,
character as xs:integer
);
declare function pos:apply-changes($text as xs:string, $chs as array(*))
as xs:string{
array:fold-left($chs,$text,pos:apply-change#2)
};
(:~ text updated with $ch changes from didChange :)
declare function pos:apply-change($text as xs:string, $ch as map(*))
as xs:string{
if(exists($ch?range))
then substring($text,1, pos:resolvePosition($text, $ch?range?start))
|| $ch?text ||
substring($text,pos:resolvePosition($text, $ch?range?end))
else $ch?text
};
(:~ find index from Position :)
declare function pos:resolvePosition($text as xs:string, $pos as map(*))
as xs:integer
{
let $nl:=characters($text)=>index-of(char("\n"))
let $s:= while-do(
map{"off":0,"line":0},
fn($r, $i){$r?line < $pos?line},
fn($r,$i){ let $next:=$nl[$i]
return if(empty($next))
then error(xs:QName("docs:range"),"bad line")
else {"off": $next+1,"line":$r?line+1}=>trace("AA ") }
)
let $off:= $s?off+$pos?character
return if($off>string-length($text))
then error(xs:QName("docs:range"),"bad offset")
else xs:integer($off)
};
(:~ convert index into Position :)
declare function pos:toPosition($text as xs:string, $index as xs:integer)
as pos:Position {
let $nl:=characters($text)=>index-of(char("\n"))
let $predicate:=fn($r, $i){
let $next:=$nl[$i=>trace("I ")]
return exists($next) and $next < $index
}
let $s:= while-do(
map{"off":0,"line":0},
$predicate,
fn($r,$i){ let $next:=$nl[$i] return {"off": $next+1,"line":$r?line+1}=>trace("AA ") }
)
return pos:Position($s?line, $index - $s?off)
};