Skip to content

Commit

Permalink
Refactor getLine to return TextLines / Rope
Browse files Browse the repository at this point in the history
  • Loading branch information
Bodigrim committed Jul 16, 2024
1 parent 023271e commit 3a46aaf
Show file tree
Hide file tree
Showing 10 changed files with 45 additions and 33 deletions.
8 changes: 4 additions & 4 deletions src/Data/Text/Lines/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -245,20 +245,20 @@ splitAtLine :: HasCallStack => Word -> TextLines -> (TextLines, TextLines)
splitAtLine k = splitAtPosition (Position k 0)

-- | Get line with given 0-based index, O(1).
-- The resulting Text does not contain @\\n@ characters..
-- Returns "" if the line index is out of bounds.
-- The result does not contain @\\n@ characters..
-- Returns 'mempty' if the line index is out of bounds.
--
-- >>> :set -XOverloadedStrings
-- >>> map (\l -> getLine l "fя𐀀\n☺bar\n\n") [0..3]
-- ["fя𐀀","☺bar","",""]
--
-- @since 0.3
getLine :: Word -> TextLines -> Text
getLine :: Word -> TextLines -> TextLines
getLine line (TextLines t@(Text arr off len) nls)
| intToWord (U.length nls) < line = mempty
| otherwise =
let lineIdx = wordToInt line
in case (nls U.!? (lineIdx - 1), nls U.!? lineIdx) of
in (`TextLines` mempty) $ case (nls U.!? (lineIdx - 1), nls U.!? lineIdx) of
(Nothing, Nothing) -> t
(Nothing, Just endNl) -> Text arr off (endNl - off) -- branch triggered by `getLine 0 "a\n"`
(Just startNl, Nothing) -> Text arr (startNl + 1) (len + off - startNl - 1)
Expand Down
15 changes: 9 additions & 6 deletions src/Data/Text/Mixed/Rope.hs
Original file line number Diff line number Diff line change
Expand Up @@ -567,20 +567,23 @@ utf16SplitAtPosition (Utf16.Position l c) rp = do
Just (beforeLine <> beforeColumn, afterColumn)

-- | Get a line by its 0-based index.
-- Returns @""@ if the index is out of bounds.
-- Returns 'mempty' if the index is out of bounds.
-- The result doesn't contain @\\n@ characters.
--
-- >>> :set -XOverloadedStrings
-- >>> map (\l -> getLine l "foo\nbar\n😊😊\n\n") [0..3]
-- ["foo","bar","😊😊",""]
--
-- @since 0.3
getLine :: Word -> Rope -> Text
getLine :: Word -> Rope -> Rope
getLine lineIdx rp =
case T.unsnoc firstLine of
Just (firstLineInit, '\n') -> firstLineInit
case charSplitAt (charLength firstLine - 1) firstLine of
(firstLineInit, firstLineLast)
| isNewline firstLineLast -> firstLineInit
_ -> firstLine
where
(_, afterIndex) = splitAtLine lineIdx rp
(firstLineRope, _ ) = splitAtLine 1 afterIndex
firstLine = toText firstLineRope
(firstLine, _ ) = splitAtLine 1 afterIndex

isNewline :: Rope -> Bool
isNewline = (== T.singleton '\n') . toText
15 changes: 9 additions & 6 deletions src/Data/Text/Rope.hs
Original file line number Diff line number Diff line change
Expand Up @@ -391,20 +391,23 @@ splitAtPosition (Position l c) rp = (beforeLine <> beforeColumn, afterColumn)
(beforeColumn, afterColumn) = splitAt c afterLine

-- | Get a line by its 0-based index.
-- Returns @""@ if the index is out of bounds.
-- Returns 'mempty' if the index is out of bounds.
-- The result doesn't contain @\\n@ characters.
--
-- >>> :set -XOverloadedStrings
-- >>> map (\l -> getLine l "foo\nbar\n😊😊\n\n") [0..3]
-- ["foo","bar","😊😊",""]
--
-- @since 0.3
getLine :: Word -> Rope -> Text
getLine :: Word -> Rope -> Rope
getLine lineIdx rp =
case T.unsnoc firstLine of
Just (firstLineInit, '\n') -> firstLineInit
case splitAt (length firstLine - 1) firstLine of
(firstLineInit, firstLineLast)
| isNewline firstLineLast -> firstLineInit
_ -> firstLine
where
(_, afterIndex) = splitAtLine lineIdx rp
(firstLineRope, _ ) = splitAtLine 1 afterIndex
firstLine = toText firstLineRope
(firstLine, _ ) = splitAtLine 1 afterIndex

isNewline :: Rope -> Bool
isNewline = (== T.singleton '\n') . toText
15 changes: 9 additions & 6 deletions src/Data/Text/Utf16/Rope.hs
Original file line number Diff line number Diff line change
Expand Up @@ -394,20 +394,23 @@ splitAtPosition (Position l c) rp = do
Just (beforeLine <> beforeColumn, afterColumn)

