[add] initial change implementation
This commit is contained in:
parent
eba2e564bb
commit
c0814be67c
4 changed files with 667 additions and 17 deletions
91
src/doci.xqm
91
src/doci.xqm
|
|
@ -4,12 +4,12 @@
|
|||
@author andy bunce
|
||||
:)
|
||||
module namespace doci = 'urn:doci';
|
||||
(: default line seperator if none found in text :)
|
||||
declare variable $doci:default-separator:=file:line-separator();
|
||||
|
||||
declare record doci:doci(
|
||||
lines as xs:string+,
|
||||
length as xs:integer,
|
||||
separator? as xs:string,
|
||||
starts? as xs:integer+
|
||||
separator? as xs:string
|
||||
);
|
||||
|
||||
declare record doci:line(
|
||||
|
|
@ -41,37 +41,89 @@ declare record doci:Range(
|
|||
end as doci:Position
|
||||
);
|
||||
|
||||
(:
|
||||
@see https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_didChange
|
||||
:)
|
||||
declare record doci:TextDocumentContentChangeEvent(
|
||||
text as xs:string,
|
||||
range? as doci:Range
|
||||
);
|
||||
|
||||
(: create new doci from string :)
|
||||
declare function doci:build($text as xs:string)
|
||||
as doci:doci{
|
||||
let $ls:=doci:separator($text )
|
||||
let $lines:=tokenize($text, '(\r\n?|\n\r?)')
|
||||
let $starts:=hof:scan-left($lines, 0,
|
||||
fn($res,$line){$res+string-length($ls)+string-length($line)}
|
||||
)
|
||||
let $lines:= doci:split-lines($text)
|
||||
|
||||
return doci:doci(
|
||||
lines:= $lines,
|
||||
length:= string-length($text),
|
||||
separator:=$ls,
|
||||
starts:= $starts
|
||||
separator:=$ls
|
||||
)
|
||||
};
|
||||
|
||||
(: line separator, assume all same:)
|
||||
(: return full text :)
|
||||
declare function doci:text($doci as doci:doci)
|
||||
as xs:string{
|
||||
string-join($doci?lines,$doci?separator)
|
||||
};
|
||||
(: number of lines:)
|
||||
declare function doci:lines($doci as doci:doci)
|
||||
as xs:string{
|
||||
$doci?lines=>count()
|
||||
};
|
||||
|
||||
(: detect line separator, assumes all the same:)
|
||||
declare function doci:separator($text as xs:string)
|
||||
as xs:string?{
|
||||
switch () {
|
||||
case contains($text," ") return " "
|
||||
case contains($text," ") return " "
|
||||
case contains($text," ") return " "
|
||||
default return ()
|
||||
default return $doci:default-separator
|
||||
}
|
||||
};
|
||||
(: apply change:)
|
||||
declare function doci:change($doci as doci:doci,$change as doci:TextDocumentContentChangeEvent)
|
||||
as doci:doci{
|
||||
let $lines:= doci:split-lines($change?text)
|
||||
return if(empty($change?range))
|
||||
then doci:doci($lines,$doci?separator)
|
||||
else let $range:=$change?range
|
||||
let $sline:=$range?start?line
|
||||
let $eline:=$range?end?line
|
||||
return switch(){
|
||||
case $sline eq $eline and count($lines) eq 1
|
||||
return let $line:=$doci?lines[$sline+1]
|
||||
let $new:=substring($line,1,$range?start?character)
|
||||
|| $lines ||
|
||||
substring($line,1+$range?end?character)
|
||||
|
||||
let $ulines:=( $doci?lines[position() le $sline],
|
||||
$new,
|
||||
$doci?lines[position() gt 1+$sline]
|
||||
)
|
||||
return doci:doci($ulines, $doci?separator)
|
||||
|
||||
default return error(#doci:change,"oh")
|
||||
}
|
||||
};
|
||||
|
||||
declare function doci:split-lines($text as xs:string)
|
||||
as xs:string+{
|
||||
if($text eq "")
|
||||
then $text
|
||||
else tokenize($text, '(\r\n?|\n\r?)')
|
||||
};
|
||||
|
||||
(: line from pos :)
|
||||
declare function doci:lineAt($doci as doci:doci,$pos as xs:integer)
|
||||
{
|
||||
let $line:=do-until(
|
||||
as doci:line {
|
||||
let $starts:=hof:scan-left($doci?lines, 0,
|
||||
fn($res,$line){$res+string-length($doci?seperator)+string-length($line)}
|
||||
)
|
||||
let $line:=if($pos gt $doci?length)
|
||||
then error(#doci:range,"pos beyond range")
|
||||
else do-until(
|
||||
{"min":1,"max":count($doci?lines)},
|
||||
fn($r){
|
||||
let $mid:=round(($r?min+$r?max) div 2,0,"away-from-zero")
|
||||
|
|
@ -81,5 +133,12 @@ let $line:=do-until(
|
|||
},
|
||||
fn($r){$r?max eq $r?min}
|
||||
)?max
|
||||
return $line
|
||||
};
|
||||
|
||||
return doci:line(
|
||||
number:= $line,
|
||||
text:= $doci?lines[$line],
|
||||
from:= $doci?starts[$line],
|
||||
to:= -1
|
||||
)
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue