cursor 0.1.0.1 → 0.2.0.0
raw patch · 5 files changed
+80/−91 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Cursor.Types: isSafeChar :: Char -> Bool
- Cursor.TextField: textFieldCursorAppendChar :: Char -> Maybe TextFieldCursor -> TextFieldCursor
+ Cursor.TextField: textFieldCursorAppendChar :: Char -> Maybe TextFieldCursor -> Maybe TextFieldCursor
- Cursor.TextField: textFieldCursorInsertChar :: Char -> Maybe TextFieldCursor -> TextFieldCursor
+ Cursor.TextField: textFieldCursorInsertChar :: Char -> Maybe TextFieldCursor -> Maybe TextFieldCursor
Files
- CHANGELOG.md +9/−0
- cursor.cabal +5/−3
- src/Cursor/Text.hs +15/−11
- src/Cursor/TextField.hs +44/−68
- src/Cursor/Types.hs +7/−9
+ CHANGELOG.md view
@@ -0,0 +1,9 @@+# Changelog++## [Unreleased]++## [0.2.0.0] - 2019-09-23++### Changed++- `textFieldCursorInsertChar` and `textFieldCursorAppendChar` now fail on unsafe characters.
cursor.cabal view
@@ -1,13 +1,13 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.31.1.+-- This file has been generated from package.yaml by hpack version 0.31.2. -- -- see: https://github.com/sol/hpack ----- hash: 8f3a123718c5c3c3ec43456e3311c0955cd17b64bda527bc0e553a10f783d5bf+-- hash: 198732d25b67091588b88dbc6fd99fc8847ea61c7ebadc1ce7a7f313a60a70eb name: cursor-version: 0.1.0.1+version: 0.2.0.0 synopsis: Purely Functional Cursors description: Purely Functional Cursors for common data structures .@@ -20,6 +20,8 @@ license: MIT license-file: LICENSE build-type: Simple+extra-source-files:+ CHANGELOG.md library exposed-modules:
src/Cursor/Text.hs view
@@ -49,7 +49,10 @@ mconcat [ genericValidate lc , decorateList (rebuildListCursor lc) $ \c ->- declare "The character is not a newline character" $ c /= '\n'+ mconcat+ [ declare "The character is not a newline character" $ c /= '\n'+ , declare "The character is a safe character" $ isSafeChar c+ ] ] emptyTextCursor :: TextCursor@@ -68,10 +71,7 @@ rebuildTextCursor = T.pack . rebuildListCursor . textCursorList textCursorListCursorL ::- Functor f- => (ListCursor Char -> f (ListCursor Char))- -> TextCursor- -> f TextCursor+ Functor f => (ListCursor Char -> f (ListCursor Char)) -> TextCursor -> f TextCursor textCursorListCursorL = lens textCursorList (\tc lc -> tc {textCursorList = lc}) textCursorNull :: TextCursor -> Bool@@ -106,19 +106,23 @@ textCursorInsert :: Char -> TextCursor -> Maybe TextCursor textCursorInsert '\n' _ = Nothing-textCursorInsert c tc = Just (tc & textCursorListCursorL %~ listCursorInsert c)+textCursorInsert c tc =+ if isSafeChar c+ then Just (tc & textCursorListCursorL %~ listCursorInsert c)+ else Nothing textCursorAppend :: Char -> TextCursor -> Maybe TextCursor textCursorAppend '\n' _ = Nothing-textCursorAppend c tc = Just (tc & textCursorListCursorL %~ listCursorAppend c)+textCursorAppend c tc =+ if isSafeChar c+ then Just (tc & textCursorListCursorL %~ listCursorAppend c)+ else Nothing textCursorRemove :: TextCursor -> Maybe (DeleteOrUpdate TextCursor)-textCursorRemove =- focusPossibleDeleteOrUpdate textCursorListCursorL listCursorRemove+textCursorRemove = focusPossibleDeleteOrUpdate textCursorListCursorL listCursorRemove textCursorDelete :: TextCursor -> Maybe (DeleteOrUpdate TextCursor)-textCursorDelete =- focusPossibleDeleteOrUpdate textCursorListCursorL listCursorDelete+textCursorDelete = focusPossibleDeleteOrUpdate textCursorListCursorL listCursorDelete textCursorSplit :: TextCursor -> (TextCursor, TextCursor) textCursorSplit tc =
src/Cursor/TextField.hs view
@@ -62,19 +62,8 @@ mconcat [ genericValidate tfc , decorate "None of the texts contain newlines" $- mconcat $- NE.toList $- flip- NE.map- (NE.zip (fromJust $ NE.nonEmpty [0 ..]) $- rebuildNonEmptyCursor rebuildTextCursor textFieldCursorNonEmpty) $ \(i, tc) ->- declare- (unwords- [ "The text of the line at index"- , show (i :: Int)- , "does not contain any newlines"- ]) $- T.all (/= '\n') tc+ decorateList (NE.toList $ rebuildNonEmptyCursor rebuildTextCursor textFieldCursorNonEmpty) $ \tc ->+ declare "The text of this line does not contain any newlines" $ T.all (/= '\n') tc ] makeTextFieldCursor :: Text -> TextFieldCursor@@ -82,32 +71,23 @@ makeTextFieldCursorWithSelection :: Int -> Int -> Text -> Maybe TextFieldCursor makeTextFieldCursorWithSelection x y t = do- let ls- -- This is safe because 'splitOn' always returns a nonempty list.- = NE.fromList $ T.split (== '\n') t+ ls <- NE.nonEmpty $ T.split (== '\n') t guard (x >= 0) guard (x < NE.length ls)- nec <-- makeNonEmptyCursorWithSelection- -- This is safe because we already checked that it would work above- (makeTextCursorWithSelection y)- x- ls+ nec <- makeNonEmptyCursorWithSelection (makeTextCursorWithSelection y) x ls void $ nonEmptyCursorCurrent nec+ -- This is safe because we already checked that it would work above pure $ TextFieldCursor (nec & nonEmptyCursorElemL %~ fromJust) rebuildTextFieldCursorLines :: TextFieldCursor -> NonEmpty Text-rebuildTextFieldCursorLines =- rebuildNonEmptyCursor rebuildTextCursor . textFieldCursorNonEmpty+rebuildTextFieldCursorLines = rebuildNonEmptyCursor rebuildTextCursor . textFieldCursorNonEmpty rebuildTextFieldCursor :: TextFieldCursor -> Text-rebuildTextFieldCursor =- T.intercalate "\n" . NE.toList . rebuildTextFieldCursorLines+rebuildTextFieldCursor = T.intercalate "\n" . NE.toList . rebuildTextFieldCursorLines emptyTextFieldCursor :: TextFieldCursor emptyTextFieldCursor =- TextFieldCursor- {textFieldCursorNonEmpty = singletonNonEmptyCursor emptyTextCursor}+ TextFieldCursor {textFieldCursorNonEmpty = singletonNonEmptyCursor emptyTextCursor} nullTextFieldCursor :: TextFieldCursor -> Bool nullTextFieldCursor = (== emptyTextFieldCursor)@@ -117,8 +97,7 @@ ( nonEmptyCursorSelection $ textFieldCursorNonEmpty tfc , textCursorIndex $ textFieldCursorNonEmpty tfc ^. nonEmptyCursorElemL) -textFieldCursorNonEmptyCursorL ::- Lens' TextFieldCursor (NonEmptyCursor TextCursor Text)+textFieldCursorNonEmptyCursorL :: Lens' TextFieldCursor (NonEmptyCursor TextCursor Text) textFieldCursorNonEmptyCursorL = lens textFieldCursorNonEmpty $ \tfc lec -> tfc {textFieldCursorNonEmpty = lec} @@ -127,13 +106,11 @@ textFieldCursorSelectPrevLine :: TextFieldCursor -> Maybe TextFieldCursor textFieldCursorSelectPrevLine =- moveMWhileKeepingSelection $- nonEmptyCursorSelectPrev rebuildTextCursor unsafeMakeTextCursor+ moveMWhileKeepingSelection $ nonEmptyCursorSelectPrev rebuildTextCursor unsafeMakeTextCursor textFieldCursorSelectNextLine :: TextFieldCursor -> Maybe TextFieldCursor textFieldCursorSelectNextLine =- moveMWhileKeepingSelection $- nonEmptyCursorSelectNext rebuildTextCursor unsafeMakeTextCursor+ moveMWhileKeepingSelection $ nonEmptyCursorSelectNext rebuildTextCursor unsafeMakeTextCursor moveMWhileKeepingSelection :: (NonEmptyCursor TextCursor Text -> Maybe (NonEmptyCursor TextCursor Text))@@ -147,13 +124,11 @@ textFieldCursorSelectFirstLine :: TextFieldCursor -> TextFieldCursor textFieldCursorSelectFirstLine =- moveWhileKeepingSelection $- nonEmptyCursorSelectFirst rebuildTextCursor unsafeMakeTextCursor+ moveWhileKeepingSelection $ nonEmptyCursorSelectFirst rebuildTextCursor unsafeMakeTextCursor textFieldCursorSelectLastLine :: TextFieldCursor -> TextFieldCursor textFieldCursorSelectLastLine =- moveWhileKeepingSelection $- nonEmptyCursorSelectLast rebuildTextCursor unsafeMakeTextCursor+ moveWhileKeepingSelection $ nonEmptyCursorSelectLast rebuildTextCursor unsafeMakeTextCursor moveWhileKeepingSelection :: (NonEmptyCursor TextCursor Text -> NonEmptyCursor TextCursor Text)@@ -172,28 +147,38 @@ textFieldCursorSelectNextChar = textFieldCursorSelectedL textCursorSelectNext textFieldCursorIndexOnLine :: TextFieldCursor -> Int-textFieldCursorIndexOnLine tfc =- textCursorIndex $ tfc ^. textFieldCursorSelectedL+textFieldCursorIndexOnLine tfc = textCursorIndex $ tfc ^. textFieldCursorSelectedL textFieldCursorSelectIndexOnLine :: Int -> TextFieldCursor -> TextFieldCursor-textFieldCursorSelectIndexOnLine ix_ =- textFieldCursorSelectedL %~ textCursorSelectIndex ix_+textFieldCursorSelectIndexOnLine ix_ = textFieldCursorSelectedL %~ textCursorSelectIndex ix_ -textFieldCursorInsertChar :: Char -> Maybe TextFieldCursor -> TextFieldCursor+-- |+--+-- returns 'Nothing' when given unsafe characters.+textFieldCursorInsertChar :: Char -> Maybe TextFieldCursor -> Maybe TextFieldCursor textFieldCursorInsertChar c mtfc = case c of- '\n' -> textFieldCursorInsertNewline mtfc- _ ->- (fromMaybe emptyTextFieldCursor mtfc) &- textFieldCursorSelectedL %~ (fromJust . textCursorInsert c)+ '\n' -> Just $ textFieldCursorInsertNewline mtfc+ _+ | isSafeChar c ->+ Just $+ (fromMaybe emptyTextFieldCursor mtfc) &+ textFieldCursorSelectedL %~ (fromJust . textCursorInsert c)+ | otherwise -> Nothing -textFieldCursorAppendChar :: Char -> Maybe TextFieldCursor -> TextFieldCursor+-- |+--+-- returns 'Nothing' when given unsafe characters.+textFieldCursorAppendChar :: Char -> Maybe TextFieldCursor -> Maybe TextFieldCursor textFieldCursorAppendChar c mtfc = case c of- '\n' -> textFieldCursorAppendNewline mtfc- _ ->- (fromMaybe emptyTextFieldCursor mtfc) &- textFieldCursorSelectedL %~ (fromJust . textCursorAppend c)+ '\n' -> Just $ textFieldCursorAppendNewline mtfc+ _+ | isSafeChar c ->+ Just $+ (fromMaybe emptyTextFieldCursor mtfc) &+ textFieldCursorSelectedL %~ (fromJust . textCursorAppend c)+ | otherwise -> Nothing textFieldCursorInsertNewline :: Maybe TextFieldCursor -> TextFieldCursor textFieldCursorInsertNewline mtfc =@@ -219,8 +204,7 @@ , nonEmptyCursorNext = rebuildTextCursor tc2 : nonEmptyCursorNext }) -textFieldCursorRemove ::- TextFieldCursor -> Maybe (DeleteOrUpdate TextFieldCursor)+textFieldCursorRemove :: TextFieldCursor -> Maybe (DeleteOrUpdate TextFieldCursor) textFieldCursorRemove tfc = if nullTextFieldCursor tfc then Just Deleted@@ -228,8 +212,7 @@ textFieldCursorNonEmptyCursorL (\lec@NonEmptyCursor {..} -> case textCursorRemove nonEmptyCursorCurrent of- Just (Updated ctc) ->- Just $ Updated $ lec & nonEmptyCursorElemL .~ ctc+ Just (Updated ctc) -> Just $ Updated $ lec & nonEmptyCursorElemL .~ ctc _ -> case nonEmptyCursorPrev of [] -> Nothing@@ -239,14 +222,11 @@ lec { nonEmptyCursorPrev = pls , nonEmptyCursorCurrent =- textCursorCombine- (unsafeMakeTextCursor pl)- nonEmptyCursorCurrent+ textCursorCombine (unsafeMakeTextCursor pl) nonEmptyCursorCurrent }) tfc -textFieldCursorDelete ::- TextFieldCursor -> Maybe (DeleteOrUpdate TextFieldCursor)+textFieldCursorDelete :: TextFieldCursor -> Maybe (DeleteOrUpdate TextFieldCursor) textFieldCursorDelete tfc = if nullTextFieldCursor tfc then Just Deleted@@ -254,8 +234,7 @@ textFieldCursorNonEmptyCursorL (\lec@NonEmptyCursor {..} -> case textCursorDelete nonEmptyCursorCurrent of- Just (Updated ctc) ->- Just $ Updated $ lec & nonEmptyCursorElemL .~ ctc+ Just (Updated ctc) -> Just $ Updated $ lec & nonEmptyCursorElemL .~ ctc _ -> case nonEmptyCursorNext of [] -> Nothing@@ -264,16 +243,13 @@ Updated $ lec { nonEmptyCursorCurrent =- textCursorCombine- nonEmptyCursorCurrent- (unsafeMakeTextCursor pl)+ textCursorCombine nonEmptyCursorCurrent (unsafeMakeTextCursor pl) , nonEmptyCursorNext = pls }) tfc textFieldCursorSelectStartOfLine :: TextFieldCursor -> TextFieldCursor-textFieldCursorSelectStartOfLine =- textFieldCursorSelectedL %~ textCursorSelectStart+textFieldCursorSelectStartOfLine = textFieldCursorSelectedL %~ textCursorSelectStart textFieldCursorSelectEndOfLine :: TextFieldCursor -> TextFieldCursor textFieldCursorSelectEndOfLine = textFieldCursorSelectedL %~ textCursorSelectEnd
src/Cursor/Types.hs view
@@ -5,6 +5,7 @@ import GHC.Generics (Generic) +import qualified Data.Text.Internal as T import Data.Validity import Data.Functor.Compose@@ -13,6 +14,9 @@ import Lens.Micro +isSafeChar :: Char -> Bool+isSafeChar c = T.safe c == c+ data DeleteOrUpdate a = Deleted | Updated a@@ -35,8 +39,7 @@ Updated a <|> _ = Updated a Deleted <|> doua = doua -joinDeletes ::- Maybe (DeleteOrUpdate a) -> Maybe (DeleteOrUpdate a) -> DeleteOrUpdate a+joinDeletes :: Maybe (DeleteOrUpdate a) -> Maybe (DeleteOrUpdate a) -> DeleteOrUpdate a joinDeletes m1 m2 = case (m1, m2) of (Nothing, Nothing) -> Deleted@@ -56,16 +59,11 @@ (Just a, _, _) -> a joinPossibleDeletes ::- Maybe (DeleteOrUpdate a)- -> Maybe (DeleteOrUpdate a)- -> Maybe (DeleteOrUpdate a)+ Maybe (DeleteOrUpdate a) -> Maybe (DeleteOrUpdate a) -> Maybe (DeleteOrUpdate a) joinPossibleDeletes d1 d2 = getCompose $ Compose d1 <|> Compose d2 focusPossibleDeleteOrUpdate ::- Lens' b a- -> (a -> Maybe (DeleteOrUpdate a))- -> b- -> Maybe (DeleteOrUpdate b)+ Lens' b a -> (a -> Maybe (DeleteOrUpdate a)) -> b -> Maybe (DeleteOrUpdate b) focusPossibleDeleteOrUpdate l func = getCompose . l (Compose . func) dullMDelete :: Maybe (DeleteOrUpdate a) -> Maybe a