Skip to content

Commit 48f1e85

Browse files
committed
Add some functions for ranges too
1 parent 2971653 commit 48f1e85

File tree

1 file changed

+35
-8
lines changed

1 file changed

+35
-8
lines changed

lsp/src/Language/LSP/VFS.hs

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ module Language.LSP.VFS
4848
, CodePointPosition (..)
4949
, codePointPositionToPosition
5050
, positionToCodePointPosition
51+
, CodePointRange (..)
52+
, codePointRangeToRange
53+
, rangeToCodePointRange
5154

5255
-- * manipulating the file contents
5356
, rangeLinesFromVfs
@@ -352,8 +355,8 @@ changeChars logger str start finish new = do
352355

353356
-- ---------------------------------------------------------------------
354357

355-
-- | A position, like a 'J.Position', but where the offsets in the line are measured in Unicode code points
356-
-- instead of UTF-16 code units.
358+
-- | A position, like a 'J.Position', but where the offsets in the line are measured in
359+
-- Unicode code points instead of UTF-16 code units.
357360
data CodePointPosition =
358361
CodePointPosition
359362
{ -- | Line position in a document (zero-based).
@@ -362,6 +365,14 @@ data CodePointPosition =
362365
, _character :: J.UInt
363366
} deriving (Show, Read, Eq, Ord)
364367

368+
-- | A range, like a 'J.Range', but where the offsets in the line are measured in
369+
-- Unicode code points instead of UTF-16 code units.
370+
data CodePointRange =
371+
CodePointRange
372+
{ _start :: CodePointPosition -- ^ The range's start position.
373+
, _end :: CodePointPosition -- ^ The range's end position.
374+
} deriving (Show, Read, Eq, Ord)
375+
365376
{- Note [Converting between code points and code units]
366377
This is inherently a somewhat expensive operation, but we take some care to minimize the cost.
367378
In particular, we use the good asymptotics of 'Rope' to our advantage:
@@ -386,7 +397,7 @@ extractLine rope l = do
386397

387398
let (_, suffix) = Rope.splitAtLine l rope
388399
(prefix, _) = Rope.splitAtLine 1 suffix
389-
pure $ prefix
400+
pure prefix
390401

391402
-- | Translate a code-point offset into a code-unit offset.
392403
-- Linear in the length of the rope.
@@ -401,7 +412,7 @@ codePointOffsetToCodeUnitOffset rope offset = do
401412
-- Get the length of the prefix in *code units*
402413
pure $ Rope.length utf16Prefix
403414

404-
-- | Translate a code-unit offset into a code-point offset.
415+
-- | Translate a UTF-16 code-unit offset into a code-point offset.
405416
-- Linear in the length of the rope.
406417
codeUnitOffsetToCodePointOffset :: Rope.Rope -> Word -> Maybe Word
407418
codeUnitOffsetToCodePointOffset rope offset = do
@@ -418,8 +429,6 @@ codeUnitOffsetToCodePointOffset rope offset = do
418429
--
419430
-- Will return 'Nothing' if the requested position is out of bounds of the document.
420431
--
421-
-- We need the file itself because this requires translating between code points and code units.
422-
--
423432
-- Logarithmic in the number of lines in the document, and linear in the length of the line containing
424433
-- the position.
425434
codePointPositionToPosition :: VirtualFile -> CodePointPosition -> Maybe J.Position
@@ -433,12 +442,20 @@ codePointPositionToPosition vFile (CodePointPosition l cpc) = do
433442
cuc <- codePointOffsetToCodeUnitOffset utfLine (fromIntegral cpc)
434443
pure $ J.Position l (fromIntegral cuc)
435444

445+
-- | Given a virtual file, translate a 'CodePointRange' in that file into a 'J.Range' in that file.
446+
--
447+
-- Will return 'Nothing' if any of the positions are out of bounds of the document.
448+
--
449+
-- Logarithmic in the number of lines in the document, and linear in the length of the lines containing
450+
-- the positions.
451+
codePointRangeToRange :: VirtualFile -> CodePointRange -> Maybe J.Range
452+
codePointRangeToRange vFile (CodePointRange b e) =
453+
J.Range <$> codePointPositionToPosition vFile b <*> codePointPositionToPosition vFile e
454+
436455
-- | Given a virtual file, translate a 'J.Position' in that file into a 'CodePointPosition' in that file.
437456
--
438457
-- Will return 'Nothing' if the requested position lies inside a code point, or if it is out of bounds of the document.
439458
--
440-
-- We need the file itself because this requires translating between code unit and code points.
441-
--
442459
-- Logarithmic in the number of lines in the document, and linear in the length of the line containing
443460
-- the position.
444461
positionToCodePointPosition :: VirtualFile -> J.Position -> Maybe CodePointPosition
@@ -450,6 +467,16 @@ positionToCodePointPosition vFile (J.Position l cuc) = do
450467
cpc <- codeUnitOffsetToCodePointOffset utf16Line (fromIntegral cuc)
451468
pure $ CodePointPosition l (fromIntegral cpc)
452469

470+
-- | Given a virtual file, translate a 'J.Range' in that file into a 'CodePointRange' in that file.
471+
--
472+
-- Will return 'Nothing' if any of the positions are out of bounds of the document.
473+
--
474+
-- Logarithmic in the number of lines in the document, and linear in the length of the lines containing
475+
-- the positions.
476+
rangeToCodePointRange :: VirtualFile -> J.Range -> Maybe CodePointRange
477+
rangeToCodePointRange vFile (J.Range b e) =
478+
CodePointRange <$> positionToCodePointPosition vFile b <*> positionToCodePointPosition vFile e
479+
453480
-- ---------------------------------------------------------------------
454481

455482
-- TODO:AZ:move this to somewhere sane

0 commit comments

Comments
 (0)