@@ -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.
357360data 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]
366377This is inherently a somewhat expensive operation, but we take some care to minimize the cost.
367378In 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.
406417codeUnitOffsetToCodePointOffset :: Rope. Rope -> Word -> Maybe Word
407418codeUnitOffsetToCodePointOffset 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.
425434codePointPositionToPosition :: 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.
444461positionToCodePointPosition :: 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