-- | Get a line by its 0-based index.
-- Returns @""@ if the index is out of bounds.
-- Returns 'mempty' if the index is out of bounds.
-- The result doesn't contain @\\n@ characters.
--
-- >>> :set -XOverloadedStrings
-- >>> map (\l -> getLine l "foo\nbar\n😊😊\n\n") [0..3]
-- ["foo","bar","😊😊",""]
--
-- @since 0.3
getLine :: Word -> Rope -> Text
getLine :: Word -> Rope -> Rope
getLine lineIdx rp =
case T.unsnoc firstLine of
Just (firstLineInit, '\n') -> firstLineInit
case splitAt (length firstLine - 1) firstLine of
Just (firstLineInit, firstLineLast)
| isNewline firstLineLast -> firstLineInit
_ -> firstLine
where
(_, afterIndex) = splitAtLine lineIdx rp
(firstLineRope, _ ) = splitAtLine 1 afterIndex
firstLine = toText firstLineRope
(firstLine, _ ) = splitAtLine 1 afterIndex

isNewline :: Rope -> Bool
isNewline = (== T.singleton '\n') . toText
15 changes: 9 additions & 6 deletions src/Data/Text/Utf8/Rope.hs
Original file line number Diff line number Diff line change
Expand Up @@ -395,20 +395,23 @@ splitAtPosition (Position l c) rp = do
Just (beforeLine <> beforeColumn, afterColumn)

-- | Get a line by its 0-based index.
-- Returns @""@ if the index is out of bounds.
-- Returns 'mempty' if the index is out of bounds.
-- The result doesn't contain @\\n@ characters.
--
-- >>> :set -XOverloadedStrings
-- >>> map (\l -> getLine l "foo\nbar\n😊😊\n\n") [0..3]
-- ["foo","bar","😊😊",""]
--
-- @since 0.3
getLine :: Word -> Rope -> Text
getLine :: Word -> Rope -> Rope
getLine lineIdx rp =
case T.unsnoc firstLine of
Just (firstLineInit, '\n') -> firstLineInit
case splitAt (length firstLine - 1) firstLine of
Just (firstLineInit, firstLineLast)
| isNewline firstLineLast -> firstLineInit
_ -> firstLine
where
(_, afterIndex) = splitAtLine lineIdx rp
(firstLineRope, _ ) = splitAtLine 1 afterIndex
firstLine = toText firstLineRope
(firstLine, _ ) = splitAtLine 1 afterIndex

isNewline :: Rope -> Bool
isNewline = (== T.singleton '\n') . toText
2 changes: 1 addition & 1 deletion test/CharLines.hs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ testSuite = testGroup "Char Lines"

, testProperty "forall i in bounds: getLine i x == lines x !! i" $
\x -> let lns = lines x in
conjoin $ zipWith (\idx ln -> getLine idx x === ln) [0..] lns
conjoin $ zipWith (\idx ln -> getLine idx x === fromText ln) [0..] lns
, testProperty "forall i out of bounds: getLine i x == mempty" $
\x (Positive offset) ->
let maxIdx = L.genericLength (lines x) - 1
Expand Down
2 changes: 1 addition & 1 deletion test/CharRope.hs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ testSuite = testGroup "Char Rope"

, testProperty "forall i in bounds: getLine i x == lines x !! i" $
\x -> let lns = Rope.lines x in
conjoin $ L.zipWith (\idx ln -> Rope.getLine idx x === ln) [0..] lns
conjoin $ L.zipWith (\idx ln -> Rope.getLine idx x === Rope.fromText ln) [0..] lns
, testProperty "forall i out of bounds: getLine i x == mempty" $
\x (Positive offset) ->
let maxIdx = L.genericLength (Rope.lines x) - 1
Expand Down
2 changes: 1 addition & 1 deletion test/MixedRope.hs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ testSuite = testGroup "Utf16 Mixed"

, testProperty "forall i in bounds: getLine i x == lines x !! i" $
\x -> let lns = Mixed.lines x in
conjoin $ L.zipWith (\idx ln -> Mixed.getLine idx x === ln) [0..] lns
conjoin $ L.zipWith (\idx ln -> Mixed.getLine idx x === Mixed.fromText ln) [0..] lns
, testProperty "forall i out of bounds: getLine i x == mempty" $
\x (Positive offset) ->
let maxIdx = L.genericLength (Mixed.lines x) - 1
Expand Down
2 changes: 1 addition & 1 deletion test/Utf16Rope.hs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ testSuite = testGroup "Utf16 Rope"

, testProperty "forall i in bounds: getLine i x == lines x !! i" $
\x -> let lns = Rope.lines x in
conjoin $ L.zipWith (\idx ln -> Rope.getLine idx x === ln) [0..] lns
conjoin $ L.zipWith (\idx ln -> Rope.getLine idx x === Rope.fromText ln) [0..] lns
, testProperty "forall i out of bounds: getLine i x == mempty" $
\x (Positive offset) ->
let maxIdx = L.genericLength (Rope.lines x) - 1
Expand Down
2 changes: 1 addition & 1 deletion test/Utf8Rope.hs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ testSuite = testGroup "Utf8 Rope"

, testProperty "forall i in bounds: getLine i x == lines x !! i" $
\x -> let lns = Rope.lines x in
conjoin $ L.zipWith (\idx ln -> Rope.getLine idx x === ln) [0..] lns
conjoin $ L.zipWith (\idx ln -> Rope.getLine idx x === Rope.fromText ln) [0..] lns
, testProperty "forall i out of bounds: getLine i x == mempty" $
\x (Positive offset) ->
let maxIdx = L.genericLength (Rope.lines x) - 1
Expand Down

0 comments on commit 3a46aaf

Please sign in to comment.