packages feed

rope-utf16-splay 0.2.0.0 → 0.3.1.0

raw patch · 8 files changed

+215/−50 lines, 8 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Data.Rope.UTF16.Internal: instance Data.Semigroup.Semigroup Data.Rope.UTF16.Internal.Chunk
- Data.Rope.UTF16.Internal: instance Data.Semigroup.Semigroup Data.Rope.UTF16.Internal.Rope
- Data.Rope.UTF16.Internal: instance Data.SplayTree.Measured Data.Rope.UTF16.Position.Position Data.Rope.UTF16.Internal.Chunk
- Data.Rope.UTF16.Internal: instance Data.SplayTree.Measured Data.Rope.UTF16.Position.Position Data.Rope.UTF16.Internal.Rope
- Data.Rope.UTF16.Position: Position :: !Int -> !RowColumn -> Position
- Data.Rope.UTF16.Position: RowColumn :: !Int -> !Int -> RowColumn
- Data.Rope.UTF16.Position: [codeUnits] :: Position -> !Int
- Data.Rope.UTF16.Position: [column] :: RowColumn -> !Int
- Data.Rope.UTF16.Position: [rowColumn] :: Position -> !RowColumn
- Data.Rope.UTF16.Position: [row] :: RowColumn -> !Int
- Data.Rope.UTF16.Position: data Position
- Data.Rope.UTF16.Position: data RowColumn
- Data.Rope.UTF16.Position: instance Data.Semigroup.Semigroup Data.Rope.UTF16.Position.Position
- Data.Rope.UTF16.Position: instance Data.Semigroup.Semigroup Data.Rope.UTF16.Position.RowColumn
- Data.Rope.UTF16.Position: instance GHC.Base.Monoid Data.Rope.UTF16.Position.Position
- Data.Rope.UTF16.Position: instance GHC.Base.Monoid Data.Rope.UTF16.Position.RowColumn
- Data.Rope.UTF16.Position: instance GHC.Classes.Eq Data.Rope.UTF16.Position.Position
- Data.Rope.UTF16.Position: instance GHC.Classes.Eq Data.Rope.UTF16.Position.RowColumn
- Data.Rope.UTF16.Position: instance GHC.Classes.Ord Data.Rope.UTF16.Position.Position
- Data.Rope.UTF16.Position: instance GHC.Classes.Ord Data.Rope.UTF16.Position.RowColumn
- Data.Rope.UTF16.Position: instance GHC.Show.Show Data.Rope.UTF16.Position.Position
- Data.Rope.UTF16.Position: instance GHC.Show.Show Data.Rope.UTF16.Position.RowColumn
- Data.Rope.UTF16.Position: lineStart :: Position -> Position
- Data.SplayTree: instance Data.SplayTree.Measured v a => Data.Semigroup.Semigroup (Data.SplayTree.SplayTree v a)
+ Data.Rope.UTF16: RowColumn :: !Int -> !Int -> RowColumn
+ Data.Rope.UTF16: [column] :: RowColumn -> !Int
+ Data.Rope.UTF16: [row] :: RowColumn -> !Int
+ Data.Rope.UTF16: all :: (Char -> Bool) -> Rope -> Bool
+ Data.Rope.UTF16: any :: (Char -> Bool) -> Rope -> Bool
+ Data.Rope.UTF16: columns :: Rope -> Int
+ Data.Rope.UTF16: data RowColumn
+ Data.Rope.UTF16: foldl :: (a -> Char -> a) -> a -> Rope -> a
+ Data.Rope.UTF16: foldl' :: (a -> Char -> a) -> a -> Rope -> a
+ Data.Rope.UTF16: foldr :: (Char -> a -> a) -> a -> Rope -> a
+ Data.Rope.UTF16: intercalate :: Rope -> [Rope] -> Rope
+ Data.Rope.UTF16: map :: (Char -> Char) -> Rope -> Rope
+ Data.Rope.UTF16: rows :: Rope -> Int
+ Data.Rope.UTF16: splitAtLine :: Int -> Rope -> (Rope, Rope)
+ Data.Rope.UTF16.Internal: all :: (Char -> Bool) -> Rope -> Bool
+ Data.Rope.UTF16.Internal: any :: (Char -> Bool) -> Rope -> Bool
+ Data.Rope.UTF16.Internal: columns :: Rope -> Int
+ Data.Rope.UTF16.Internal: foldl :: (a -> Char -> a) -> a -> Rope -> a
+ Data.Rope.UTF16.Internal: foldl' :: (a -> Char -> a) -> a -> Rope -> a
+ Data.Rope.UTF16.Internal: foldr :: (Char -> a -> a) -> a -> Rope -> a
+ Data.Rope.UTF16.Internal: instance Data.SplayTree.Measured Data.Rope.UTF16.Internal.Position.Position Data.Rope.UTF16.Internal.Chunk
+ Data.Rope.UTF16.Internal: instance Data.SplayTree.Measured Data.Rope.UTF16.Internal.Position.Position Data.Rope.UTF16.Internal.Rope
+ Data.Rope.UTF16.Internal: instance GHC.Base.Semigroup Data.Rope.UTF16.Internal.Chunk
+ Data.Rope.UTF16.Internal: instance GHC.Base.Semigroup Data.Rope.UTF16.Internal.Rope
+ Data.Rope.UTF16.Internal: intercalate :: Rope -> [Rope] -> Rope
+ Data.Rope.UTF16.Internal: map :: (Char -> Char) -> Rope -> Rope
+ Data.Rope.UTF16.Internal: rows :: Rope -> Int
+ Data.Rope.UTF16.Internal: splitAtLine :: Int -> Rope -> (Rope, Rope)
+ Data.Rope.UTF16.Internal.Position: Position :: !Int -> !RowColumn -> Position
+ Data.Rope.UTF16.Internal.Position: RowColumn :: !Int -> !Int -> RowColumn
+ Data.Rope.UTF16.Internal.Position: [codeUnits] :: Position -> !Int
+ Data.Rope.UTF16.Internal.Position: [column] :: RowColumn -> !Int
+ Data.Rope.UTF16.Internal.Position: [rowColumn] :: Position -> !RowColumn
+ Data.Rope.UTF16.Internal.Position: [row] :: RowColumn -> !Int
+ Data.Rope.UTF16.Internal.Position: data Position
+ Data.Rope.UTF16.Internal.Position: data RowColumn
+ Data.Rope.UTF16.Internal.Position: instance GHC.Base.Monoid Data.Rope.UTF16.Internal.Position.Position
+ Data.Rope.UTF16.Internal.Position: instance GHC.Base.Monoid Data.Rope.UTF16.Internal.Position.RowColumn
+ Data.Rope.UTF16.Internal.Position: instance GHC.Base.Semigroup Data.Rope.UTF16.Internal.Position.Position
+ Data.Rope.UTF16.Internal.Position: instance GHC.Base.Semigroup Data.Rope.UTF16.Internal.Position.RowColumn
+ Data.Rope.UTF16.Internal.Position: instance GHC.Classes.Eq Data.Rope.UTF16.Internal.Position.Position
+ Data.Rope.UTF16.Internal.Position: instance GHC.Classes.Eq Data.Rope.UTF16.Internal.Position.RowColumn
+ Data.Rope.UTF16.Internal.Position: instance GHC.Classes.Ord Data.Rope.UTF16.Internal.Position.Position
+ Data.Rope.UTF16.Internal.Position: instance GHC.Classes.Ord Data.Rope.UTF16.Internal.Position.RowColumn
+ Data.Rope.UTF16.Internal.Position: instance GHC.Show.Show Data.Rope.UTF16.Internal.Position.Position
+ Data.Rope.UTF16.Internal.Position: instance GHC.Show.Show Data.Rope.UTF16.Internal.Position.RowColumn
+ Data.SplayTree: instance Data.SplayTree.Measured v a => GHC.Base.Semigroup (Data.SplayTree.SplayTree v a)
- Data.SplayTree: Fork :: (SplayTree v a) -> a -> (SplayTree v a) -> !v -> SplayTree v a
+ Data.SplayTree: Fork :: SplayTree v a -> a -> SplayTree v a -> !v -> SplayTree v a
- Data.SplayTree: Inside :: (SplayTree v a) -> a -> (SplayTree v a) -> SplitResult v a
+ Data.SplayTree: Inside :: SplayTree v a -> a -> SplayTree v a -> SplitResult v a

