diff --git a/src/Data/Text/Lines/Internal.hs b/src/Data/Text/Lines/Internal.hs index 54432b3..033adb3 100644 --- a/src/Data/Text/Lines/Internal.hs +++ b/src/Data/Text/Lines/Internal.hs @@ -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) diff --git a/src/Data/Text/Mixed/Rope.hs b/src/Data/Text/Mixed/Rope.hs index 8e9eca1..e4238b4 100644 --- a/src/Data/Text/Mixed/Rope.hs +++ b/src/Data/Text/Mixed/Rope.hs @@ -567,7 +567,7 @@ 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 @@ -575,12 +575,15 @@ utf16SplitAtPosition (Utf16.Position l c) rp = do -- ["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 diff --git a/src/Data/Text/Rope.hs b/src/Data/Text/Rope.hs index 23e95e7..2781ed3 100644 --- a/src/Data/Text/Rope.hs +++ b/src/Data/Text/Rope.hs @@ -391,7 +391,7 @@ 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 @@ -399,12 +399,15 @@ splitAtPosition (Position l c) rp = (beforeLine <> beforeColumn, afterColumn) -- ["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 diff --git a/src/Data/Text/Utf16/Rope.hs b/src/Data/Text/Utf16/Rope.hs index 27ffe0e..dc265f7 100644 --- a/src/Data/Text/Utf16/Rope.hs +++ b/src/Data/Text/Utf16/Rope.hs @@ -394,7 +394,7 @@ 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 @@ -402,12 +402,15 @@ splitAtPosition (Position l c) rp = do -- ["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 diff --git a/src/Data/Text/Utf8/Rope.hs b/src/Data/Text/Utf8/Rope.hs index 33e4b67..9d78f9b 100644 --- a/src/Data/Text/Utf8/Rope.hs +++ b/src/Data/Text/Utf8/Rope.hs @@ -395,7 +395,7 @@ 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 @@ -403,12 +403,15 @@ splitAtPosition (Position l c) rp = do -- ["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 diff --git a/test/CharLines.hs b/test/CharLines.hs index de8008a..887d8b9 100644 --- a/test/CharLines.hs +++ b/test/CharLines.hs @@ -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 diff --git a/test/CharRope.hs b/test/CharRope.hs index 1191179..10b1cfe 100644 --- a/test/CharRope.hs +++ b/test/CharRope.hs @@ -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 diff --git a/test/MixedRope.hs b/test/MixedRope.hs index c7f4cc1..f18d49d 100644 --- a/test/MixedRope.hs +++ b/test/MixedRope.hs @@ -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 diff --git a/test/Utf16Rope.hs b/test/Utf16Rope.hs index 7009ff5..105dd96 100644 --- a/test/Utf16Rope.hs +++ b/test/Utf16Rope.hs @@ -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 diff --git a/test/Utf8Rope.hs b/test/Utf8Rope.hs index 89fa332..ad725cd 100644 --- a/test/Utf8Rope.hs +++ b/test/Utf8Rope.hs @@ -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