@@ -378,48 +378,52 @@ line. Which is okay-ish, so long as we don't have very long lines.
378
378
379
379
-- | Extracts a specific line from a 'Rope.Rope'.
380
380
-- Logarithmic in the number of lines.
381
- extractLine :: Rope. Rope -> Word -> Rope. Rope
382
- extractLine rope l =
381
+ extractLine :: Rope. Rope -> Word -> Maybe Rope. Rope
382
+ extractLine rope l = do
383
+ -- Check for the line being out of bounds
384
+ let lastLine = Rope. posLine $ Rope. lengthAsPosition rope
385
+ guard $ l <= lastLine
386
+
383
387
let (_, suffix) = Rope. splitAtLine l rope
384
388
(prefix, _) = Rope. splitAtLine 1 suffix
385
- in prefix
389
+ pure $ prefix
386
390
387
391
-- | Given a virtual file, translate a 'CodePointPosition' in that file into a 'J.Position' in that file.
388
392
--
389
- -- If the position is out of bounds (i.e. beyond the last line or the last character in a line), then the
390
- -- greatest valid position less than that will be returned.
393
+ -- Will return 'Nothing' if the requested position is out of bounds of the document.
391
394
--
392
395
-- We need the file itself because this requires translating between code points and code units.
393
- codePointPositionToPosition :: VirtualFile -> CodePointPosition -> J. Position
394
- codePointPositionToPosition vFile (CodePointPosition l cpc) =
396
+ codePointPositionToPosition :: VirtualFile -> CodePointPosition -> Maybe J. Position
397
+ codePointPositionToPosition vFile (CodePointPosition l cpc) = do
395
398
-- See Note [Converting between code points and code units]
396
399
let text = _file_text vFile
397
- utf16Line = extractLine text (fromIntegral l)
400
+ utf16Line <- extractLine text (fromIntegral l)
398
401
399
- -- Convert the line a rope using *code points*
400
- utfLine = URope. fromText $ Rope. toText utf16Line
402
+ -- Convert the line a rope using *code points*
403
+ let utfLine = URope. fromText $ Rope. toText utf16Line
404
+ -- Check for the position being out of bounds
405
+ guard $ (fromIntegral cpc) <= URope. length utfLine
401
406
-- Split at the given position in *code points*
402
- (utfLinePrefix, _) = URope. splitAt (fromIntegral cpc) utfLine
407
+ let (utfLinePrefix, _) = URope. splitAt (fromIntegral cpc) utfLine
403
408
-- Convert the prefix to a rope using *code units*
404
409
utf16LinePrefix = Rope. fromText $ URope. toText utfLinePrefix
405
410
-- Get the length of the prefix in *code units*
406
411
cuc = Rope. length utf16LinePrefix
407
- in J. Position l (fromIntegral cuc)
412
+ pure $ J. Position l (fromIntegral cuc)
408
413
409
414
-- | Given a virtual file, translate a 'J.Position' in that file into a 'CodePointPosition' in that file.
410
415
--
411
- -- May fail if the requested position lies inside a code point.
412
- --
413
- -- If the position is out of bounds (i.e. beyond the last line or the last character in a line), then the
414
- -- greatest valid position less than that will be returned.
416
+ -- Will return 'Nothing' if the requested position lies inside a code point, or if it is out of bounds of the document.
415
417
--
416
418
-- We need the file itself because this requires translating between code unit and code points.
417
419
positionToCodePointPosition :: VirtualFile -> J. Position -> Maybe CodePointPosition
418
420
positionToCodePointPosition vFile (J. Position l cuc) = do
419
421
-- See Note [Converting between code points and code units]
420
422
let text = _file_text vFile
421
- utf16Line = extractLine text (fromIntegral l)
423
+ utf16Line <- extractLine text (fromIntegral l)
422
424
425
+ -- Check for the position being out of bounds
426
+ guard $ (fromIntegral cuc) <= Rope. length utf16Line
423
427
-- Split at the given position in *code units*
424
428
(utf16LinePrefix, _) <- Rope. splitAt (fromIntegral cuc) utf16Line
425
429
-- Convert the prefixto a rope using *code points*
0 commit comments