text-zipper 0.8.3 → 0.9
raw patch · 4 files changed
+51/−33 lines, 4 files
Files
- CHANGELOG +8/−0
- src/Data/Text/Zipper.hs +37/−31
- src/Data/Text/Zipper/Generic.hs +5/−1
- text-zipper.cabal +1/−1
CHANGELOG view
@@ -1,3 +1,11 @@+0.9+---++- insertChar and insertMany now only insert printable characters and+ newlines (subject to text zipper line limits)+- The GenericTextZipper class now requires a new method,+ toList :: a -> [Char]+ 0.8.3 -----
src/Data/Text/Zipper.hs view
@@ -46,6 +46,7 @@ import Control.Applicative ((<$>)) import Control.DeepSeq+import Data.Char (isPrint) import Data.Monoid import qualified Data.Text as T import qualified Data.Vector as V@@ -64,6 +65,7 @@ , init_ :: a -> a , null_ :: a -> Bool , lines_ :: a -> [a]+ , toList_ :: a -> [Char] , lineLimit :: Maybe Int } @@ -118,19 +120,21 @@ -- ^'null'. -> (a -> [a]) -- ^'lines'.+ -> (a -> [Char])+ -- ^'toList'. -> [a] -- ^The initial lines of text. -> Maybe Int -- ^Limit to this many lines of text ('Nothing' means no limit). -> TextZipper a-mkZipper fromCh drp tk lngth lst int nl linesFunc ls lmt =+mkZipper fromCh drp tk lngth lst int nl linesFunc toListF ls lmt = let limitedLs = case lmt of Nothing -> ls Just n -> take n ls (first, rest) = if null limitedLs then (mempty, mempty) else (head limitedLs, tail limitedLs)- in TZ mempty first [] rest fromCh drp tk lngth lst int nl linesFunc lmt+ in TZ mempty first [] rest fromCh drp tk lngth lst int nl linesFunc toListF lmt -- |Get the text contents of the zipper. getText :: (Monoid a) => TextZipper a -> [a]@@ -184,36 +188,37 @@ currentLine :: (Monoid a) => TextZipper a -> a currentLine tz = (toLeft tz) `mappend` (toRight tz) --- |Insert a character at the current cursor position. Move the--- cursor one position to the right.+-- |Insert a character at the current cursor position.+--+-- If the character is a newline, break the current line.+--+-- If the character is non-printable, ignore it.+--+-- Otherwise insert the character and move the cursor one position to+-- the right. insertChar :: (Monoid a) => Char -> TextZipper a -> TextZipper a-insertChar '\n' tz = breakLine tz-insertChar ch tz = tz { toLeft = toLeft tz `mappend` (fromChar tz ch) }+insertChar ch tz = maybe tz id $ insertChar_ ch tz +insertChar_ :: (Monoid a) => Char -> TextZipper a -> Maybe (TextZipper a)+insertChar_ ch tz+ | ch == '\n' = breakLine_ tz+ | isPrint ch = Just $ tz { toLeft = toLeft tz `mappend` (fromChar tz ch) }+ | otherwise = Nothing+ -- |Insert many characters at the current cursor position. Move the--- cursor one position to the end of the inserted text.+-- cursor to the end of the inserted text. insertMany :: (Monoid a) => a -> TextZipper a -> TextZipper a-insertMany cs tz =- let ls = lines_ tz cs- go [] z = z- go (a:as) z = let maybeBreak = if null as then id else breakLine- in go as $ maybeBreak $ z { toLeft = toLeft z `mappend` a }- in case lineLimit tz of- Nothing ->- let toInsert = ls- in go toInsert tz- Just limit ->- -- How many more lines can we add without violating the- -- limit?- let toInsert = take remainingLines ls- remainingLines = max 0 (limit - totalLines)- totalLines = length (above tz) +- length (below tz)- in go toInsert tz+insertMany str tz =+ let go [] z = z+ go (c:cs) z = maybe z (go cs) $ insertChar_ c z+ in go (toList_ tz str) tz -- |Insert a line break at the current cursor position. breakLine :: (Monoid a) => TextZipper a -> TextZipper a-breakLine tz =+breakLine tz = maybe tz id $ breakLine_ tz++breakLine_ :: (Monoid a) => TextZipper a -> Maybe (TextZipper a)+breakLine_ tz = -- Plus two because we count the current line and the line we are -- about to create; if that number of lines exceeds the limit, -- ignore this operation.@@ -222,9 +227,10 @@ } in case lineLimit tz of Just lim -> if length (above tz) + length (below tz) + 2 > lim- then tz- else modified- Nothing -> modified+ then Nothing+ else Just modified+ Nothing -> Just modified+ -- |Move the cursor to the end of the current line. gotoEOL :: (Monoid a) => TextZipper a -> TextZipper a gotoEOL tz = tz { toLeft = currentLine tz@@ -393,12 +399,12 @@ -- |Construct a zipper from list values. stringZipper :: [String] -> Maybe Int -> TextZipper String stringZipper =- mkZipper (:[]) drop take length last init null lines+ mkZipper (:[]) drop take length last init null lines id -- |Construct a zipper from vectors of characters. vectorZipper :: [V.Vector Char] -> Maybe Int -> TextZipper (V.Vector Char) vectorZipper =- mkZipper V.singleton V.drop V.take V.length V.last V.init V.null V.vecLines+ mkZipper V.singleton V.drop V.take V.length V.last V.init V.null V.vecLines V.toList -- |Empty a zipper. clearZipper :: (Monoid a) => TextZipper a -> TextZipper a@@ -412,4 +418,4 @@ -- |Construct a zipper from 'T.Text' values. textZipper :: [T.Text] -> Maybe Int -> TextZipper T.Text textZipper =- mkZipper T.singleton T.drop T.take T.length T.last T.init T.null T.lines+ mkZipper T.singleton T.drop T.take T.length T.last T.init T.null T.lines T.unpack
src/Data/Text/Zipper/Generic.hs view
@@ -24,6 +24,7 @@ init :: a -> a null :: a -> Bool lines :: a -> [a]+ toList :: a -> [Char] instance GenericTextZipper [Char] where singleton = (:[])@@ -34,6 +35,7 @@ init = Prelude.init null = Prelude.null lines = Prelude.lines+ toList = id instance GenericTextZipper T.Text where singleton = T.singleton@@ -44,6 +46,7 @@ init = T.init null = T.null lines = T.lines+ toList = T.unpack instance GenericTextZipper (V.Vector Char) where singleton = V.singleton@@ -54,8 +57,9 @@ init = V.init null = V.null lines = V.vecLines+ toList = V.toList textZipper :: GenericTextZipper a => [a] -> Maybe Int -> TextZipper a textZipper =- mkZipper singleton drop take length last init null lines+ mkZipper singleton drop take length last init null lines toList
text-zipper.cabal view
@@ -1,5 +1,5 @@ name: text-zipper-version: 0.8.3+version: 0.9 synopsis: A text editor zipper library description: This library provides a zipper and API for editing text. license: BSD3