Skip to content

Commit 225c95f

Browse files
authored
Implementation of ; and , for vi editing mode (#207)
1 parent d7c26e5 commit 225c95f

File tree

7 files changed

+243
-179
lines changed

7 files changed

+243
-179
lines changed

Changelog

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
Unreleased changes:
1+
Changed in version 0.8.4.1:
2+
3+
* Implemented ; and , movements and enabled them for d, c, and y actions.
4+
5+
* Internal refactoring of f, F, t, T commands to allow implementation of ;
6+
and , commands.
27

38
Changed in version 0.8.4.0:
49

@@ -43,6 +48,7 @@ Changed in version 0.8.1.0:
4348
Changed in version 0.8.0.1:
4449
* Add a Cabal flag to disable the example executable as well as
4550
the test that uses it.
51+
4652
Changed in version 0.8.0.0:
4753
* Breaking changes:
4854
* Add a `MonadFail` instance for `InputT`.

System/Console/Haskeline/Command.hs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module System.Console.Haskeline.Command(
22
-- * Commands
33
Effect(..),
4-
KeyMap(..),
4+
KeyMap(..),
55
CmdM(..),
66
Command,
77
KeyCommand,
@@ -20,10 +20,12 @@ module System.Console.Haskeline.Command(
2020
change,
2121
changeFromChar,
2222
(+>),
23+
useKey,
2324
useChar,
2425
choiceCmd,
2526
keyChoiceCmd,
2627
keyChoiceCmdM,
28+
doAfter,
2729
doBefore
2830
) where
2931

@@ -34,9 +36,9 @@ import System.Console.Haskeline.LineState
3436
import System.Console.Haskeline.Key
3537

3638
data Effect = LineChange (Prefix -> LineChars)
37-
| PrintLines [String]
38-
| ClearScreen
39-
| RingBell
39+
| PrintLines [String]
40+
| ClearScreen
41+
| RingBell
4042

4143
lineChange :: LineState s => s -> Effect
4244
lineChange = LineChange . flip lineChars
@@ -91,7 +93,7 @@ useKey k x = KeyMap $ \k' -> if k==k' then Just (Consumed x) else Nothing
9193
-- TODO: could just be a monadic action that returns a Char.
9294
useChar :: (Char -> Command m s t) -> KeyCommand m s t
9395
useChar act = KeyMap $ \k -> case k of
94-
Key m (KeyChar c) | isPrint c && m==noModifier
96+
Key m (KeyChar c) | isPrint c && m == noModifier
9597
-> Just $ Consumed (act c)
9698
_ -> Nothing
9799

@@ -110,9 +112,15 @@ keyChoiceCmd = keyCommand . choiceCmd
110112
keyChoiceCmdM :: [KeyMap (CmdM m a)] -> CmdM m a
111113
keyChoiceCmdM = GetKey . choiceCmd
112114

115+
doBefore :: Monad m => Command m s t -> KeyCommand m t u -> KeyCommand m s u
116+
doBefore g km = fmap (g >=>) km
117+
118+
doAfter :: Monad m => KeyCommand m s t -> Command m t u -> KeyCommand m s u
119+
doAfter km g = fmap (>=> g) km
120+
113121
infixr 6 >+>
114122
(>+>) :: Monad m => KeyCommand m s t -> Command m t u -> KeyCommand m s u
115-
km >+> g = fmap (>=> g) km
123+
(>+>) = doAfter
116124

117125
-- attempt to run the command (predicated on getting a valid key); but if it fails, just keep
118126
-- going.
@@ -155,6 +163,3 @@ change = (setState .)
155163

156164
changeFromChar :: (LineState t, Monad m) => (Char -> s -> t) -> KeyCommand m s t
157165
changeFromChar f = useChar $ change . f
158-
159-
doBefore :: Monad m => Command m s t -> KeyCommand m t u -> KeyCommand m s u
160-
doBefore cmd = fmap (cmd >=>)

System/Console/Haskeline/Command/History.hs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ data HistLog = HistLog {pastHistory, futureHistory :: [[Grapheme]]}
1717
prevHistoryM :: [Grapheme] -> HistLog -> Maybe ([Grapheme],HistLog)
1818
prevHistoryM _ HistLog {pastHistory = []} = Nothing
1919
prevHistoryM s HistLog {pastHistory=ls:past, futureHistory=future}
20-
= Just (ls,
20+
= Just (ls,
2121
HistLog {pastHistory=past, futureHistory= s:future})
2222

2323
prevHistories :: [Grapheme] -> HistLog -> [([Grapheme],HistLog)]
@@ -45,7 +45,7 @@ runHistoryFromFile (Just file) stifleAmt f = do
4545
return x
4646

4747
prevHistory, firstHistory :: Save s => s -> HistLog -> (s, HistLog)
48-
prevHistory s h = let (s',h') = fromMaybe (listSave s,h)
48+
prevHistory s h = let (s',h') = fromMaybe (listSave s,h)
4949
$ prevHistoryM (listSave s) h
5050
in (listRestore s',h')
5151

@@ -73,7 +73,7 @@ reverseHist f = do
7373
modify reverser
7474
return y
7575
where
76-
reverser h = HistLog {futureHistory=pastHistory h,
76+
reverser h = HistLog {futureHistory=pastHistory h,
7777
pastHistory=futureHistory h}
7878

7979
data SearchMode = SearchMode {searchTerm :: [Grapheme],
@@ -84,13 +84,17 @@ data SearchMode = SearchMode {searchTerm :: [Grapheme],
8484
data Direction = Forward | Reverse
8585
deriving (Show,Eq)
8686

87+
flipDir :: Direction -> Direction
88+
flipDir Forward = Reverse
89+
flipDir Reverse = Forward
90+
8791
directionName :: Direction -> String
8892
directionName Forward = "i-search"
8993
directionName Reverse = "reverse-i-search"
9094

9195
instance LineState SearchMode where
9296
beforeCursor _ sm = beforeCursor prefix (foundHistory sm)
93-
where
97+
where
9498
prefix = stringToGraphemes ("(" ++ directionName (direction sm) ++ ")`")
9599
++ searchTerm sm ++ stringToGraphemes "': "
96100
afterCursor = afterCursor . foundHistory
@@ -105,14 +109,14 @@ startSearchMode :: Direction -> InsertMode -> SearchMode
105109
startSearchMode dir im = SearchMode {searchTerm = [],foundHistory=im, direction=dir}
106110

107111
addChar :: Char -> SearchMode -> SearchMode
108-
addChar c s = s {searchTerm = listSave $ insertChar c
112+
addChar c s = s {searchTerm = listSave $ insertChar c
109113
$ listRestore $ searchTerm s}
110114

111115
searchHistories :: Direction -> [Grapheme] -> [([Grapheme],HistLog)]
112116
-> Maybe (SearchMode,HistLog)
113117
searchHistories dir text = foldr mplus Nothing . map findIt
114118
where
115-
findIt (l,h) = do
119+
findIt (l,h) = do
116120
im <- findInLine text l
117121
return (SearchMode text im dir,h)
118122

System/Console/Haskeline/Command/KillRing.hs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,55 +38,55 @@ runKillRing act = do
3838
pasteCommand :: (Save s, MonadState KillRing m, MonadState Undo m)
3939
=> ([Grapheme] -> s -> s) -> Command m (ArgMode s) s
4040
pasteCommand use = \s -> do
41-
ms <- liftM peek get
41+
ms <- peek <$> get
4242
case ms of
4343
Nothing -> return $ argState s
4444
Just p -> do
4545
modify $ saveToUndo $ argState s
4646
setState $ applyArg (use p) s
4747

48-
deleteFromDiff' :: InsertMode -> InsertMode -> ([Grapheme],InsertMode)
48+
deleteFromDiff' :: InsertMode -> InsertMode -> ([Grapheme], InsertMode)
4949
deleteFromDiff' (IMode xs1 ys1) (IMode xs2 ys2)
5050
| posChange >= 0 = (take posChange ys1, IMode xs1 ys2)
51-
| otherwise = (take (negate posChange) ys2 ,IMode xs2 ys1)
51+
| otherwise = (take (negate posChange) ys2, IMode xs2 ys1)
5252
where
5353
posChange = length xs2 - length xs1
5454

5555
killFromHelper :: (MonadState KillRing m, MonadState Undo m,
5656
Save s, Save t)
5757
=> KillHelper -> Command m s t
5858
killFromHelper helper = saveForUndo >=> \oldS -> do
59-
let (gs,newIM) = applyHelper helper (save oldS)
59+
let (gs, newIM) = applyHelper helper (save oldS)
6060
modify (push gs)
6161
setState (restore newIM)
6262

6363
killFromArgHelper :: (MonadState KillRing m, MonadState Undo m, Save s, Save t)
6464
=> KillHelper -> Command m (ArgMode s) t
6565
killFromArgHelper helper = saveForUndo >=> \oldS -> do
66-
let (gs,newIM) = applyArgHelper helper (fmap save oldS)
66+
let (gs, newIM) = applyArgHelper helper (fmap save oldS)
6767
modify (push gs)
6868
setState (restore newIM)
6969

7070
copyFromArgHelper :: (MonadState KillRing m, Save s)
7171
=> KillHelper -> Command m (ArgMode s) s
7272
copyFromArgHelper helper = \oldS -> do
73-
let (gs,_) = applyArgHelper helper (fmap save oldS)
73+
let (gs, _) = applyArgHelper helper (fmap save oldS)
7474
modify (push gs)
7575
setState (argState oldS)
7676

7777

7878
data KillHelper = SimpleMove (InsertMode -> InsertMode)
79-
| GenericKill (InsertMode -> ([Grapheme],InsertMode))
79+
| GenericKill (InsertMode -> ([Grapheme], InsertMode))
8080
-- a generic kill gives more flexibility, but isn't repeatable.
81-
-- for example: dd,cc, %
81+
-- for example: dd, cc, %
8282

8383
killAll :: KillHelper
8484
killAll = GenericKill $ \(IMode xs ys) -> (reverse xs ++ ys, emptyIM)
8585

86-
applyHelper :: KillHelper -> InsertMode -> ([Grapheme],InsertMode)
86+
applyHelper :: KillHelper -> InsertMode -> ([Grapheme], InsertMode)
8787
applyHelper (SimpleMove move) im = deleteFromDiff' im (move im)
8888
applyHelper (GenericKill act) im = act im
8989

90-
applyArgHelper :: KillHelper -> ArgMode InsertMode -> ([Grapheme],InsertMode)
90+
applyArgHelper :: KillHelper -> ArgMode InsertMode -> ([Grapheme], InsertMode)
9191
applyArgHelper (SimpleMove move) im = deleteFromDiff' (argState im) (applyArg move im)
9292
applyArgHelper (GenericKill act) im = act (argState im)

System/Console/Haskeline/Command/Undo.hs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ initialUndo = Undo {pastUndo = [emptyIM], futureRedo = []}
1919

2020
saveToUndo :: Save s => s -> Undo -> Undo
2121
saveToUndo s undo
22-
| not isSame = Undo {pastUndo = toSave:pastUndo undo,futureRedo=[]}
22+
| not isSame = Undo {pastUndo = toSave:pastUndo undo, futureRedo=[]}
2323
| otherwise = undo
2424
where
2525
toSave = save s
@@ -39,12 +39,11 @@ redoFuture ls u@Undo {futureRedo = (futureLS:lss)}
3939

4040

4141
saveForUndo :: (Save s, MonadState Undo m)
42-
=> Command m s s
42+
=> Command m s s
4343
saveForUndo s = do
4444
modify (saveToUndo s)
4545
return s
4646

4747
commandUndo, commandRedo :: (MonadState Undo m, Save s) => Command m s s
4848
commandUndo = simpleCommand $ liftM Right . update . undoPast
4949
commandRedo = simpleCommand $ liftM Right . update . redoFuture
50-

System/Console/Haskeline/LineState.hs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module System.Console.Haskeline.LineState(
55
-- * Graphemes
66
Grapheme(),
77
baseChar,
8+
baseGrapheme, -- XXX The author says no!
89
stringToGraphemes,
910
graphemesToString,
1011
modifyBaseChar,
@@ -74,7 +75,7 @@ import Data.Char
7475
-- can represent one grapheme; for example, an @a@ followed by the diacritic @\'\\768\'@ should
7576
-- be treated as one unit.
7677
data Grapheme = Grapheme {gBaseChar :: Char,
77-
combiningChars :: [Char]}
78+
combiningChars :: [Char]}
7879
deriving Eq
7980

8081
instance Show Grapheme where
@@ -163,7 +164,7 @@ listRestore xs = restore $ IMode (reverse xs) []
163164

164165
class Move s where
165166
goLeft, goRight, moveToStart, moveToEnd :: s -> s
166-
167+
167168
-- | The standard line state representation; considers the cursor to be located
168169
-- between two characters. The first list is reversed.
169170
data InsertMode = IMode [Grapheme] [Grapheme]
@@ -181,7 +182,7 @@ instance Save InsertMode where
181182
restore = id
182183

183184
instance Move InsertMode where
184-
goLeft im@(IMode [] _) = im
185+
goLeft im@(IMode [] _) = im
185186
goLeft (IMode (x:xs) ys) = IMode xs (x:ys)
186187

187188
goRight im@(IMode _ []) = im
@@ -194,7 +195,7 @@ emptyIM :: InsertMode
194195
emptyIM = IMode [] []
195196

196197
-- | Insert one character, which may be combining, to the left of the cursor.
197-
--
198+
--
198199
insertChar :: Char -> InsertMode -> InsertMode
199200
insertChar c im@(IMode xs ys)
200201
| isCombiningChar c = case xs of
@@ -203,7 +204,7 @@ insertChar c im@(IMode xs ys)
203204
z:zs -> IMode (addCombiner z c : zs) ys
204205
| otherwise = IMode (baseGrapheme c : xs) ys
205206

206-
-- | Insert a sequence of characters to the left of the cursor.
207+
-- | Insert a sequence of characters to the left of the cursor.
207208
insertString :: String -> InsertMode -> InsertMode
208209
insertString s (IMode xs ys) = IMode (reverse (stringToGraphemes s) ++ xs) ys
209210

@@ -212,12 +213,12 @@ deleteNext im@(IMode _ []) = im
212213
deleteNext (IMode xs (_:ys)) = IMode xs ys
213214

214215
deletePrev im@(IMode [] _) = im
215-
deletePrev (IMode (_:xs) ys) = IMode xs ys
216+
deletePrev (IMode (_:xs) ys) = IMode xs ys
216217

217218
skipLeft, skipRight :: (Char -> Bool) -> InsertMode -> InsertMode
218-
skipLeft f (IMode xs ys) = let (ws,zs) = span (f . baseChar) xs
219+
skipLeft f (IMode xs ys) = let (ws,zs) = span (f . baseChar) xs
219220
in IMode zs (reverse ws ++ ys)
220-
skipRight f (IMode xs ys) = let (ws,zs) = span (f . baseChar) ys
221+
skipRight f (IMode xs ys) = let (ws,zs) = span (f . baseChar) ys
221222
in IMode (reverse ws ++ xs) zs
222223

223224
transposeChars :: InsertMode -> InsertMode
@@ -326,7 +327,7 @@ instance Functor ArgMode where
326327

327328
instance LineState s => LineState (ArgMode s) where
328329
beforeCursor _ am = let pre = map baseGrapheme $ "(arg: " ++ show (arg am) ++ ") "
329-
in beforeCursor pre (argState am)
330+
in beforeCursor pre (argState am)
330331
afterCursor = afterCursor . argState
331332

332333
instance Result s => Result (ArgMode s) where
@@ -342,15 +343,15 @@ startArg = ArgMode
342343
addNum :: Int -> ArgMode s -> ArgMode s
343344
addNum n am
344345
| arg am >= 1000 = am -- shouldn't ever need more than 4 digits
345-
| otherwise = am {arg = arg am * 10 + n}
346+
| otherwise = am {arg = arg am * 10 + n}
346347

347-
-- todo: negatives
348+
-- TODO: negatives
348349
applyArg :: (s -> s) -> ArgMode s -> s
349350
applyArg f am = repeatN (arg am) f (argState am)
350351

351352
repeatN :: Int -> (a -> a) -> a -> a
352353
repeatN n f | n <= 1 = f
353-
| otherwise = f . repeatN (n-1) f
354+
| otherwise = f . repeatN (n-1) f
354355

355356
applyCmdArg :: (InsertMode -> InsertMode) -> ArgMode CommandMode -> CommandMode
356357
applyCmdArg f am = withCommandMode (repeatN (arg am) f) (argState am)
@@ -406,10 +407,9 @@ afterChar _ _ = False
406407
goRightUntil, goLeftUntil :: (InsertMode -> Bool) -> InsertMode -> InsertMode
407408
goRightUntil f = loop . goRight
408409
where
409-
loop im@(IMode _ ys) | null ys || f im = im
410+
loop im@(IMode _ ys) | null ys || f im = im
410411
| otherwise = loop (goRight im)
411412
goLeftUntil f = loop . goLeft
412413
where
413-
loop im@(IMode xs _) | null xs || f im = im
414-
| otherwise = loop (goLeft im)
415-
414+
loop im@(IMode xs _) | null xs || f im = im
415+
| otherwise = loop (goLeft im)

0 commit comments

Comments
 (0)