Files

CHANGELOG.md view
@@ -1,3 +1,14 @@+# 0.3.1.0++- Add `splitAtLine` function++# 0.3.0.0++- Add `rows` and `columns` functions+- Make `Position` module internal+- Add `map` and `intersperse` functions+- Add `foldl`, `foldl'`, `foldr`, `any`, and `all` functions+ # 0.2.0.0  - Rename rowColumnCodePoints to rowColumnCodeUnits
README.md view
@@ -1,4 +1,5 @@-# rope-utf16-splay [![Build Status](https://travis-ci.org/ollef/rope-utf16-splay.svg?branch=master)](https://travis-ci.org/ollef/rope-utf16-splay)+# rope-utf16-splay [![Build Status](https://travis-ci.org/ollef/rope-utf16-splay.svg?branch=master)](https://travis-ci.org/ollef/rope-utf16-splay) [![Hackage](https://img.shields.io/hackage/v/rope-utf16-splay.svg)](https://hackage.haskell.org/package/rope-utf16-splay)+  Thick strings optimised for indexing and updating using UTF-16 code units and row/column pairs.
rope-utf16-splay.cabal view
@@ -1,5 +1,5 @@ name:                rope-utf16-splay-version:             0.2.0.0+version:             0.3.1.0 synopsis:            Ropes optimised for updating using UTF-16 code units and                      row/column pairs. description:         Ropes optimised for updating using UTF-16 code units and@@ -29,8 +29,8 @@   exposed-modules:                        Data.Rope.UTF16                        Data.Rope.UTF16.Internal+                       Data.Rope.UTF16.Internal.Position                        Data.Rope.UTF16.Internal.Text-                       Data.Rope.UTF16.Position                        Data.SplayTree   build-depends:                        base >= 4.9 && < 5,
src/Data/Rope/UTF16.hs view
@@ -1,34 +1,50 @@ module Data.Rope.UTF16-  ( module Position-  , Rope.Rope+  ( Rope.Rope    -- * Queries   , Rope.null+  , Rope.length+  , Rope.rows+  , Rope.columns -  -- * Conversions to and from 'Text' and 'String'+  -- * Conversions   , Rope.toText   , Rope.toLazyText   , Rope.fromText   , Rope.toString +  -- * Transformations+  , Rope.map+  , Rope.intercalate+   -- * Chunking   , Rope.toChunks   , Rope.unconsChunk   , Rope.unsnocChunk    -- * UTF-16 code unit indexing-  , Rope.length   , Rope.splitAt   , Rope.take   , Rope.drop+  , Position.RowColumn(..)   , Rope.rowColumnCodeUnits+  , Rope.splitAtLine    -- * Breaking by predicate   , Rope.span   , Rope.break   , Rope.takeWhile   , Rope.dropWhile++  -- * Folds+  , Rope.foldl+  , Rope.foldl'+  , Rope.foldr++  -- * Special folds+  , Rope.any+  , Rope.all   ) where -import Data.Rope.UTF16.Position as Position import Data.Rope.UTF16.Internal as Rope+import Data.Rope.UTF16.Internal.Position as Position
src/Data/Rope/UTF16/Internal.hs view
@@ -3,8 +3,9 @@ {-# language MultiParamTypeClasses #-} module Data.Rope.UTF16.Internal where -import Data.Foldable+import Data.Foldable as Foldable import Data.Function+import Data.List import Data.Semigroup import Data.String import Data.Text(Text)@@ -12,8 +13,8 @@ import qualified Data.Text.Lazy as Lazy import qualified Data.Text.Unsafe as Unsafe +import Data.Rope.UTF16.Internal.Position import Data.Rope.UTF16.Internal.Text-import Data.Rope.UTF16.Position import Data.SplayTree(SplayTree) import qualified Data.SplayTree as SplayTree @@ -83,8 +84,25 @@ null :: Rope -> Bool null (Rope r) = SplayTree.null r +-- | Length in code units (not characters)+length :: Rope -> Int+length = codeUnits . SplayTree.measure++-- | The number of newlines in the rope+--+-- @since 0.3.0.0+rows :: Rope -> Int+rows (Rope r) = row $ rowColumn $ SplayTree.measure r++-- | The number of code units (not characters) since the last newline or the+-- start of the rope+--+-- @since 0.3.0.0+columns :: Rope -> Int+columns (Rope r) = column $ rowColumn $ SplayTree.measure r+ ---------------------------------------------------------------------------------- * Conversions to and from 'Text' and 'String'+-- * Conversions  toText :: Rope -> Text toText = Text.concat . toChunks@@ -111,9 +129,24 @@   | otherwise = Rope $ SplayTree.singleton $ chunk t  toString :: Rope -> String-toString = concatMap Text.unpack . toChunks+toString = Foldable.concatMap Text.unpack . toChunks  -------------------------------------------------------------------------------+-- * Transformations++-- | Map over the characters of a rope+--+-- @since 0.3.0.0+map :: (Char -> Char) -> Rope -> Rope+map f (Rope r) = Rope $ SplayTree.map (chunk . Text.map f . chunkText) r++-- | Concatenate the interspersion of a rope between the elements of a list of ropes+--+-- @since 0.3.0.0+intercalate :: Rope -> [Rope] -> Rope+intercalate r rs = mconcat $ intersperse r rs++------------------------------------------------------------------------------- -- * Chunking  -- | The raw 'Text' data that the 'Rope' is built from@@ -135,10 +168,6 @@ ------------------------------------------------------------------------------- -- * UTF-16 code unit indexing --- | Length in code units (not characters)-length :: Rope -> Int-length = codeUnits . SplayTree.measure- -- | Split the rope at the nth code unit (not character) splitAt :: Int -> Rope -> (Rope, Rope) splitAt n (Rope r) = case SplayTree.split ((> n) . codeUnits) r of@@ -178,8 +207,20 @@           Unsafe.Iter _ delta -> go (i + delta) (v' <> RowColumn 0 delta)  -------------------------------------------------------------------------------+-- * Lines++-- | Split the rope immediately after the i:th newline+--+-- @since 0.3.1.0+splitAtLine :: Int -> Rope -> (Rope, Rope)+splitAtLine r rope = Data.Rope.UTF16.Internal.splitAt i rope+  where+    i = rowColumnCodeUnits (RowColumn r 0) rope++------------------------------------------------------------------------------- -- * Breaking by predicate +-- | @span f r = (takeWhile f r, dropWhile f r)@ span :: (Char -> Bool) -> Rope -> (Rope, Rope) span f (Rope r) = case SplayTree.uncons r of   Nothing -> (mempty, mempty)@@ -190,11 +231,50 @@       (pret, postt) = Text.span f $ chunkText t       (pre', post') = Data.Rope.UTF16.Internal.span f $ Rope r' +-- | @break f = span (not . f)@ break :: (Char -> Bool) -> Rope -> (Rope, Rope) break f = Data.Rope.UTF16.Internal.span (not . f) +-- | @takeWhile f = fst . span f@ takeWhile :: (Char -> Bool) -> Rope -> Rope takeWhile f = fst . Data.Rope.UTF16.Internal.span f +-- | @dropWhile f = snd . span f@ dropWhile :: (Char -> Bool) -> Rope -> Rope dropWhile f = snd . Data.Rope.UTF16.Internal.span f++-------------------------------------------------------------------------------+-- * Folds++-- | Fold left+--+-- @since 0.3.0.0+foldl :: (a -> Char -> a) -> a -> Rope -> a+foldl f a (Rope r) = Foldable.foldl (\a' c -> Text.foldl f a' $ chunkText c) a r++-- | A strict version of 'foldl'+--+-- @since 0.3.0.0+foldl' :: (a -> Char -> a) -> a -> Rope -> a+foldl' f a (Rope r) = Foldable.foldl' (\a' c -> Text.foldl' f a' $ chunkText c) a r++-- | Fold right+--+-- @since 0.3.0.0+foldr :: (Char -> a -> a) -> a -> Rope -> a+foldr f a (Rope r) = Foldable.foldr (\c a' -> Text.foldr f a' $ chunkText c) a r++-------------------------------------------------------------------------------+-- * Special folds++-- | Do any characters in the rope satisfy the predicate?+--+-- @since 0.3.0.0+any :: (Char -> Bool) -> Rope -> Bool+any p (Rope r) = getAny $ foldMap (Any . Text.any p . chunkText) r++-- | Do all characters in the rope satisfy the predicate?+--+-- @since 0.3.0.0+all :: (Char -> Bool) -> Rope -> Bool+all p (Rope r) = getAll $ foldMap (All . Text.all p . chunkText) r
+ src/Data/Rope/UTF16/Internal/Position.hs view
@@ -0,0 +1,31 @@+module Data.Rope.UTF16.Internal.Position where++import Data.Semigroup++data RowColumn = RowColumn+  { row :: !Int -- ^ Number of newlines before this position+  , column :: !Int -- ^ Number of code units since last newline or start of string+  } deriving (Eq, Ord, Show)++instance Semigroup RowColumn where+  RowColumn 0 c1 <> RowColumn 0 c2 = RowColumn 0 $ c1 + c2+  RowColumn 0 _ <> v2 = v2+  RowColumn r1 c1 <> RowColumn 0 c2 = RowColumn r1 $ c1 + c2+  RowColumn r1 _ <> RowColumn r2 c2 = RowColumn (r1 + r2) c2++instance Monoid RowColumn where+  mempty = RowColumn 0 0+  mappend = (<>)++data Position = Position+  { codeUnits :: !Int+  , rowColumn :: !RowColumn+  } deriving (Eq, Ord, Show)++instance Semigroup Position where+  Position cp1 v1 <> Position cp2 v2+    = Position (cp1 + cp2) (v1 <> v2)++instance Monoid Position where+  mempty = Position 0 mempty+  mappend = (<>)
− src/Data/Rope/UTF16/Position.hs
@@ -1,34 +0,0 @@-module Data.Rope.UTF16.Position where--import Data.Semigroup--data RowColumn = RowColumn-  { row :: !Int -- ^ Number of newlines before this position-  , column :: !Int -- ^ Number of code units since last newline or start of string-  } deriving (Eq, Ord, Show)--instance Semigroup RowColumn where-  RowColumn 0 c1 <> RowColumn 0 c2 = RowColumn 0 $ c1 + c2-  RowColumn 0 _ <> v2 = v2-  RowColumn r1 c1 <> RowColumn 0 c2 = RowColumn r1 $ c1 + c2-  RowColumn r1 _ <> RowColumn r2 c2 = RowColumn (r1 + r2) c2--instance Monoid RowColumn where-  mempty = RowColumn 0 0-  mappend = (<>)--data Position = Position-  { codeUnits :: !Int-  , rowColumn :: !RowColumn-  } deriving (Eq, Ord, Show)--lineStart :: Position -> Position-lineStart (Position cp (RowColumn r c)) = Position (cp - c) $ RowColumn r 0--instance Semigroup Position where-  Position cp1 v1 <> Position cp2 v2-    = Position (cp1 + cp2) (v1 <> v2)--instance Monoid Position where-  mempty = Position 0 mempty-  mappend = (<>)
tests/Main.hs view
@@ -1,6 +1,8 @@+{-# LANGUAGE OverloadedStrings #-} module Main where  import Data.Semigroup+import Data.Text (Text) import qualified Data.Text as Text import qualified Data.Text.Unsafe as Unsafe import Test.QuickCheck.Function as QC@@ -46,6 +48,11 @@     let t = Text.pack $ replicate newlines '\n' ++ takeWhile (/= '\n') s     Rope.clamp16 (newlines + i) t == Rope.rowColumnCodeUnits (Rope.RowColumn newlines i) (Rope.fromText t) +  , testProperty "splitAtLine" $ \s i -> do+    let t = Text.pack s+        (rows1', rows2') = Rope.splitAtLine i (Rope.fromText t)+    splitAtLineSpec i t == (Rope.toText rows1', Rope.toText rows2')+   , testProperty "span matches Text" $ \s p -> do     let t = Text.pack s         f = QC.applyFun p@@ -71,4 +78,57 @@   , testProperty "null matches Text" $ \s -> do     let t = Text.pack s     Rope.null (Rope.fromText t) == Text.null t++  , testProperty "rows is number of newlines" $ \s -> do+    let t = Text.pack s+        newlines = length $ filter (== '\n') s+    Rope.rows (Rope.fromText t) == newlines++  , testProperty "columns is number of code units of last line" $ \s -> do+    let t = Text.pack s+        lastLine = Text.takeWhileEnd (/= '\n') t+        cols = Unsafe.lengthWord16 lastLine+    Rope.columns (Rope.fromText t) == cols++  , testProperty "foldl matches Text" $ \s p a -> do+    let t = Text.pack s+        f = QC.applyFun2 p+    Rope.foldl f (a :: Int) (Rope.fromText t) == Text.foldl f a t++  , testProperty "foldl' matches Text" $ \s p a -> do+    let t = Text.pack s+        f = QC.applyFun2 p+    Rope.foldl' f (a :: Int) (Rope.fromText t) == Text.foldl' f a t++  , testProperty "foldr matches Text" $ \s p a -> do+    let t = Text.pack s+        f = QC.applyFun2 p+    Rope.foldr f (a :: Int) (Rope.fromText t) == Text.foldr f a t++  , testProperty "any matches Text" $ \s p -> do+    let t = Text.pack s+        f = QC.applyFun p+    Rope.any f (Rope.fromText t) == Text.any f t++  , testProperty "all matches Text" $ \s p -> do+    let t = Text.pack s+        f = QC.applyFun p+    Rope.all f (Rope.fromText t) == Text.all f t++  , testProperty "map matches Text" $ \s p -> do+    let t = Text.pack s+        f = QC.applyFun p+    Rope.toText (Rope.map f (Rope.fromText t)) == Text.map f t++  , testProperty "intercalate matches Text" $ \s ss -> do+    let t = Text.pack s+        ts = Text.pack <$> ss+    Rope.toText (Rope.intercalate (Rope.fromText t) (Rope.fromText <$> ts)) == Text.intercalate t ts   ]++splitAtLineSpec :: Int -> Text -> (Text, Text)+splitAtLineSpec i t = case Text.splitOn "\n" t of+  [] -> ("", "")+  ts -> do+    let (pres, posts) = splitAt i (fmap (<> "\n") (init ts) <> [last ts])+    (Text.concat pres, Text.concat posts)