@@ -388,48 +388,66 @@ extractLine rope l = do
388388 (prefix, _) = Rope. splitAtLine 1 suffix
389389 pure $ prefix
390390
391+ -- | Translate a code-point offset into a code-unit offset.
392+ -- Linear in the length of the rope.
393+ codePointOffsetToCodeUnitOffset :: URope. Rope -> Word -> Maybe Word
394+ codePointOffsetToCodeUnitOffset rope offset = do
395+ -- Check for the position being out of bounds
396+ guard $ offset <= URope. length rope
397+ -- Split at the given position in *code points*
398+ let (prefix, _) = URope. splitAt offset rope
399+ -- Convert the prefix to a rope using *code units*
400+ utf16Prefix = Rope. fromText $ URope. toText prefix
401+ -- Get the length of the prefix in *code units*
402+ pure $ Rope. length utf16Prefix
403+
404+ -- | Translate a code-unit offset into a code-point offset.
405+ -- Linear in the length of the rope.
406+ codeUnitOffsetToCodePointOffset :: Rope. Rope -> Word -> Maybe Word
407+ codeUnitOffsetToCodePointOffset rope offset = do
408+ -- Check for the position being out of bounds
409+ guard $ offset <= Rope. length rope
410+ -- Split at the given position in *code units*
411+ (prefix, _) <- Rope. splitAt offset rope
412+ -- Convert the prefixto a rope using *code points*
413+ let utfPrefix = URope. fromText $ Rope. toText prefix
414+ -- Get the length of the prefix in *code points*
415+ pure $ URope. length utfPrefix
416+
391417-- | Given a virtual file, translate a 'CodePointPosition' in that file into a 'J.Position' in that file.
392418--
393419-- Will return 'Nothing' if the requested position is out of bounds of the document.
394420--
395421-- We need the file itself because this requires translating between code points and code units.
422+ --
423+ -- Logarithmic in the number of lines in the document, and linear in the length of the line containing
424+ -- the position.
396425codePointPositionToPosition :: VirtualFile -> CodePointPosition -> Maybe J. Position
397426codePointPositionToPosition vFile (CodePointPosition l cpc) = do
398427 -- See Note [Converting between code points and code units]
399428 let text = _file_text vFile
400429 utf16Line <- extractLine text (fromIntegral l)
401-
402430 -- Convert the line a rope using *code points*
403431 let utfLine = URope. fromText $ Rope. toText utf16Line
404- -- Check for the position being out of bounds
405- guard $ (fromIntegral cpc) <= URope. length utfLine
406- -- Split at the given position in *code points*
407- let (utfLinePrefix, _) = URope. splitAt (fromIntegral cpc) utfLine
408- -- Convert the prefix to a rope using *code units*
409- utf16LinePrefix = Rope. fromText $ URope. toText utfLinePrefix
410- -- Get the length of the prefix in *code units*
411- cuc = Rope. length utf16LinePrefix
432+
433+ cuc <- codePointOffsetToCodeUnitOffset utfLine (fromIntegral cpc)
412434 pure $ J. Position l (fromIntegral cuc)
413435
414436-- | Given a virtual file, translate a 'J.Position' in that file into a 'CodePointPosition' in that file.
415437--
416438-- Will return 'Nothing' if the requested position lies inside a code point, or if it is out of bounds of the document.
417439--
418440-- We need the file itself because this requires translating between code unit and code points.
441+ --
442+ -- Logarithmic in the number of lines in the document, and linear in the length of the line containing
443+ -- the position.
419444positionToCodePointPosition :: VirtualFile -> J. Position -> Maybe CodePointPosition
420445positionToCodePointPosition vFile (J. Position l cuc) = do
421446 -- See Note [Converting between code points and code units]
422447 let text = _file_text vFile
423448 utf16Line <- extractLine text (fromIntegral l)
424449
425- -- Check for the position being out of bounds
426- guard $ (fromIntegral cuc) <= Rope. length utf16Line
427- -- Split at the given position in *code units*
428- (utf16LinePrefix, _) <- Rope. splitAt (fromIntegral cuc) utf16Line
429- -- Convert the prefixto a rope using *code points*
430- let utfLinePrefix = URope. fromText $ Rope. toText utf16LinePrefix
431- -- Get the length of the prefix in *code points*
432- cpc = URope. length utfLinePrefix
450+ cpc <- codeUnitOffsetToCodePointOffset utf16Line (fromIntegral cuc)
433451 pure $ CodePointPosition l (fromIntegral cpc)
434452
435453-- ---------------------------------------------------------------------
0 commit comments