text-rope-0.3: Text lines and ropes

Copyright | (c) 2021-2022 Andrew Lelechenko
License | BSD3
Maintainer | Andrew Lelechenko <andrew.lelechenko@gmail.com>
Safe Haskell | None
Language | Haskell2010

Data.Text.Mixed.Rope

Contents

- Lines
- Code points
- UTF-16 code units
- UTF-8 code units

Description

Since: 0.3

Synopsis

- data Rope
- fromText :: Text -> Rope
- fromTextLines :: TextLines -> Rope
- toText :: Rope -> Text
- toTextLines :: Rope -> TextLines
- null :: Rope -> Bool
- lines :: Rope -> [Text]
- lengthInLines :: Rope -> Word
- splitAtLine :: Word -> Rope -> (Rope, Rope)
- getLine :: Word -> Rope -> Rope
- charLength :: Rope -> Word
- charSplitAt :: Word -> Rope -> (Rope, Rope)
- charLengthAsPosition :: Rope -> Position
- charSplitAtPosition :: Position -> Rope -> (Rope, Rope)
- utf16Length :: Rope -> Word
- utf16SplitAt :: Word -> Rope -> Maybe (Rope, Rope)
- utf16LengthAsPosition :: Rope -> Position
- utf16SplitAtPosition :: Position -> Rope -> Maybe (Rope, Rope)
- utf8Length :: Rope -> Word
- utf8SplitAt :: Word -> Rope -> Maybe (Rope, Rope)
- utf8LengthAsPosition :: Rope -> Position
- utf8SplitAtPosition :: Position -> Rope -> Maybe (Rope, Rope)

# Documentation

data Rope #

Rope of `Text` chunks with logarithmic concatenation. This rope offers three interfaces: one based on code points, one based on UTF-16 code units, and one based on UTF-8 code units. This comes with a price of more bookkeeping and is less performant than Data.Text.Rope, Data.Text.Utf8.Rope, or Data.Text.Utf16.Rope.

#### Instances

Instances details

NFData Rope # |
Instance details Defined in Data.Text.Mixed.Rope Methods rnf :: Rope -> () #
Monoid Rope # |
Instance details Defined in Data.Text.Mixed.Rope Methods mempty :: Rope # mappend :: Rope -> Rope -> Rope # mconcat :: [Rope] -> Rope #
Semigroup Rope # |
Instance details Defined in Data.Text.Mixed.Rope Methods (<>) :: Rope -> Rope -> Rope # sconcat :: NonEmpty Rope -> Rope # stimes :: Integral b => b -> Rope -> Rope #
IsString Rope # |
Instance details Defined in Data.Text.Mixed.Rope Methods fromString :: String -> Rope #
Show Rope # |
Instance details Defined in Data.Text.Mixed.Rope Methods showsPrec :: Int -> Rope -> ShowS # show :: Rope -> String # showList :: [Rope] -> ShowS #
Eq Rope # |
Instance details Defined in Data.Text.Mixed.Rope Methods (==) :: Rope -> Rope -> Bool # (/=) :: Rope -> Rope -> Bool #
Ord Rope # |
Instance details Defined in Data.Text.Mixed.Rope Methods compare :: Rope -> Rope -> Ordering # (<) :: Rope -> Rope -> Bool # (<=) :: Rope -> Rope -> Bool # (>) :: Rope -> Rope -> Bool # (>=) :: Rope -> Rope -> Bool # max :: Rope -> Rope -> Rope # min :: Rope -> Rope -> Rope #

fromText :: Text -> Rope #

Create from `Text`, linear time.

fromTextLines :: TextLines -> Rope #

Create from `TextLines`, linear time.

toText :: Rope -> Text #

Glue chunks into `Text`, linear time.

toTextLines :: Rope -> TextLines #

Glue chunks into `TextLines`, linear time.

null :: Rope -> Bool #

Check whether a rope is empty, O(1).

# Lines

lines :: Rope -> [Text] #

Split into lines by `\n`, similar to `Data.Text.``lines`. Each line is produced in O(1).

    >>> :set -XOverloadedStrings
    >>> lines ""
    []
    >>> lines "foo"
    ["foo"]
    >>> lines "foo\n"
    ["foo"]
    >>> lines "foo\n\n"
    ["foo",""]
    >>> lines "foo\nbar"
    ["foo","bar"]

lengthInLines :: Rope -> Word #

Equivalent to `length` . `lines`, but in logarithmic time.

    >>> :set -XOverloadedStrings
    >>> lengthInLines ""
    0
    >>> lengthInLines "foo"
    1
    >>> lengthInLines "foo\n"
    1
    >>> lengthInLines "foo\n\n"
    2
    >>> lengthInLines "foo\nbar"
    2

If you do not care about ignoring the last newline character, you can use `posLine` . `charLengthAsPosition` instead, which works in O(1).

splitAtLine :: Word -> Rope -> (Rope, Rope) #

Split at given line, logarithmic time.

    >>> :set -XOverloadedStrings
    >>> map (\l -> splitAtLine l "foo\nbar") [0..3]
    [("","foo\nbar"),("foo\n","bar"),("foo\nbar",""),("foo\nbar","")]

