1+ {-# LANGUAGE LambdaCase #-}
12#if __GLASGOW_HASKELL__ < 802
23{-# OPTIONS_GHC -Wno-redundant-constraints #-}
34#endif
@@ -21,15 +22,20 @@ type EitherMode = Either CommandMode InsertMode
2122
2223type SavedCommand m = Command (ViT m ) (ArgMode CommandMode ) EitherMode
2324
25+ data InlineSearch = F -- f | F
26+ | T -- t | T
27+
2428data ViState m = ViState {
2529 lastCommand :: SavedCommand m ,
26- lastSearch :: [Grapheme ]
30+ lastSearch :: [Grapheme ],
31+ lastInlineSearch :: Maybe (Char , InlineSearch , Direction )
2732 }
2833
2934emptyViState :: Monad m => ViState m
3035emptyViState = ViState {
3136 lastCommand = return . Left . argState,
32- lastSearch = []
37+ lastSearch = [] ,
38+ lastInlineSearch = Nothing
3339 }
3440
3541type ViT m = StateT (ViState m ) (InputCmdT m )
@@ -134,6 +140,40 @@ simpleCmdActions = choiceCmd [
134140 , simpleKey KillLine `useKey` (noArg >=> killAndStoreC (SimpleMove moveToStart))
135141 ]
136142
143+ inlineSearchActions :: InputKeyCmd (ArgMode CommandMode ) CommandMode
144+ inlineSearchActions = choiceCmd
145+ [ simpleChar ' f' `useKey` keyCommand (useChar $ \ c -> (saveInlineSearch F Forward c >>= ) . viInlineSearch id )
146+ , simpleChar ' F' `useKey` keyCommand (useChar $ \ c -> (saveInlineSearch F Reverse c >>= ) . viInlineSearch id )
147+ , simpleChar ' t' `useKey` keyCommand (useChar $ \ c -> (saveInlineSearch T Forward c >>= ) . viInlineSearch id )
148+ , simpleChar ' T' `useKey` keyCommand (useChar $ \ c -> (saveInlineSearch T Reverse c >>= ) . viInlineSearch id )
149+ , simpleChar ' ;' `useKey` ((getLastInlineSearch >>= ) . viInlineSearch id )
150+ , simpleChar ' ,' `useKey` ((getLastInlineSearch >>= ) . viInlineSearch flipDir)
151+ ]
152+
153+ viInlineSearch :: forall m . Monad m => (Direction -> Direction )
154+ -> ArgMode CommandMode
155+ -> (Maybe (Char , InlineSearch , Direction ))
156+ -> CmdM (ViT m ) CommandMode
157+ viInlineSearch flipdir = \ s -> \ case
158+ Nothing -> return $ argState s
159+ Just (g, fOrT, dir) -> setState $ (applyArg . withCommandMode . search fOrT (flipdir dir)) (== g) s
160+ where
161+ search :: InlineSearch -> Direction -> (Char -> Bool ) -> InsertMode -> InsertMode
162+ search F Forward = goRightUntil . overChar
163+ search F Reverse = goLeftUntil . overChar
164+ search T Forward = goRightUntil . beforeChar
165+ search T Reverse = goLeftUntil . afterChar
166+
167+ getLastInlineSearch :: forall m . Monad m => CmdM (ViT m ) (Maybe (Char , InlineSearch , Direction ))
168+ getLastInlineSearch = lastInlineSearch <$> (get :: CmdM (ViT m ) (ViState m )) -- TODO: ideally this is a usage of `gets`
169+
170+ saveInlineSearch :: forall m . Monad m => InlineSearch -> Direction -> Char
171+ -> CmdM (ViT m ) (Maybe (Char , InlineSearch , Direction ))
172+ saveInlineSearch fOrT dir char
173+ = do let ret = Just (char, fOrT, dir)
174+ modify $ \ (vs :: ViState m ) -> vs {lastInlineSearch = ret}
175+ return ret
176+
137177replaceOnce :: InputCmd CommandMode CommandMode
138178replaceOnce = try $ changeFromChar replaceChar
139179
@@ -150,37 +190,38 @@ repeatedCommands = choiceCmd [argumented, doBefore noArg repeatableCommands]
150190 ]
151191
152192pureMovements :: InputKeyCmd (ArgMode CommandMode ) CommandMode
153- pureMovements = choiceCmd $ charMovements ++ map mkSimpleCommand movements
193+ pureMovements = choiceCmd $ map mkSimpleCommand movements
154194 where
155- charMovements = [ charMovement ' f' $ \ c -> goRightUntil $ overChar (== c)
156- , charMovement ' F' $ \ c -> goLeftUntil $ overChar (== c)
157- , charMovement ' t' $ \ c -> goRightUntil $ beforeChar (== c)
158- , charMovement ' T' $ \ c -> goLeftUntil $ afterChar (== c)
159- ]
160- mkSimpleCommand (k,move) = k +> change (applyCmdArg move)
161- charMovement c move = simpleChar c +> keyChoiceCmd [
162- useChar (change . applyCmdArg . move)
163- , withoutConsuming (change argState)
164- ]
165-
166- useMovementsForKill :: Command m s t -> (KillHelper -> Command m s t ) -> KeyCommand m s t
167- useMovementsForKill alternate useHelper = choiceCmd $
195+ mkSimpleCommand (k, move) = k `useKey` change (applyCmdArg move)
196+
197+ useMovementsForKill :: (KillHelper -> Command m s t ) -> KeyCommand m s t
198+ useMovementsForKill useHelper = choiceCmd $
168199 specialCases
169200 ++ map (\ (k,move) -> k `useKey` useHelper (SimpleMove move)) movements
170201 where
171202 specialCases = [ simpleChar ' e' `useKey` useHelper (SimpleMove goToWordDelEnd)
172203 , simpleChar ' E' `useKey` useHelper (SimpleMove goToBigWordDelEnd)
173204 , simpleChar ' %' `useKey` useHelper (GenericKill deleteMatchingBrace)
174- -- Note 't' and 'f' behave differently than in pureMovements.
175- , charMovement ' f' $ \ c -> goRightUntil $ afterChar (== c)
176- , charMovement ' F' $ \ c -> goLeftUntil $ overChar (== c)
177- , charMovement ' t' $ \ c -> goRightUntil $ overChar (== c)
178- , charMovement ' T' $ \ c -> goLeftUntil $ afterChar (== c)
179205 ]
180- charMovement c move = simpleChar c +> keyChoiceCmd [
181- useChar (useHelper . SimpleMove . move)
182- , withoutConsuming alternate]
183206
207+ useInlineSearchForKill :: Monad m => Command (ViT m ) s t -> (KillHelper -> Command (ViT m ) s t ) -> KeyMap (Command (ViT m ) s t )
208+ useInlineSearchForKill alternate killCmd = choiceCmd
209+ [ simpleChar ' f' `useKey` keyCommand (useChar $ \ c -> (saveInlineSearch F Forward c >>= ) . getSearchAndKill)
210+ , simpleChar ' F' `useKey` keyCommand (useChar $ \ c -> (saveInlineSearch F Reverse c >>= ) . getSearchAndKill)
211+ , simpleChar ' t' `useKey` keyCommand (useChar $ \ c -> (saveInlineSearch T Forward c >>= ) . getSearchAndKill)
212+ , simpleChar ' T' `useKey` keyCommand (useChar $ \ c -> (saveInlineSearch T Reverse c >>= ) . getSearchAndKill)
213+ , simpleChar ' ;' `useKey` ((getLastInlineSearch >>= ) . getSearchAndKill)
214+ , simpleChar ' ,' `useKey` ((reverseDir <$> getLastInlineSearch >>= ) . getSearchAndKill)
215+ ]
216+ where
217+ getSearchAndKill = \ s
218+ -> \ case (Just (g, fOrT, forOrRev)) -> killCmd (SimpleMove $ moveForKill fOrT forOrRev $ (== g)) s
219+ Nothing -> alternate s
220+
221+ moveForKill F Forward = goRightUntil . afterChar
222+ moveForKill F Reverse = goLeftUntil . overChar
223+ moveForKill T Forward = goRightUntil . overChar
224+ moveForKill T Reverse = goLeftUntil . afterChar
184225
185226repeatableCommands :: InputKeyCmd (ArgMode CommandMode ) EitherMode
186227repeatableCommands = choiceCmd
@@ -201,6 +242,7 @@ repeatableCmdMode = choiceCmd
201242 , simpleChar ' d' `useKey` deletionCmd
202243 , simpleChar ' y' `useKey` yankCommand
203244 , ctrlChar ' w' `useKey` killAndStoreC wordErase
245+ , inlineSearchActions
204246 , pureMovements
205247 ]
206248 where
@@ -220,7 +262,8 @@ deletionCmd :: InputCmd (ArgMode CommandMode) CommandMode
220262deletionCmd = keyChoiceCmd
221263 [ reinputArg >+> deletionCmd
222264 , simpleChar ' d' `useKey` killAndStoreC killAll
223- , useMovementsForKill (change argState) killAndStoreC
265+ , useMovementsForKill killAndStoreC
266+ , useInlineSearchForKill (change argState) killAndStoreC
224267 , withoutConsuming (change argState)
225268 ]
226269
@@ -232,7 +275,8 @@ deletionToInsertCmd = keyChoiceCmd
232275 -- readline does this too, so we should also.
233276 , simpleChar ' w' `useKey` killAndStoreE (SimpleMove goToWordDelEnd)
234277 , simpleChar ' W' `useKey` killAndStoreE (SimpleMove goToBigWordDelEnd)
235- , useMovementsForKill (fmap Left . change argState) killAndStoreE
278+ , useMovementsForKill killAndStoreE
279+ , useInlineSearchForKill (fmap Left . change argState) killAndStoreE
236280 , withoutConsuming (return . Left . argState)
237281 ]
238282
@@ -241,7 +285,8 @@ yankCommand :: InputCmd (ArgMode CommandMode) CommandMode
241285yankCommand = keyChoiceCmd
242286 [ reinputArg >+> yankCommand
243287 , simpleChar ' y' `useKey` copyAndStore killAll
244- , useMovementsForKill (change argState) copyAndStore
288+ , useMovementsForKill copyAndStore
289+ , useInlineSearchForKill (change argState) copyAndStore
245290 , withoutConsuming (change argState)
246291 ]
247292
@@ -451,3 +496,8 @@ viSearchHist dir toSearch cm = do
451496 Right sm -> do
452497 put vstate {lastSearch = toSearch'}
453498 setState (restore (foundHistory sm))
499+
500+ reverseDir :: Maybe (a , b , Direction ) -> Maybe (a , b , Direction )
501+ reverseDir = (third3 flipDir <$> )
502+ where
503+ third3 f (a, b, c) = (a, b, f c)
0 commit comments