0 | module Language.LSP.VirtualDocument
10 | import Language.LSP.Message.Location
11 | import Language.LSP.Message.TextDocument
12 | import Decidable.Equality
14 | import Control.Function
15 | import Syntax.PreorderReasoning
74 | lineLength : String -> Nat
76 | lineLength str = assert_total $
77 | let l = strLength str in
78 | if isNL (strIndex str (l - 1))
79 | then minus (cast l) 1
83 | takePos : Pos -> String -> String
85 | let ls : List String = lines str in
86 | let ln : Nat = length ls in
88 | False => fastUnlines ls
90 | let (pre, post) = splitAt l ls in
92 | [] => fastUnlines pre
94 | let ll : Nat := lineLength pl in
95 | let cx : Nat := if c > ll then ll else c in
96 | fastUnlines $
pre ++ [strSubstr 0 (cast cx) pl]
99 | dropPos : Pos -> String -> String
100 | dropPos (l,c) str =
101 | let ls : List String = lines str in
102 | let ln : Nat = length ls in
106 | let (pre, post) = splitAt l ls in
110 | let ll : Nat := lineLength pl in
111 | let cx : Nat := if c > ll then ll else c in
112 | fastUnlines $
(strSubstr (cast cx) (cast (minus (cast (strLength pl)) cx)) pl :: prest)
116 | dropLastNL : String -> String
117 | dropLastNL str = assert_total $
case strLength str of
119 | n => strSubstr 0 (n - 1) str
122 | rangeSplit : Pos -> Pos -> String -> (String, String)
123 | rangeSplit s e str = (dropLastNL $
takePos s str, dropLastNL $
dropPos e str)
131 | update : Pos -> Pos -> String -> String -> String
132 | update s e new content =
133 | let (pre, post) = rangeSplit s e content in
134 | fastConcat [pre, new, post, "\n"]
139 | isIdentifierChar : Char -> Bool
140 | isIdentifierChar c = or [isAlphaNum c, c == '.', c == '_', c == '\'']
148 | identifierAtIndex : String -> Nat -> String
149 | identifierAtIndex "" i = ""
150 | identifierAtIndex str i = identifierPre (minus i 1) i
153 | l = cast (strLength str)
155 | identifierPost : Nat -> Nat -> String
156 | identifierPost n Z = assert_total $
case isIdentifierChar (strIndex str (cast Z)) of
157 | True => identifierPost n (S Z)
159 | identifierPost n (S m) = assert_total $
case (S m) == l of
160 | True => strSubstr (cast n) (cast (minus (S m) n)) str
161 | False => case isIdentifierChar (strIndex str (cast (S m))) of
162 | True => identifierPost n (S (S m))
163 | False => strSubstr (cast n) (cast (minus (S m) n)) str
165 | identifierPre : Nat -> Nat -> String
166 | identifierPre Z m = assert_total $
case isIdentifierChar (strIndex str (cast Z)) of
167 | True => identifierPost Z m
168 | False => identifierPost (S Z) m
169 | identifierPre (S n) m = assert_total $
case isIdentifierChar (strIndex str (cast (S n))) of
170 | True => identifierPre n m
171 | False => identifierPost (S (S n)) m
176 | identifierAtPos : Pos -> String -> String
177 | identifierAtPos (l,c) str =
178 | let ls : List String := lines str in
179 | let ln : Nat := length ls in
182 | False => case drop l ls of
185 | let ll : Nat := lineLength line in
186 | let cx : Nat := if c > ll then ll else c in
187 | identifierAtIndex line cx
194 | identifierAtPosition : Position -> String -> String
195 | identifierAtPosition (MkPosition line character) str = identifierAtPos (cast line, cast character) str
199 | validRange : (startline, startchar, endline, endchar : Nat) -> Bool
200 | validRange startline startchar endline endchar =
201 | case compare startline endline of
203 | EQ => case compare startchar endchar of
209 | changeRange : Range -> String -> String -> Either String String
210 | changeRange (MkRange (MkPosition sl sc) (MkPosition el ec)) content str =
211 | case validRange (cast sl) (cast sc) (cast el) (cast ec) of
212 | False => Left "Invalid range: \{show (sl,sc,el,ec)}"
213 | True => Right $
update (cast sl, cast sc) (cast el, cast ec) str content
215 | contentChangeEvent : TextDocumentContentChangeEvent -> String
216 | contentChangeEvent (MkTextDocumentContentChangeEvent text) = text
218 | contentChangeEventWithRange : TextDocumentContentChangeEventWithRange -> String -> Either String String
219 | contentChangeEventWithRange
220 | (MkTextDocumentContentChangeEventWithRange range rangeLength text)
222 | = changeRange range content text
224 | contentChangeOneOf : OneOf [TextDocumentContentChangeEvent, TextDocumentContentChangeEventWithRange] -> String -> Either String String
225 | contentChangeOneOf (Here c) _ = Right $
contentChangeEvent c
226 | contentChangeOneOf (There (Here r)) c = contentChangeEventWithRange r c
229 | changeVirtualContent
230 | : List (OneOf [TextDocumentContentChangeEvent, TextDocumentContentChangeEventWithRange])
231 | -> String -> Either String String
232 | changeVirtualContent changes content = foldlM (flip contentChangeOneOf) content changes
238 | wordPosTestCase : Pos -> String -> String -> IO ()
239 | wordPosTestCase p str expected = do
240 | let res = identifierAtPos p str
243 | putStrLn "OK: identifierAtPos \{show p} \{show str} \{show expected}"
245 | putStrLn "Failed: identifierAtPos \{show p} \{show str} \{show expected}"
246 | putStrLn "Expected: \{show expected}"
247 | putStrLn "Got: \{show res}"
249 | updateTestCase : Pos -> Pos -> String -> String -> String -> IO ()
250 | updateTestCase s e new str expected = do
251 | let res = update s e new str
254 | putStrLn "OK: update \{show s} \{show e} \{show new} \{show str}"
256 | putStrLn "Failed: update \{show s} \{show e} \{show new} \{show str}"
257 | putStrLn "Expected: \{show expected}"
258 | putStrLn "Got: \{show res}"
267 | updateTestCase (0,0) (0,0) "" str "\n"
268 | updateTestCase (0,0) (0,0) "a\nb" str "a\nb\n"
269 | updateTestCase (0,0) (0,1) "a" str "a\n"
270 | updateTestCase (1,0) (1,0) "a" str "a\n"
271 | updateTestCase (1,1) (1,1) "a" str "a\n"
272 | updateTestCase (1,1) (1,2) "a" str "a\n"
273 | updateTestCase (1,1) (2,2) "a" str "a\n"
277 | updateTestCase (0,0) (0,0) "" str " \n"
278 | updateTestCase (0,0) (0,0) "a\nb" str "a\nb \n"
279 | updateTestCase (0,0) (0,1) "a" str "a\n"
280 | updateTestCase (1,0) (1,0) "a" str " a\n"
281 | updateTestCase (1,1) (1,1) "a" str " a\n"
282 | updateTestCase (2,1) (2,1) "" str " \n"
283 | updateTestCase (2,1) (2,1) "a" str " a\n"
287 | updateTestCase (0,0) (0,0) "" str "\n"
288 | updateTestCase (0,0) (0,0) "a\nb" str "a\nb\n"
289 | updateTestCase (0,0) (0,1) "a" str "a\n"
290 | updateTestCase (1,0) (1,0) "a" str "a\n"
291 | updateTestCase (1,1) (1,1) "a" str "a\n"
292 | updateTestCase (2,1) (2,1) "" str "\n"
293 | updateTestCase (2,1) (2,1) "a" str "a\n"
298 | let str = "This is a line."
299 | updateTestCase (0,0) (0,0) "" str "This is a line.\n"
300 | updateTestCase (0,5) (0,5) "" str "This is a line.\n"
301 | updateTestCase (0,0) (0,0) "a" str "aThis is a line.\n"
302 | updateTestCase (0,5) (0,5) "a" str "This ais a line.\n"
303 | updateTestCase (0,5) (0,8) "xx" str "This xxa line.\n"
304 | updateTestCase (0,5) (0,15) "aaa" str "This aaa\n"
305 | updateTestCase (0,3) (0,4) "" str "Thi is a line.\n"
306 | updateTestCase (0,11) (0,20) "" str "This is a l\n"
311 | let str = "This is a newline.\n"
312 | updateTestCase (0,0) (0,0) "" str str
313 | updateTestCase (0,5) (0,5) "" str str
314 | updateTestCase (0,0) (0,0) "a" str "aThis is a newline.\n"
315 | updateTestCase (0,5) (0,5) "a" str "This ais a newline.\n"
316 | updateTestCase (0,5) (0,8) "aa" str "This aaa newline.\n"
317 | updateTestCase (0,5) (0,18) "aaa" str "This aaa\n"
318 | updateTestCase (0,18) (0,18) "a" str "This is a newline.a\n"
319 | updateTestCase (0,11) (0,20) "" str "This is a n\n"
324 | let str = "This is the first line.\nThis is the second line.\nThis is the third line."
325 | updateTestCase (1,0) (1,0) "" str (str ++ "\n")
326 | updateTestCase (1,0) (1,0) "a" str "This is the first line.\naThis is the second line.\nThis is the third line.\n"
330 | updateTestCase (1,24) (2,0) "a" str "This is the first line.\nThis is the second line.aThis is the third line.\n"
331 | updateTestCase (1,19) (2,0) "a" str "This is the first line.\nThis is the second aThis is the third line.\n"
332 | updateTestCase (1,0) (2,0) "" str "This is the first line.\nThis is the third line.\n"
333 | updateTestCase (1,0) (2,0) "a" str "This is the first line.\naThis is the third line.\n"
334 | updateTestCase (1,8) (2,8) "" str "This is the first line.\nThis is the third line.\n"
335 | updateTestCase (1,8) (2,8) "a " str "This is the first line.\nThis is a the third line.\n"
336 | updateTestCase (1,8) (2,9) "x" str "This is the first line.\nThis is xhe third line.\n"
337 | updateTestCase (1,23) (2,22) "" str "This is the first line.\nThis is the second line.\n"
338 | updateTestCase (1,23) (2,22) "a" str "This is the first line.\nThis is the second linea.\n"
339 | updateTestCase (1,23) (2,23) "a" str "This is the first line.\nThis is the second linea\n"
340 | updateTestCase (0,23) (1,24) "" str "This is the first line.\nThis is the third line.\n"
341 | updateTestCase (1,0) (1,40) "" str "This is the first line.\n\nThis is the third line.\n"
342 | updateTestCase (1,0) (1,24) "" str "This is the first line.\n\nThis is the third line.\n"
343 | updateTestCase (1,10) (1,40) "" str "This is the first line.\nThis is th\nThis is the third line.\n"
344 | updateTestCase (1,0) (4,40) "" str "This is the first line.\n\n"
345 | updateTestCase (1,10) (4,40) "" str "This is the first line.\nThis is th\n"
350 | let str = "This is the first line.\nThis is the second line.\nThis is the third line.\n"
351 | updateTestCase (1,0) (1,0) "" str str
352 | updateTestCase (1,0) (1,0) "a" str "This is the first line.\naThis is the second line.\nThis is the third line.\n"
356 | updateTestCase (1,24) (2,0) "a" str "This is the first line.\nThis is the second line.aThis is the third line.\n"
357 | updateTestCase (1,19) (2,0) "a" str "This is the first line.\nThis is the second aThis is the third line.\n"
358 | updateTestCase (1,0) (2,0) "" str "This is the first line.\nThis is the third line.\n"
359 | updateTestCase (1,0) (2,0) "a" str "This is the first line.\naThis is the third line.\n"
360 | updateTestCase (1,8) (2,8) "" str "This is the first line.\nThis is the third line.\n"
361 | updateTestCase (1,8) (2,8) "a " str "This is the first line.\nThis is a the third line.\n"
362 | updateTestCase (1,8) (2,9) "x" str "This is the first line.\nThis is xhe third line.\n"
363 | updateTestCase (1,23) (2,22) "" str "This is the first line.\nThis is the second line.\n"
364 | updateTestCase (1,23) (2,22) "a" str "This is the first line.\nThis is the second linea.\n"
365 | updateTestCase (1,23) (2,23) "a" str "This is the first line.\nThis is the second linea\n"
366 | updateTestCase (0,23) (1,24) "" str "This is the first line.\nThis is the third line.\n"
367 | updateTestCase (1,0) (1,40) "" str "This is the first line.\n\nThis is the third line.\n"
368 | updateTestCase (1,0) (1,24) "" str "This is the first line.\n\nThis is the third line.\n"
369 | updateTestCase (1,10) (1,40) "" str "This is the first line.\nThis is th\nThis is the third line.\n"
370 | updateTestCase (1,0) (4,40) "" str "This is the first line.\n\n"
371 | updateTestCase (1,10) (4,40) "" str "This is the first line.\nThis is th\n"
376 | wordPosTestCase (0,0) "" ""
377 | wordPosTestCase (0,10) "" ""
378 | wordPosTestCase (1,0) "" ""
379 | wordPosTestCase (1,10) "" ""
382 | wordPosTestCase (0,0) "\n" ""
383 | wordPosTestCase (0,10) "\n" ""
384 | wordPosTestCase (1,0) "\n" ""
385 | wordPosTestCase (1,10) "\n" ""
386 | wordPosTestCase (2,0) "\n" ""
387 | wordPosTestCase (2,10) "\n" ""
390 | wordPosTestCase (0,0) " " ""
391 | wordPosTestCase (0,10) " " ""
392 | wordPosTestCase (1,0) " " ""
393 | wordPosTestCase (1,10) " " ""
398 | let str = "This is a line."
399 | wordPosTestCase (0,0) str "This"
400 | wordPosTestCase (0,2) str "This"
401 | wordPosTestCase (0,4) str "This"
402 | wordPosTestCase (0,5) str "is"
403 | wordPosTestCase (0,6) str "is"
404 | wordPosTestCase (0,7) str "is"
405 | wordPosTestCase (0,8) str "a"
406 | wordPosTestCase (0,9) str "a"
407 | wordPosTestCase (0,10) str "line."
408 | wordPosTestCase (0,12) str "line."
409 | wordPosTestCase (0,14) str "line."
410 | wordPosTestCase (0,20) str "line."
411 | wordPosTestCase (1,0) str ""
416 | let str = "This is a line.\n"
417 | wordPosTestCase (0,0) str "This"
418 | wordPosTestCase (0,2) str "This"
419 | wordPosTestCase (0,4) str "This"
420 | wordPosTestCase (0,5) str "is"
421 | wordPosTestCase (0,6) str "is"
422 | wordPosTestCase (0,7) str "is"
423 | wordPosTestCase (0,8) str "a"
424 | wordPosTestCase (0,9) str "a"
425 | wordPosTestCase (0,10) str "line."
426 | wordPosTestCase (0,12) str "line."
427 | wordPosTestCase (0,14) str "line."
428 | wordPosTestCase (0,20) str "line."
429 | wordPosTestCase (1,0) str ""
434 | let str = "This is the first line.\nThis is the second line.\nThis is the third line."
435 | wordPosTestCase (0,0) str "This"
436 | wordPosTestCase (0,2) str "This"
437 | wordPosTestCase (0,4) str "This"
438 | wordPosTestCase (0,5) str "is"
439 | wordPosTestCase (0,6) str "is"
440 | wordPosTestCase (0,7) str "is"
441 | wordPosTestCase (0,8) str "the"
442 | wordPosTestCase (0,12) str "first"
443 | wordPosTestCase (0,21) str "line."
444 | wordPosTestCase (0,30) str "line."
445 | wordPosTestCase (1,0) str "This"
446 | wordPosTestCase (1,14) str "second"
447 | wordPosTestCase (1,21) str "line."
448 | wordPosTestCase (1,30) str "line."
449 | wordPosTestCase (2,0) str "This"
450 | wordPosTestCase (2,14) str "third"
451 | wordPosTestCase (2,21) str "line."
452 | wordPosTestCase (2,30) str "line."
453 | wordPosTestCase (3,0) str ""
454 | wordPosTestCase (3,30) str ""
459 | let str = "This is the first line.\nThis is the second line.\nThis is the third line.\n"
460 | wordPosTestCase (0,0) str "This"
461 | wordPosTestCase (0,2) str "This"
462 | wordPosTestCase (0,4) str "This"
463 | wordPosTestCase (0,5) str "is"
464 | wordPosTestCase (0,6) str "is"
465 | wordPosTestCase (0,7) str "is"
466 | wordPosTestCase (0,8) str "the"
467 | wordPosTestCase (0,12) str "first"
468 | wordPosTestCase (0,21) str "line."
469 | wordPosTestCase (0,30) str "line."
470 | wordPosTestCase (1,0) str "This"
471 | wordPosTestCase (1,14) str "second"
472 | wordPosTestCase (1,21) str "line."
473 | wordPosTestCase (1,30) str "line."
474 | wordPosTestCase (2,0) str "This"
475 | wordPosTestCase (2,14) str "third"
476 | wordPosTestCase (2,21) str "line."
477 | wordPosTestCase (2,30) str "line."
478 | wordPosTestCase (3,0) str ""
479 | wordPosTestCase (3,30) str ""