getLine :: Word -> Rope -> Rope #

Get a line by its 0-based index. 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

# Code points

charLength :: Rope -> Word #

Length in code points, similar to `Data.Text.``length`, O(1).

    >>> :set -XOverloadedStrings
    >>> charLength "fя𐀀"
    3

charSplitAt :: Word -> Rope -> (Rope, Rope) #

Split at given code point, similar to `Data.Text.``splitAt`. Takes linear time.

    >>> :set -XOverloadedStrings
    >>> map (\c -> charSplitAt c "fя𐀀") [0..4]
    [("","fя𐀀"),("f","я𐀀"),("fя","𐀀"),("fя𐀀",""),("fя𐀀","")]

charLengthAsPosition :: Rope -> Position #

Measure text length as an amount of lines and columns. Time is linear in the length of the last line.

    >>> :set -XOverloadedStrings
    >>> charLengthAsPosition "f𐀀"
    Position {posLine = 0, posColumn = 2}
    >>> charLengthAsPosition "f\n𐀀"
    Position {posLine = 1, posColumn = 1}
    >>> charLengthAsPosition "f\n𐀀\n"
    Position {posLine = 2, posColumn = 0}

charSplitAtPosition :: Position -> Rope -> (Rope, Rope) #

Combination of `splitAtLine` and subsequent `charSplitAt`. Time is linear in `posColumn` and logarithmic in `posLine`.

    >>> :set -XOverloadedStrings
    >>> charSplitAtPosition (Position 1 0) "f\n𐀀я"
    ("f\n","𐀀я")
    >>> charSplitAtPosition (Position 1 1) "f\n𐀀я"
    ("f\n𐀀","я")
    >>> charSplitAtPosition (Position 1 2) "f\n𐀀я"
    ("f\n𐀀я","")
    >>> charSplitAtPosition (Position 0 2) "f\n𐀀я"
    ("f\n","𐀀я")
    >>> charSplitAtPosition (Position 0 3) "f\n𐀀я"
    ("f\n𐀀","я")
    >>> charSplitAtPosition (Position 0 4) "f\n𐀀я"
    ("f\n𐀀я","")

# UTF-16 code units

utf16Length :: Rope -> Word #

Length in UTF-16 code units, O(1).

    >>> :set -XOverloadedStrings
    >>> utf16Length "fя𐀀"
    4

utf16SplitAt :: Word -> Rope -> Maybe (Rope, Rope) #

Split at given UTF-16 code unit. If requested number of code units splits a code point in half, return `Nothing`. Takes linear time.

    >>> :set -XOverloadedStrings
    >>> map (\c -> utf16SplitAt c "fя𐀀") [0..4]
    [Just ("","fя𐀀"),Just ("f","я𐀀"),Just ("fя","𐀀"),Nothing,Just ("fя𐀀","")]

utf16LengthAsPosition :: Rope -> Position #

Measure text length as an amount of lines and columns. Time is linear in the length of the last line.

    >>> :set -XOverloadedStrings
    >>> utf16LengthAsPosition "f𐀀"
    Position {posLine = 0, posColumn = 3}
    >>> utf16LengthAsPosition "f\n𐀀"
    Position {posLine = 1, posColumn = 2}
    >>> utf16LengthAsPosition "f\n𐀀\n"
    Position {posLine = 2, posColumn = 0}

utf16SplitAtPosition :: Position -> Rope -> Maybe (Rope, Rope) #

Combination of `splitAtLine` and subsequent `utf16SplitAt`. Time is linear in `posColumn` and logarithmic in `posLine`.

    >>> :set -XOverloadedStrings
    >>> utf16SplitAtPosition (Position 1 0) "f\n𐀀я"
    Just ("f\n","𐀀я")
    >>> utf16SplitAtPosition (Position 1 1) "f\n𐀀я"
    Nothing
    >>> utf16SplitAtPosition (Position 1 2) "f\n𐀀я"
    Just ("f\n𐀀","я")
    >>> utf16SplitAtPosition (Position 0 2) "f\n𐀀я"
    Just ("f\n","𐀀я")
    >>> utf16SplitAtPosition (Position 0 3) "f\n𐀀я"
    Nothing
    >>> utf16SplitAtPosition (Position 0 4) "f\n𐀀я"
    Just ("f\n𐀀","я")

# UTF-8 code units

utf8Length :: Rope -> Word #

Length in UTF-8 code units aka bytes, O(1).

    >>> :set -XOverloadedStrings
    >>> utf8Length "fя𐀀"
    4

utf8SplitAt :: Word -> Rope -> Maybe (Rope, Rope) #

Split at given UTF-8 code unit aka byte. If requested number of code units splits a code point in half, return `Nothing`. Takes linear time.

utf8LengthAsPosition :: Rope -> Position #

Measure text length as an amount of lines and columns. Time is linear in the length of the last line.

utf8SplitAtPosition :: Position -> Rope -> Maybe (Rope, Rope) #

Combination of `splitAtLine` and subsequent `utf8SplitAt`. Time is linear in `posColumn` and logarithmic in `posLine`.