From 82276bf75466c57d12a2b26c32d6f47cb6bac431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Xaver=20H=C3=B6rl?= Date: Sun, 17 Feb 2019 17:53:17 +0100 Subject: [PATCH 1/5] Add MonadFail constraint to MonadInteract and instance to the implementation --- yi-core/src/Yi/Interact.hs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/yi-core/src/Yi/Interact.hs b/yi-core/src/Yi/Interact.hs index a1dcece86..7c0df93a4 100644 --- a/yi-core/src/Yi/Interact.hs +++ b/yi-core/src/Yi/Interact.hs @@ -68,6 +68,7 @@ module Yi.Interact accepted ) where +import qualified Control.Monad.Fail as Fail import Control.Applicative (Alternative ((<|>), empty)) import Control.Arrow (first) import Lens.Micro.Platform (_1, _2, view) @@ -80,7 +81,7 @@ import qualified Data.Text as T (Text, append, pack) -- Classes -- | Abstraction of monadic interactive processes -class (Eq w, Monad m, Alternative m, Applicative m, MonadPlus m) => MonadInteract m w e | m -> w e where +class (Eq w, Monad m, Alternative m, Applicative m, MonadPlus m,Fail.MonadFail m) => MonadInteract m w e | m -> w e where write :: w -> m () -- ^ Outputs a result. eventBounds :: Ord e => Maybe e -> Maybe e -> m e @@ -124,9 +125,12 @@ instance Alternative (I ev w) where empty = Fails (<|>) = Plus +instance Fail.MonadFail (I event w) where + fail _ = Fails + instance Monad (I event w) where return = Returns - fail _ = Fails + fail = Fail.fail (>>=) = Binds instance Eq w => MonadPlus (I event w) where From 0b71e2d8a916d1e8556a0039f15ebde5658e1e5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Xaver=20H=C3=B6rl?= Date: Sun, 17 Feb 2019 18:34:39 +0100 Subject: [PATCH 2/5] Replace potentially failing patterns --- yi-core/src/Yi/Buffer/Region.hs | 4 +++- yi-core/src/Yi/Rectangle.hs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/yi-core/src/Yi/Buffer/Region.hs b/yi-core/src/Yi/Buffer/Region.hs index 730cada3f..5eeb51b69 100644 --- a/yi-core/src/Yi/Buffer/Region.hs +++ b/yi-core/src/Yi/Buffer/Region.hs @@ -93,13 +93,15 @@ inclusiveRegionB r = -- a list of small regions form this block region. blockifyRegion :: Region -> BufferM [Region] blockifyRegion r = savingPointB $ do - [lowCol, highCol] <- sort <$> mapM colOf [regionStart r, regionEnd r] + (lowCol, highCol) <- curry sortTuple <$> colOf (regionStart r) <*> colOf (regionEnd r) startLine <- lineOf $ regionStart r endLine <- lineOf $ regionEnd r when (startLine > endLine) $ fail "blockifyRegion: impossible" mapM (\line -> mkRegion <$> pointOfLineColB line lowCol <*> pointOfLineColB line (1 + highCol)) [startLine..endLine] + where + sortTuple (a,b) = if a < b then (a,b) else (b,a) -- | Joins lines in the region with a single space, skipping any empty -- lines. diff --git a/yi-core/src/Yi/Rectangle.hs b/yi-core/src/Yi/Rectangle.hs index ffe52946e..33032ba25 100644 --- a/yi-core/src/Yi/Rectangle.hs +++ b/yi-core/src/Yi/Rectangle.hs @@ -28,8 +28,10 @@ getRectangle :: BufferM (Region, Int, Int) getRectangle = do r <- getSelectRegionB extR <- unitWiseRegion Line r - [lowCol,highCol] <- sort <$> mapM colOf [regionStart r, regionEnd r] + (lowCol,highCol) <- curry sortTuple <$> colOf (regionStart r) <*> colOf (regionEnd r) return (extR, lowCol, highCol) + where + sortTuple (a,b) = if a < b then (a,b) else (b,a) -- | Split text at the boundaries given multiSplit :: [Int] -> R.YiString -> [R.YiString] From 6f0b1c0302c312e992c18f1f1d02b02fb86f258d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Xaver=20H=C3=B6rl?= Date: Sun, 17 Feb 2019 18:37:29 +0100 Subject: [PATCH 3/5] Explicitly error out when marks are not present --- yi-core/src/Yi/Buffer/Misc.hs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/yi-core/src/Yi/Buffer/Misc.hs b/yi-core/src/Yi/Buffer/Misc.hs index 524d89cd8..a9b60bc4b 100644 --- a/yi-core/src/Yi/Buffer/Misc.hs +++ b/yi-core/src/Yi/Buffer/Misc.hs @@ -449,9 +449,10 @@ runBufferFull w b f = MarkSet { insMark = MarkValue 0 Forward, selMark = MarkValue 0 Backward, -- sel fromMark = MarkValue 0 Backward } -- from - else do - Just mrks <- uses winMarksA (M.lookup $ wkey (b ^. lastActiveWindowA)) - forM mrks getMarkValueB + else uses winMarksA (M.lookup $ wkey (b ^. lastActiveWindowA)) + >>= \case + Just mrks -> forM mrks getMarkValueB + Nothing -> error "runBufferFull: no marks from previous window" newMrks <- forM newMarkValues newMarkB winMarksA %= M.insert (wkey w) newMrks lastActiveWindowA .= w @@ -869,9 +870,10 @@ getInsMark :: BufferM Mark getInsMark = insMark <$> askMarks askMarks :: BufferM WinMarks -askMarks = do - Just !ms <- getMarks =<< ask - return ms +askMarks = + ask >>= getMarks >>= \case + Just !ms -> return ms + Nothing -> error "askMarks failed" getMarkB :: Maybe String -> BufferM Mark getMarkB m = do From f8fb11bfdd7c618634475457ad5a0fa4fe17ebb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Xaver=20H=C3=B6rl?= Date: Sun, 17 Feb 2019 18:38:41 +0100 Subject: [PATCH 4/5] Replace potentially failing pattern by explicit call to error in Yi.Hoogle --- yi-core/src/Yi/Hoogle.hs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/yi-core/src/Yi/Hoogle.hs b/yi-core/src/Yi/Hoogle.hs index 5b86f0734..6e082b945 100644 --- a/yi-core/src/Yi/Hoogle.hs +++ b/yi-core/src/Yi/Hoogle.hs @@ -80,10 +80,12 @@ hoogle = do wordRegion <- regionOfB unitWord word <- readRegionB wordRegion return (wordRegion, word) - ((modl,fun):_) <- io $ hoogleFunModule word - - withCurrentBuffer $ replaceRegionB wordRegion fun - return modl + funMods <- io $ hoogleFunModule word + case funMods of + ((modl,fun):_) -> do + withCurrentBuffer $ replaceRegionB wordRegion fun + return modl + _ -> error "hoogle search failed" -- | Call out to 'hoogleRaw', and print inside the Minibuffer the results of -- searching Hoogle with the word at point. From e57dcbea81e4cd02288a7e9a714dda53ef06196c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Xaver=20H=C3=B6rl?= Date: Sun, 17 Feb 2019 19:40:34 +0100 Subject: [PATCH 5/5] Replace potentially failing patterns by explicit call to error in Yi.Search --- yi-core/src/Yi/Search.hs | 65 +++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/yi-core/src/Yi/Search.hs b/yi-core/src/Yi/Search.hs index dc48863b1..ed2b18c65 100644 --- a/yi-core/src/Yi/Search.hs +++ b/yi-core/src/Yi/Search.hs @@ -298,10 +298,12 @@ isearchDelE = do _ -> return () -- if the searched string is empty, don't try to remove chars from it. isearchHistory :: Int -> EditorM () -isearchHistory delta = do - Isearch ((current,_p0,_dir):_) <- getEditorDyn - h <- historyMoveGen iSearch delta (return current) - isearchFunE (const h) +isearchHistory delta = + getEditorDyn >>= \case + Isearch ((current,_p0,_dir):_) -> do + h <- historyMoveGen iSearch delta (return current) + isearchFunE (const h) + _ -> error "isearchHistory: invalid isearch state encountered" isearchPrevE :: EditorM () isearchPrevE = isearchNext0 Backward @@ -310,34 +312,37 @@ isearchNextE :: EditorM () isearchNextE = isearchNext0 Forward isearchNext0 :: Direction -> EditorM () -isearchNext0 newDir = do - Isearch ((current,_p0,_dir):_rest) <- getEditorDyn - if T.null current - then isearchHistory 1 - else isearchNext newDir - +isearchNext0 newDir = + getEditorDyn >>= \case + Isearch ((current,_p0,_dir):_rest) -> + if T.null current + then isearchHistory 1 + else isearchNext newDir + _ -> error "isearchNext0: invalid isearch state encountered" isearchNext :: Direction -> EditorM () -isearchNext direction = do - Isearch ((current, p0, _dir) : rest) <- getEditorDyn - withCurrentBuffer $ moveTo (regionStart p0 + startOfs) - mp <- withCurrentBuffer $ - regexB direction (makeISearch current) - case mp of - [] -> do - endPoint <- withCurrentBuffer $ do - moveTo (regionEnd p0) -- revert to offset we were before. - sizeB - printMsg "isearch: end of document reached" - let wrappedOfs = case direction of - Forward -> mkRegion 0 0 - Backward -> mkRegion endPoint endPoint - putEditorDyn $ Isearch ((current,wrappedOfs,direction):rest) -- prepare to wrap around. - (p:_) -> do - withCurrentBuffer $ - moveTo (regionEnd p) - printMsg $ "I-search: " <> current - putEditorDyn $ Isearch ((current,p,direction):rest) +isearchNext direction = + getEditorDyn >>= \case + Isearch ((current, p0, _dir) : rest) -> do + withCurrentBuffer $ moveTo (regionStart p0 + startOfs) + mp <- withCurrentBuffer $ + regexB direction (makeISearch current) + case mp of + [] -> do + endPoint <- withCurrentBuffer $ do + moveTo (regionEnd p0) -- revert to offset we were before. + sizeB + printMsg "isearch: end of document reached" + let wrappedOfs = case direction of + Forward -> mkRegion 0 0 + Backward -> mkRegion endPoint endPoint + putEditorDyn $ Isearch ((current,wrappedOfs,direction):rest) -- prepare to wrap around. + (p:_) -> do + withCurrentBuffer $ + moveTo (regionEnd p) + printMsg $ "I-search: " <> current + putEditorDyn $ Isearch ((current,p,direction):rest) + _ -> error "isearchNext: invalid isearch state encountered" where startOfs = case direction of Forward -> 1 Backward -> -1