summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMateuszKowalczyk <>2014-11-07 02:41:00 (GMT)
committerhdiff <hdiff@hdiff.luite.com>2014-11-07 02:41:00 (GMT)
commit0e0ab9b409840228154c255e02541b7ff8ae068e (patch)
treed693cb17cdaf355b66cedf48ef86602a489f580b
parente440755857847e7732d19c7e3b1b6673959268d6 (diff)
version 0.11.10.11.1
-rw-r--r--src/library/Yi/Buffer/HighLevel.hs37
-rw-r--r--src/library/Yi/Buffer/Misc.hs29
-rw-r--r--src/library/Yi/Buffer/TextUnit.hs16
-rw-r--r--src/library/Yi/Editor.hs6
-rw-r--r--src/library/Yi/Eval.hs71
-rw-r--r--src/library/Yi/File.hs66
-rw-r--r--src/library/Yi/Keymap/Emacs.hs2
-rw-r--r--src/library/Yi/Keymap/Emacs/Utils.hs2
-rw-r--r--src/library/Yi/Keymap/Vim/Ex/Commands/Edit.hs2
-rw-r--r--src/library/Yi/Keymap/Vim/Ex/Commands/Quit.hs4
-rw-r--r--src/library/Yi/Keymap/Vim/Ex/Commands/Substitute.hs91
-rw-r--r--src/library/Yi/Keymap/Vim/Ex/Commands/Write.hs2
-rw-r--r--src/library/Yi/Keymap/Vim/ExMap.hs1
-rw-r--r--src/library/Yi/Keymap/Vim/Motion.hs2
-rw-r--r--src/library/Yi/Keymap/Vim/NormalMap.hs15
-rw-r--r--src/library/Yi/Keymap/Vim/Operator.hs3
-rw-r--r--src/library/Yi/Keymap/Vim/Tag.hs3
-rw-r--r--src/library/Yi/Main.hs4
-rw-r--r--src/library/Yi/Mode/Haskell.hs2
-rw-r--r--src/library/Yi/PersistentState.hs25
-rw-r--r--src/library/Yi/Tag.hs39
-rw-r--r--src/library/Yi/Types.hs7
-rw-r--r--src/library/Yi/UI/Pango.hs2
-rw-r--r--src/library/Yi/UI/SimpleLayout.hs24
-rw-r--r--src/library/Yi/UI/Vty.hs27
-rw-r--r--src/tests/vimtests/change/V3jc.test15
-rw-r--r--src/tests/vimtests/change/cc.test12
-rw-r--r--src/tests/vimtests/insertion/O4.test (renamed from src/tests/vimtests/insertion/O3.test)0
-rw-r--r--yi.cabal5
29 files changed, 395 insertions, 119 deletions
diff --git a/src/library/Yi/Buffer/HighLevel.hs b/src/library/Yi/Buffer/HighLevel.hs
index 3252d11..485eb2e 100644
--- a/src/library/Yi/Buffer/HighLevel.hs
+++ b/src/library/Yi/Buffer/HighLevel.hs
@@ -56,6 +56,7 @@ module Yi.Buffer.HighLevel
, lastNonSpaceB
, leftEdgesOfRegionB
, leftOnEol
+ , lineMoveVisRel
, linePrefixSelectionB
, lineStreamB
, lowercaseWordB
@@ -1152,3 +1153,39 @@ testHexB = savingPointB $ do
if leftChar == 'x' && leftToLeftChar == '0'
then return True
else return False
+
+-- | Move point down by @n@ lines
+-- If line extends past width of window, count moving
+-- a single line as moving width points to the right.
+lineMoveVisRel :: Int -> BufferM ()
+lineMoveVisRel = movingToPrefVisCol . lineMoveVisRelUp
+
+lineMoveVisRelUp :: Int -> BufferM ()
+lineMoveVisRelUp 0 = return ()
+lineMoveVisRelUp n | n < 0 = lineMoveVisRelDown $ negate n
+ | otherwise = do
+ wid <- width <$> use lastActiveWindowA
+ col <- curCol
+ len <- pointB >>= eolPointB >>= colOf
+ let jumps = (len `div` wid) - (col `div` wid)
+ next = n - jumps
+ if next <= 0
+ then moveXorEol (n * wid)
+ else do moveXorEol (jumps * wid)
+ void $ gotoLnFrom 1
+ lineMoveVisRelUp $ next - 1
+
+lineMoveVisRelDown :: Int -> BufferM ()
+lineMoveVisRelDown 0 = return ()
+lineMoveVisRelDown n | n < 0 = lineMoveVisRelUp $ negate n
+ | otherwise = do
+ wid <- width <$> use lastActiveWindowA
+ col <- curCol
+ let jumps = col `div` wid
+ next = n - jumps
+ if next <= 0
+ then leftN (n * wid)
+ else do leftN (jumps * wid)
+ void $ gotoLnFrom $ -1
+ moveToEol
+ lineMoveVisRelDown $ next - 1
diff --git a/src/library/Yi/Buffer/Misc.hs b/src/library/Yi/Buffer/Misc.hs
index 5800664..5d95abf 100644
--- a/src/library/Yi/Buffer/Misc.hs
+++ b/src/library/Yi/Buffer/Misc.hs
@@ -100,6 +100,7 @@ module Yi.Buffer.Misc
, savingPrefCol
, forgetPreferCol
, movingToPrefCol
+ , movingToPrefVisCol
, preferColA
, markSavedB
, addOverlayB
@@ -552,6 +553,7 @@ newB unique nm s =
, bkey__ = unique
, undos = emptyU
, preferCol = Nothing
+ , preferVisCol = Nothing
, bufferDynamic = mempty
, pendingUpdates = []
, selectionStyle = SelectionStyle False False
@@ -855,6 +857,18 @@ movingToPrefCol f = do
preferColA .= Just targetCol
return r
+-- | Moves to a visual column within the current line as shown
+-- on the editor (ie, moving within the current width of a
+-- single visual line)
+movingToPrefVisCol :: BufferM a -> BufferM a
+movingToPrefVisCol f = do
+ prefCol <- use preferVisColA
+ targetCol <- maybe curVisCol return prefCol
+ r <- f
+ moveToVisColB targetCol
+ preferVisColA .= Just targetCol
+ return r
+
moveToColB :: Int -> BufferM ()
moveToColB targetCol = do
solPnt <- solPointB =<< pointB
@@ -864,6 +878,13 @@ moveToColB targetCol = do
toSkip = takeWhile (\(char,col) -> char /= '\n' && col < targetCol) (zip chrs cols)
moveTo $ solPnt +~ fromIntegral (length toSkip)
+moveToVisColB :: Int -> BufferM ()
+moveToVisColB targetCol = do
+ col <- curCol
+ wid <- width <$> use lastActiveWindowA
+ let jumps = col `div` wid
+ moveToColB $ jumps * wid + targetCol
+
moveToLineColB :: Int -> Int -> BufferM ()
moveToLineColB line col = gotoLn line >> moveToColB col
@@ -871,13 +892,15 @@ pointOfLineColB :: Int -> Int -> BufferM Point
pointOfLineColB line col = savingPointB $ moveToLineColB line col >> pointB
forgetPreferCol :: BufferM ()
-forgetPreferCol = preferColA .= Nothing
+forgetPreferCol = preferColA .= Nothing >> preferVisColA .= Nothing
savingPrefCol :: BufferM a -> BufferM a
savingPrefCol f = do
pc <- use preferColA
+ pv <- use preferVisColA
result <- f
preferColA .= pc
+ preferVisColA .= pv
return result
-- | Move point up one line
@@ -974,6 +997,10 @@ indentSettingsB = withModeB $ return . modeIndentSettings
curCol :: BufferM Int
curCol = colOf =<< pointB
+-- | Current column, visually.
+curVisCol :: BufferM Int
+curVisCol = rem <$> curCol <*> (width <$> use lastActiveWindowA)
+
colOf :: Point -> BufferM Int
colOf p = do
is <- indentSettingsB
diff --git a/src/library/Yi/Buffer/TextUnit.hs b/src/library/Yi/Buffer/TextUnit.hs
index 9672ab2..e12261b 100644
--- a/src/library/Yi/Buffer/TextUnit.hs
+++ b/src/library/Yi/Buffer/TextUnit.hs
@@ -98,10 +98,18 @@ unitWord = GenUnit Document $ \direction -> checkPeekB (-1) [isWordChar, not . i
unitDelimited :: Char -> Char -> Bool -> TextUnit
unitDelimited left right included = GenUnit Document $ \direction ->
case (included,direction) of
- (False, Backward) -> checkPeekB 0 [(== left)] Backward
- (False, Forward) -> (== right) <$> readB
- (True, Backward) -> checkPeekB (-1) [(== left)] Backward
- (True, Forward) -> checkPeekB 0 [(== right)] Backward
+ (False, Backward) -> do
+ isCursorOnLeftChar <- (== left) <$> readB
+ when isCursorOnLeftChar rightB
+ checkPeekB 0 [(== left)] Backward
+ (False, Forward) -> do
+ isCursorOnRightChar <- (== right) <$> readB
+ isTextUnitBlank <- checkPeekB 0 [(== left)] Backward
+ if isTextUnitBlank && isCursorOnRightChar
+ then leftB >> return True
+ else return isCursorOnRightChar
+ (True, Backward) -> checkPeekB 0 [(== left)] Forward
+ (True, Forward) -> rightB >> checkPeekB 0 [(== right)] Backward
isWordChar :: Char -> Bool
isWordChar x = isAlphaNum x || x == '_'
diff --git a/src/library/Yi/Editor.hs b/src/library/Yi/Editor.hs
index 0f1d23f..c83d9a8 100644
--- a/src/library/Yi/Editor.hs
+++ b/src/library/Yi/Editor.hs
@@ -134,10 +134,10 @@ import Yi.Utils hiding ((+~))
import Yi.Window
instance Binary Editor where
- put (Editor bss bs supply ts dv _sl msh kr _re _dir _ev _cwa ) =
+ put (Editor bss bs supply ts dv _sl msh kr re _dir _ev _cwa ) =
let putNE (x :| xs) = put x >> put xs
in putNE bss >> put bs >> put supply >> put ts
- >> put dv >> put msh >> put kr
+ >> put dv >> put msh >> put kr >> put re
get = do
bss <- (:|) <$> get <*> get
bs <- get
@@ -146,6 +146,7 @@ instance Binary Editor where
dv <- get
msh <- get
kr <- get
+ re <- get
return $ emptyEditor { bufferStack = bss
, buffers = bs
, refSupply = supply
@@ -153,6 +154,7 @@ instance Binary Editor where
, dynamic = dv
, maxStatusHeight = msh
, killring = kr
+ , currentRegex = re
}
-- | The initial state
diff --git a/src/library/Yi/Eval.hs b/src/library/Yi/Eval.hs
index fc0e39c..484042f 100644
--- a/src/library/Yi/Eval.hs
+++ b/src/library/Yi/Eval.hs
@@ -3,6 +3,7 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS_HADDOCK show-extensions #-}
-- |
@@ -33,8 +34,12 @@ module Yi.Eval (
) where
import Control.Applicative ((<$>), (<*>))
+import Control.Concurrent
+import Control.Monad.Catch (try)
import Control.Lens hiding (Action)
import Control.Monad hiding (mapM_)
+import Control.Monad.Base
+import Control.Monad.Trans (lift)
import Data.Array
import Data.Binary
import Data.Default
@@ -51,7 +56,6 @@ import Yi.Boot.Internal (reload)
import Yi.Buffer
import Yi.Config.Simple.Types
import Yi.Core (errorEditor, runAction)
-import Yi.Debug
import Yi.Types (YiVariable,YiConfigVariable)
import Yi.Editor
import Yi.File
@@ -108,6 +112,49 @@ instance Default NamesCache where
def = NamesCache []
instance YiVariable NamesCache
+type HintRequest = (String, MVar (Either LHI.InterpreterError Action))
+newtype HintThreadVar = HintThreadVar (Maybe (MVar HintRequest))
+ deriving (Typeable, Default)
+
+instance Binary HintThreadVar where
+ put _ = return ()
+ get = return def
+instance YiVariable HintThreadVar
+
+getHintThread :: (MonadEditor m, MonadBase IO m) => m (MVar HintRequest)
+getHintThread = do
+ HintThreadVar x <- getEditorDyn
+ case x of
+ Just t -> return t
+ Nothing -> do
+ req <- io newEmptyMVar
+ contextFile <- Yi.Paths.getEvaluatorContextFilename
+ void . io . forkIO $ hintEvaluatorThread req contextFile
+ putEditorDyn . HintThreadVar $ Just req
+ return req
+
+hintEvaluatorThread :: MVar HintRequest -> FilePath -> IO ()
+hintEvaluatorThread request contextFile = do
+ haveUserContext <- doesFileExist contextFile
+ void $ LHI.runInterpreter $ do
+ LHI.set [LHI.searchPath LHI.:= []]
+
+ -- We no longer have Yi.Prelude, perhaps we should remove
+ -- NoImplicitPrelude?
+ LHI.set [LHI.languageExtensions LHI.:= [ LHI.OverloadedStrings
+ , LHI.NoImplicitPrelude
+ ]]
+ when haveUserContext $ do
+ LHI.loadModules [contextFile]
+ LHI.setTopLevelModules ["Env"]
+
+ -- Yi.Keymap: Action lives there
+ LHI.setImportsQ [("Yi", Nothing), ("Yi.Keymap",Just "Yi.Keymap")]
+ forever $ do
+ (s,response) <- lift $ takeMVar request
+ res <- try $ LHI.interpret ("Yi.makeAction (" ++ s ++ ")") (LHI.as :: Action)
+ lift $ putMVar response res
+
-- Evaluator implemented by calling GHCi. This evaluator can run
-- arbitrary expressions in the class 'YiAction'.
--
@@ -129,23 +176,11 @@ ghciEvaluator = Evaluator { execEditorActionImpl = execAction
execAction :: String -> YiM ()
execAction "reload" = reload
execAction s = do
- contextFile <- Yi.Paths.getEvaluatorContextFilename
- haveUserContext <- io $ doesFileExist contextFile
- res <- io $ LHI.runInterpreter $ do
- LHI.set [LHI.searchPath LHI.:= []]
-
- -- We no longer have Yi.Prelude, perhaps we should remove
- -- NoImplicitPrelude?
- LHI.set [LHI.languageExtensions LHI.:= [ LHI.OverloadedStrings
- , LHI.NoImplicitPrelude
- ]]
- when haveUserContext $ do
- LHI.loadModules [contextFile]
- LHI.setTopLevelModules ["Env"]
-
- -- Yi.Keymap: Action lives there
- LHI.setImportsQ [("Yi", Nothing), ("Yi.Keymap",Just "Yi.Keymap")]
- LHI.interpret ("Yi.makeAction (" ++ s ++ ")") (error "as" :: Action)
+ request <- getHintThread
+ res <- io $ do
+ response <- newEmptyMVar
+ putMVar request (s,response)
+ takeMVar response
case res of
Left err -> errorEditor (showT err)
Right action -> runAction action
diff --git a/src/library/Yi/File.hs b/src/library/Yi/File.hs
index 12acdc0..102f609 100644
--- a/src/library/Yi/File.hs
+++ b/src/library/Yi/File.hs
@@ -1,5 +1,7 @@
+{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_HADDOCK show-extensions #-}
-- |
@@ -13,6 +15,7 @@ module Yi.File (
-- * File-based actions
editFile,
openingNewFile,
+ openNewFile,
viWrite, viWriteTo, viSafeWriteTo,
fwriteE, -- :: YiM ()
@@ -24,19 +27,25 @@ module Yi.File (
-- * Helper functions
setFileName,
- deservesSave
+ deservesSave,
+
+ -- * Configuration
+ preSaveHooks
) where
import Control.Applicative
-import Control.Lens hiding (act)
-import Control.Monad (void)
+import Control.Lens hiding (act, Action)
+import Control.Monad (when, void)
import Control.Monad.Base
+import Data.Default
import Data.Monoid
import qualified Data.Text as T
+import Data.Typeable
import Data.Time
import System.Directory
import System.FriendlyPath
import Yi.Buffer
+import Yi.Config.Simple.Types (customVariable, Field)
import Yi.Core
import Yi.Dired
import Yi.Editor
@@ -44,8 +53,22 @@ import Yi.Keymap
import Yi.Monad
import qualified Yi.Rope as R
import Yi.String
+import Yi.Types
import Yi.Utils
+newtype PreSaveHooks = PreSaveHooks { _unPreSaveHooks :: [Action] }
+ deriving Typeable
+
+instance Default PreSaveHooks where
+ def = PreSaveHooks []
+
+instance YiConfigVariable PreSaveHooks
+
+makeLenses ''PreSaveHooks
+
+preSaveHooks :: Field [Action]
+preSaveHooks = customVariable . unPreSaveHooks
+
-- | Tries to open a new buffer with 'editFile' and runs the given
-- action on the buffer handle if it succeeds.
--
@@ -55,6 +78,10 @@ openingNewFile fp act = editFile fp >>= \case
Left m -> printMsg m
Right ref -> void $ withGivenBuffer ref act
+-- | Same as @openingNewFile@ with no action to run after.
+openNewFile :: FilePath -> YiM ()
+openNewFile = flip openingNewFile $ return ()
+
-- | Revert to the contents of the file on disk
revertE :: YiM ()
revertE = do
@@ -81,22 +108,22 @@ viWrite = do
Just f -> do
bufInfo <- withCurrentBuffer bufInfoB
let s = bufInfoFileName bufInfo
- fwriteE
+ succeed <- fwriteE
let message = (showT f <>) (if f == s
then " written"
else " " <> showT s <> " written")
- printMsg message
+ when succeed $ printMsg message
-- | Try to write to a named file in the manner of vi/vim
viWriteTo :: T.Text -> YiM ()
viWriteTo f = do
bufInfo <- withCurrentBuffer bufInfoB
let s = T.pack $ bufInfoFileName bufInfo
- fwriteToE f
+ succeed <- fwriteToE f
let message = f `T.append` if f == s
then " written"
else ' ' `T.cons` s `T.append` " written"
- printMsg message
+ when succeed $ printMsg message
-- | Try to write to a named file if it doesn't exist. Error out if it does.
viSafeWriteTo :: T.Text -> YiM ()
@@ -107,11 +134,11 @@ viSafeWriteTo f = do
else viWriteTo f
-- | Write current buffer to disk, if this buffer is associated with a file
-fwriteE :: YiM ()
+fwriteE :: YiM Bool
fwriteE = fwriteBufferE =<< gets currentBuffer
-- | Write a given buffer to disk if it is associated with a file.
-fwriteBufferE :: BufferRef -> YiM ()
+fwriteBufferE :: BufferRef -> YiM Bool
fwriteBufferE bufferKey = do
nameContents <- withGivenBuffer bufferKey $ do
fl <- gets file
@@ -121,27 +148,32 @@ fwriteBufferE bufferKey = do
case nameContents of
(Just f, contents, conv) -> io (doesDirectoryExist f) >>= \case
- True -> printMsg "Can't save over a directory, doing nothing."
+ True -> printMsg "Can't save over a directory, doing nothing." >> return False
False -> do
- liftBase $ case conv of
- Nothing -> R.writeFileUsingText f contents
+ hooks <- view preSaveHooks <$> askCfg
+ sequence_ $ map runAction hooks
+ mayErr <- liftBase $ case conv of
+ Nothing -> R.writeFileUsingText f contents >> return Nothing
Just cn -> R.writeFile f contents cn
- io getCurrentTime >>= withGivenBuffer bufferKey . markSavedB
- (Nothing, _, _) -> printMsg "Buffer not associated with a file"
+ case mayErr of
+ Just err -> printMsg err >> return False
+ Nothing -> io getCurrentTime >>= withGivenBuffer bufferKey . markSavedB
+ >> return True
+ (Nothing, _, _) -> printMsg "Buffer not associated with a file" >> return False
-- | Write current buffer to disk as @f@. The file is also set to @f@.
-fwriteToE :: T.Text -> YiM ()
+fwriteToE :: T.Text -> YiM Bool
fwriteToE f = do
b <- gets currentBuffer
setFileName b (T.unpack f)
fwriteBufferE b
-- | Write all open buffers
-fwriteAllE :: YiM ()
+fwriteAllE :: YiM Bool
fwriteAllE =
do allBuffs <- gets bufferSet
let modifiedBuffers = filter (not . isUnchangedBuffer) allBuffs
- mapM_ fwriteBufferE (fmap bkey modifiedBuffers)
+ all id <$> mapM fwriteBufferE (fmap bkey modifiedBuffers)
-- | Make a backup copy of file
backupE :: FilePath -> YiM ()
diff --git a/src/library/Yi/Keymap/Emacs.hs b/src/library/Yi/Keymap/Emacs.hs
index 1e50f2c..0f11698 100644
--- a/src/library/Yi/Keymap/Emacs.hs
+++ b/src/library/Yi/Keymap/Emacs.hs
@@ -268,7 +268,7 @@ emacsKeys univArg =
, ctrlCh 'q' ?>>!
((withCurrentBuffer (readOnlyA %= not)) :: EditorM ())
, ctrlCh 's' ?>>! fwriteE
- , ctrlCh 'w' ?>>! promptFile "Write file:" fwriteToE
+ , ctrlCh 'w' ?>>! promptFile "Write file:" (void . fwriteToE)
, ctrlCh 'x' ?>>! (exchangePointAndMarkB >>
assign highlightSelectionA True)
, char 'b' ?>>! switchBufferE
diff --git a/src/library/Yi/Keymap/Emacs/Utils.hs b/src/library/Yi/Keymap/Emacs/Utils.hs
index d493d07..5033c7a 100644
--- a/src/library/Yi/Keymap/Emacs/Utils.hs
+++ b/src/library/Yi/Keymap/Emacs/Utils.hs
@@ -121,7 +121,7 @@ askIndividualSave hasQuit allBuffers@(firstBuffer : others) =
>>! closeBufferAndWindowE
-- cancel
] ++ [char 'q' ?>>! quitEditor | hasQuit])
- yesAction = do fwriteBufferE (bkey firstBuffer)
+ yesAction = do void $ fwriteBufferE (bkey firstBuffer)
withEditor closeBufferAndWindowE
continue
diff --git a/src/library/Yi/Keymap/Vim/Ex/Commands/Edit.hs b/src/library/Yi/Keymap/Vim/Ex/Commands/Edit.hs
index d735c45..4aaf623 100644
--- a/src/library/Yi/Keymap/Vim/Ex/Commands/Edit.hs
+++ b/src/library/Yi/Keymap/Vim/Ex/Commands/Edit.hs
@@ -36,7 +36,7 @@ edit tab f = Common.impureExCommand {
cmdShow = showEdit tab f
, cmdAction = YiA $ do
when tab $ withEditor newTabE
- void . editFile $ T.unpack f
+ openNewFile $ T.unpack f
, cmdComplete = (fmap . fmap)
(showEdit tab) (Common.filenameComplete f)
}
diff --git a/src/library/Yi/Keymap/Vim/Ex/Commands/Quit.hs b/src/library/Yi/Keymap/Vim/Ex/Commands/Quit.hs
index 317fa7d..5ecfe8f 100644
--- a/src/library/Yi/Keymap/Vim/Ex/Commands/Quit.hs
+++ b/src/library/Yi/Keymap/Vim/Ex/Commands/Quit.hs
@@ -96,4 +96,6 @@ quitAllE = do
<> " (add ! to override)"
saveAndQuitAllE :: YiM ()
-saveAndQuitAllE = Common.forAllBuffers fwriteBufferE >> quitEditor \ No newline at end of file
+saveAndQuitAllE = do
+ succeed <- fwriteAllE
+ when succeed $ quitEditor \ No newline at end of file
diff --git a/src/library/Yi/Keymap/Vim/Ex/Commands/Substitute.hs b/src/library/Yi/Keymap/Vim/Ex/Commands/Substitute.hs
index 4ad5fb1..3431e5d 100644
--- a/src/library/Yi/Keymap/Vim/Ex/Commands/Substitute.hs
+++ b/src/library/Yi/Keymap/Vim/Ex/Commands/Substitute.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_HADDOCK show-extensions #-}
@@ -16,7 +17,10 @@ import Data.Monoid
import qualified Data.Text as T
import qualified Text.ParserCombinators.Parsec as P
import Yi.Buffer.Adjusted hiding (Delete)
+import Yi.Editor
+import Yi.MiniBuffer
import Yi.Keymap
+import Yi.Keymap.Keys
import Yi.Keymap.Vim.Common
import qualified Yi.Keymap.Vim.Ex.Commands.Common as Common
import Yi.Keymap.Vim.Ex.Types
@@ -32,30 +36,91 @@ parse = Common.parse $ do
void $ P.char delimiter
to <- R.fromString <$> P.many (P.noneOf [delimiter])
void $ P.char delimiter
- flagChars <- P.many (P.oneOf "gi")
+ flagChars <- P.many (P.oneOf "gic")
return $! substitute from to delimiter
('g' `elem` flagChars)
('i' `elem` flagChars)
+ ('c' `elem` flagChars)
(not $ null percents)
-substitute :: R.YiString -> R.YiString -> Char -> Bool -> Bool -> Bool -> ExCommand
-substitute from to delimiter global caseInsensitive allLines = Common.pureExCommand {
+substitute :: R.YiString -> R.YiString -> Char -> Bool -> Bool -> Bool -> Bool -> ExCommand
+substitute from to delimiter global caseInsensitive confirm allLines = Common.pureExCommand {
cmdShow = (if allLines then "%" else "")
<> "substitute"
<> (delimiter `T.cons` R.toText from)
<> (delimiter `T.cons` R.toText to)
`T.snoc` delimiter
+ <> (if confirm then "c" else "")
<> (if caseInsensitive then "i" else "")
<> (if global then "g" else "")
- , cmdAction = BufferA $ do
- let regex = makeSimpleSearch from
- replace = do
- region <- regionOfB Line
- void $ searchAndRepRegion0 regex to global region
+ , cmdAction = EditorA $ do
+ regex <- if R.null from
+ then getRegexE
+ else return . Just . makeSimpleSearch $ from
+ case regex of
+ Nothing -> printMsg "No previous search pattern"
+ Just regex' -> if confirm
+ then substituteConfirm regex' to global allLines
+ else withCurrentBuffer $ do
+ let replace = void $ regionOfB Line
+ >>= searchAndRepRegion0 regex' to global
+ if allLines
+ then withEveryLineB replace
+ else replace
+ moveToSol
+ }
- if allLines
- then withEveryLineB replace
- else replace
+-- | Run substitution in confirm mode
+substituteConfirm :: SearchExp -> R.YiString -> Bool -> Bool -> EditorM ()
+substituteConfirm regex to global allLines = do
+ setRegexE regex
+ regions <- withCurrentBuffer $ findMatches regex global allLines
+ substituteMatch to 0 False regions
- moveToSol
- }
+-- | All matches to replace under given flags
+findMatches :: SearchExp -> Bool -> Bool -> BufferM [Region]
+findMatches regex global allLines = do
+ lns <- if allLines
+ then do lineCount <- lineCountB
+ lineRegions [1..lineCount]
+ else return <$> regionOfB Line
+ let f = if global then id else take 1
+ concat <$> mapM (fmap f . regexRegionB regex) lns
+
+-- | Get regions corresponding to all lines
+lineRegions :: [Int] -> BufferM [Region]
+lineRegions = mapM $ \ln -> gotoLn ln >> regionOfB Line
+
+-- | Offsets a region (to account for a region prior being modified)
+offsetRegion :: Int -> Region -> Region
+offsetRegion k reg = mkRegion (regionStart reg + k') (regionEnd reg + k')
+ where k' = fromIntegral k
+
+-- | Runs a list of matches using itself as a continuation
+substituteMatch :: R.YiString -> Int -> Bool -> [Region] -> EditorM ()
+substituteMatch _ _ _ [] = resetRegexE
+substituteMatch to co autoAll (m:ms) = do
+ let m' = offsetRegion co m
+ withCurrentBuffer . moveTo $ regionStart m'
+ len <- withCurrentBuffer $ R.length <$> readRegionB m'
+ let diff = R.length to - len
+ tex = "replace with " <> R.toText to <> " (y/n/a/q)?"
+ if autoAll
+ then do withCurrentBuffer $ replaceRegionB m' to
+ substituteMatch to (co + diff) True ms
+ else void . spawnMinibufferE tex . const $ askKeymap to co (co + diff) m ms
+
+-- | Actual choices during confirm mode.
+askKeymap :: R.YiString -> Int -> Int -> Region -> [Region] -> Keymap
+askKeymap to co co' m ms = choice [
+ char 'n' ?>>! cleanUp >> substituteMatch to co False ms
+ , char 'a' ?>>! do cleanUp
+ replace
+ substituteMatch to co' True ms
+ , char 'y' ?>>! do cleanUp
+ replace
+ substituteMatch to co' False ms
+ , char 'q' ?>>! cleanUp >> resetRegexE
+ ]
+ where cleanUp = closeBufferAndWindowE
+ replace = withCurrentBuffer $ replaceRegionB (offsetRegion co m) to
diff --git a/src/library/Yi/Keymap/Vim/Ex/Commands/Write.hs b/src/library/Yi/Keymap/Vim/Ex/Commands/Write.hs
index fac3b21..84aace7 100644
--- a/src/library/Yi/Keymap/Vim/Ex/Commands/Write.hs
+++ b/src/library/Yi/Keymap/Vim/Ex/Commands/Write.hs
@@ -53,4 +53,4 @@ writeAsCmd filename = Common.impureExCommand {
tryWriteBuffer :: BufferRef -> YiM ()
tryWriteBuffer buf = do
ns <- Common.needsSaving buf
- when ns $ fwriteBufferE buf \ No newline at end of file
+ when ns . void $ fwriteBufferE buf \ No newline at end of file
diff --git a/src/library/Yi/Keymap/Vim/ExMap.hs b/src/library/Yi/Keymap/Vim/ExMap.hs
index b14d3b2..0b58c9a 100644
--- a/src/library/Yi/Keymap/Vim/ExMap.hs
+++ b/src/library/Yi/Keymap/Vim/ExMap.hs
@@ -89,6 +89,7 @@ exitEx success = do
resetCountE
switchModeE Normal
closeBufferAndWindowE
+ withCurrentBuffer $ setVisibleSelection False
exitBinding :: VimBinding
exitBinding = VimBindingE f
diff --git a/src/library/Yi/Keymap/Vim/Motion.hs b/src/library/Yi/Keymap/Vim/Motion.hs
index 8839437..c3609a5 100644
--- a/src/library/Yi/Keymap/Vim/Motion.hs
+++ b/src/library/Yi/Keymap/Vim/Motion.hs
@@ -89,6 +89,8 @@ changeMoveStyle smod (Move s j m) = Move (smod s) j m
linewiseMotions :: [(EventString, Bool, Maybe Int -> BufferM ())]
linewiseMotions = fmap withDefaultCount
[ ("j", False, void . lineMoveRel)
+ , ("gj", False, void . lineMoveVisRel)
+ , ("gk", False, void . lineMoveVisRel . negate)
, ("k", False, void . lineMoveRel . negate)
, ("<Down>", False, void . lineMoveRel)
, ("<Up>", False, void . lineMoveRel . negate)
diff --git a/src/library/Yi/Keymap/Vim/NormalMap.hs b/src/library/Yi/Keymap/Vim/NormalMap.hs
index bfe3a21..a235f3d 100644
--- a/src/library/Yi/Keymap/Vim/NormalMap.hs
+++ b/src/library/Yi/Keymap/Vim/NormalMap.hs
@@ -22,11 +22,12 @@ import Data.Monoid
import qualified Data.Text as T
import Prelude hiding (null, lookup)
import System.Directory (doesFileExist)
+import System.FriendlyPath (expandTilda)
import Yi.Buffer.Adjusted hiding (Insert)
import Yi.Core (quitEditor, closeWindow)
import Yi.Editor
import Yi.Event
-import Yi.File (editFile, fwriteE)
+import Yi.File (openNewFile, fwriteE)
import Yi.History
import Yi.Keymap
import Yi.Keymap.Keys
@@ -392,7 +393,7 @@ searchBinding = VimBindingE (f . T.unpack . _unEv)
f _ _ = NoMatch
continueSearching :: (Direction -> Direction) -> EditorM ()
-continueSearching fdir = do
+continueSearching fdir =
getRegexE >>= \case
Just regex -> do
dir <- fdir <$> use searchDirectionA
@@ -452,12 +453,12 @@ tabTraversalBinding = VimBindingE (f . T.unpack . _unEv)
openFileUnderCursor :: Maybe (EditorM ()) -> YiM ()
openFileUnderCursor editorAction = do
fileName <- fmap R.toString . withCurrentBuffer $ readUnitB unitViWORD
- fileExists <- io $ doesFileExist fileName
- if (not fileExists) then
- withEditor . fail $ "Can't find file \"" <> fileName <> "\""
- else do
+ fileExists <- io $ doesFileExist =<< expandTilda fileName
+ if fileExists then do
maybeM withEditor editorAction
- void . editFile $ fileName
+ openNewFile $ fileName
+ else
+ withEditor . fail $ "Can't find file \"" <> fileName <> "\""
recordMacroBinding :: VimBinding
recordMacroBinding = VimBindingE (f . T.unpack . _unEv)
diff --git a/src/library/Yi/Keymap/Vim/Operator.hs b/src/library/Yi/Keymap/Vim/Operator.hs
index 737bd2a..0ac9580 100644
--- a/src/library/Yi/Keymap/Vim/Operator.hs
+++ b/src/library/Yi/Keymap/Vim/Operator.hs
@@ -108,6 +108,9 @@ opChange = VimOperator {
withCurrentBuffer $ do
point <- deleteRegionWithStyleB reg style
moveTo point
+ when (style == LineWise) $ do
+ insertB '\n'
+ leftB
switchModeE $ Insert 'c'
return Continue
}
diff --git a/src/library/Yi/Keymap/Vim/Tag.hs b/src/library/Yi/Keymap/Vim/Tag.hs
index ea8e661..947feb4 100644
--- a/src/library/Yi/Keymap/Vim/Tag.hs
+++ b/src/library/Yi/Keymap/Vim/Tag.hs
@@ -23,6 +23,7 @@ module Yi.Keymap.Vim.Tag
) where
import Control.Applicative
+import Control.Lens (view)
import Control.Monad
import Data.Binary
import Data.Default
@@ -181,7 +182,7 @@ completeVimTag s =
-- file exists.
tagsFile :: YiM (Maybe FilePath)
tagsFile = do
- fs <- withEditor getTagsFileList
+ fs <- view tagsFileList <$> askCfg
let g f' f = do
case f' of
Just _ -> return f'
diff --git a/src/library/Yi/Main.hs b/src/library/Yi/Main.hs
index 5be03c7..ed16346 100644
--- a/src/library/Yi/Main.hs
+++ b/src/library/Yi/Main.hs
@@ -133,9 +133,9 @@ getConfig shouldOpenInTabs (cfg, cfgcon) opt =
[] -> fail "The `-l' option must come after a file argument"
File filename -> if shouldOpenInTabs && not (null (startActions cfg)) then
- prependActions [YiA (void $ editFile filename), EditorA newTabE]
+ prependActions [YiA $ openNewFile filename, EditorA newTabE]
else
- prependAction (void $ editFile filename)
+ prependAction $ openNewFile filename
EditorNm emul -> case lookup (fmap toLower emul) editors of
Just modifyCfg -> return (modifyCfg cfg, cfgcon)
diff --git a/src/library/Yi/Mode/Haskell.hs b/src/library/Yi/Mode/Haskell.hs
index 12afdf7..5fd7be6 100644
--- a/src/library/Yi/Mode/Haskell.hs
+++ b/src/library/Yi/Mode/Haskell.hs
@@ -422,7 +422,7 @@ ghciSend cmd = do
-- | Load current buffer in GHCi
ghciLoadBuffer :: YiM ()
ghciLoadBuffer = do
- fwriteE
+ void $ fwriteE
f <- withCurrentBuffer (gets file)
case f of
Nothing -> error "Couldn't get buffer filename in ghciLoadBuffer"
diff --git a/src/library/Yi/PersistentState.hs b/src/library/Yi/PersistentState.hs
index e9e7e9a..e242aba 100644
--- a/src/library/Yi/PersistentState.hs
+++ b/src/library/Yi/PersistentState.hs
@@ -16,9 +16,11 @@
module Yi.PersistentState(loadPersistentState,
savePersistentState,
- maxHistoryEntries)
+ maxHistoryEntries,
+ persistentSearch)
where
+import Control.Monad
import Data.Typeable
import Data.Binary
#if __GLASGOW_HASKELL__ < 708
@@ -69,6 +71,19 @@ makeLenses ''MaxHistoryEntries
maxHistoryEntries :: Field Int
maxHistoryEntries = customVariable . unMaxHistoryEntries
+newtype PersistentSearch = PersistentSearch { _unPersistentSearch :: Bool }
+ deriving(Typeable, Binary)
+
+instance Default PersistentSearch where
+ def = PersistentSearch True
+
+instance YiConfigVariable PersistentSearch
+
+makeLenses ''PersistentSearch
+
+persistentSearch :: Field Bool
+persistentSearch = customVariable . unPersistentSearch
+
-- | Trims per-command histories to contain at most N completions each.
trimHistories :: Int -> Histories -> Histories
trimHistories maxHistory (Histories m) = Histories $ M.map trimH m
@@ -116,6 +131,8 @@ loadPersistentState = do
maybePState <- readPersistentState
case maybePState of
Nothing -> return ()
- Just pState -> do withEditor $ putEditorDyn $ histories pState
- withEditor $ assign killringA $ aKillring pState
- withEditor $ maybe (return ()) setRegexE $ aCurrentRegex pState
+ Just pState -> do putEditorDyn $ histories pState
+ assign killringA $ aKillring pState
+ PersistentSearch keepSearch <- askConfigVariableA
+ when keepSearch . withEditor $
+ maybe (return ()) setRegexE $ aCurrentRegex pState
diff --git a/src/library/Yi/Tag.hs b/src/library/Yi/Tag.hs
index 019adbd..7e69907 100644
--- a/src/library/Yi/Tag.hs
+++ b/src/library/Yi/Tag.hs
@@ -28,11 +28,11 @@ module Yi.Tag ( lookupTag
, getTags
, setTags
, resetTags
- , getTagsFileList
- , setTagsFileList
+ , tagsFileList
) where
import Control.Applicative
+import Control.Lens
import Data.Binary
import qualified Data.ByteString as BS
import qualified Data.ByteString.UTF8 as BS8
@@ -44,7 +44,6 @@ import GHC.Generics (Generic)
import Data.Default
import qualified Data.Foldable as F
import Data.List (isPrefixOf)
-import Data.List.Split (splitOn)
import Data.Map (Map, fromListWith, lookup, keys)
import Data.Maybe (mapMaybe)
import qualified Data.Text as T
@@ -54,16 +53,28 @@ import Data.Typeable
import System.FilePath (takeFileName, takeDirectory, (</>))
import System.FriendlyPath
import Yi.Editor
-import Yi.Types (YiVariable)
+import Yi.Config.Simple.Types (Field, customVariable)
+import Yi.Types (YiVariable, YiConfigVariable)
+newtype TagsFileList = TagsFileList { _unTagsFileList :: [FilePath] }
+ deriving Typeable
+
+instance Default TagsFileList where
+ def = TagsFileList ["tags"]
+
+instance YiConfigVariable TagsFileList
+
+makeLenses ''TagsFileList
+
+tagsFileList :: Field [FilePath]
+tagsFileList = customVariable . unTagsFileList
newtype Tags = Tags (Maybe TagTable) deriving Typeable
+
instance Default Tags where
def = Tags Nothing
-newtype TagsFileList = TagsFileList [FilePath] deriving Typeable
-instance Default TagsFileList where
- def = TagsFileList ["tags"]
+instance YiVariable Tags
newtype Tag = Tag { _unTag :: T.Text } deriving (Show, Eq, Ord)
@@ -151,16 +162,6 @@ getTags = do
Tags t <- getEditorDyn
return t
-setTagsFileList :: String -> EditorM ()
-setTagsFileList fps = do
- resetTags
- putEditorDyn $ TagsFileList (splitOn "," fps)
-
-getTagsFileList :: EditorM [FilePath]
-getTagsFileList = do
- TagsFileList fps <- getEditorDyn
- return fps
-
#if __GLASGOW_HASKELL__ < 708
$(derive makeBinary ''Tags)
$(derive makeBinary ''TagTable)
@@ -173,7 +174,3 @@ instance Binary Tags
instance Binary TagTable
instance Binary TagsFileList
#endif
-
-instance YiVariable Tags
-
-instance YiVariable TagsFileList
diff --git a/src/library/Yi/Types.hs b/src/library/Yi/Types.hs
index 348ca1b..e2cdce7 100644
--- a/src/library/Yi/Types.hs
+++ b/src/library/Yi/Types.hs
@@ -213,6 +213,7 @@ data Attributes = Attributes
, undos :: !URList -- ^ undo/redo list
, bufferDynamic :: !DynamicState.DynamicState -- ^ dynamic components
, preferCol :: !(Maybe Int) -- ^ prefered column to arrive at when we do a lineDown / lineUp
+ , preferVisCol :: !(Maybe Int) -- ^ prefered column to arrive at visually (ie, respecting wrap)
, pendingUpdates :: ![UIUpdate] -- ^ updates that haven't been synched in the UI yet
, selectionStyle :: !SelectionStyle
, keymapProcess :: !KeymapProcess
@@ -233,15 +234,15 @@ data Attributes = Attributes
instance Binary Yi.Types.Attributes where
- put (Yi.Types.Attributes n b u bd pc pu selectionStyle_
+ put (Yi.Types.Attributes n b u bd pc pv pu selectionStyle_
_proc wm law lst ro ins _dc _pfw isTransacPresent transacAccum fv cn) = do
let putTime (UTCTime x y) = B.put (fromEnum x) >> B.put (fromEnum y)
B.put n >> B.put b >> B.put u >> B.put bd
- B.put pc >> B.put pu >> B.put selectionStyle_ >> B.put wm
+ B.put pc >> B.put pv >> B.put pu >> B.put selectionStyle_ >> B.put wm
B.put law >> putTime lst >> B.put ro >> B.put ins >> B.put _dc
B.put isTransacPresent >> B.put transacAccum >> B.put fv >> B.put cn
get = Yi.Types.Attributes <$> B.get <*> B.get <*> B.get <*>
- B.get <*> B.get <*> B.get <*> B.get <*> pure I.End <*> B.get <*> B.get
+ B.get <*> B.get <*> B.get <*> B.get <*> B.get <*> pure I.End <*> B.get <*> B.get
<*> getTime <*> B.get <*> B.get <*> B.get
<*> pure (const False) <*> B.get <*> B.get <*> B.get <*> B.get
where
diff --git a/src/library/Yi/UI/Pango.hs b/src/library/Yi/UI/Pango.hs
index da7f90a..9599801 100644
--- a/src/library/Yi/UI/Pango.hs
+++ b/src/library/Yi/UI/Pango.hs
@@ -597,7 +597,7 @@ getDimensionsInTab ui f e tab = do
let metrics = winMetrics wi
lineHeight = ascent metrics + descent metrics
charWidth = max (approximateCharWidth metrics) (approximateDigitWidth metrics)
- width = round $ fromIntegral wid / charWidth
+ width = round $ fromIntegral wid / charWidth - 1
height = round $ fromIntegral h / lineHeight
b0 = findBufferWith (bufkey win) e
rgn <- shownRegion ui f wi b0
diff --git a/src/library/Yi/UI/SimpleLayout.hs b/src/library/Yi/UI/SimpleLayout.hs
index af84bba..ca71bed 100644
--- a/src/library/Yi/UI/SimpleLayout.hs
+++ b/src/library/Yi/UI/SimpleLayout.hs
@@ -125,22 +125,28 @@ layoutWindow win e w h = win
dispLnCount = h' - wrapCount
-coordsOfCharacterB :: Size2D -> Point -> Point
- -> BufferM (Maybe Point2D)
+coordsOfCharacterB :: Size2D -> Point -> Point -> BufferM (Maybe Point2D)
coordsOfCharacterB _ topLeft char | topLeft > char = return Nothing
coordsOfCharacterB (Size2D w h) (Point topLeft) (Point char)
| char - topLeft >= w * h = return Nothing
coordsOfCharacterB (Size2D w h) (Point topLeft) (Point char) = savingPointB $ do
ts <- fmap tabSize indentSettingsB
text <- fmap (R.toString . R.take (w * h)) (streamB Forward (Point topLeft))
- let go !x !y n t | x >= w = go (x - w) (y + 1) n t
- go _ !y _ _ | y >= h = Nothing
+ let go _ !y _ _ | y >= h = Nothing
go !x !y 0 _ = Just (Point2D x y)
- go !x !y !n (c : t) =
- case c of
- '\t' -> go (x + ts) y (n - 1) t
- '\n' -> go 0 (y + 1) (n - 1) t
- _ -> go (x + 1) y (n - 1) t
+ go !x !y !n (c : d : t) =
+ case (c, d, (compare x wOffset)) of
+ ('\t', _ , _) -> go (x + ts) y (n - 1) (d:t)
+ ('\n', _ , _) -> go 0 (y + 1) (n - 1) (d:t)
+ ( _ ,'\n',EQ) -> go x y (n - 1) (d:t)
+ ( _ , _ ,EQ) -> go (x - wOffset) (y + 1) (n - 1) (d:t)
+ ( _ , _ , _) -> go (x + 1) y (n - 1) (d:t)
+ where wOffset = w - 1
+ go !x !y !n (c : []) =
+ case (c, (compare x wOffset)) of
+ ('\n', _) -> go 0 (y + 1) (n - 1) [c]
+ ( _ , _) -> go (x + 1) y (n - 1) [c]
+ where wOffset = w - 1
go !x !y _ _ = Just (Point2D x y)
return (go 0 0 (char - topLeft) text)
diff --git a/src/library/Yi/UI/Vty.hs b/src/library/Yi/UI/Vty.hs
index 03dc556..97460ab 100644
--- a/src/library/Yi/UI/Vty.hs
+++ b/src/library/Yi/UI/Vty.hs
@@ -232,7 +232,7 @@ renderWindow cfg e (SL.Rect x y w h) (win, focused) =
point))
rendered =
- drawText h' w
+ drawText wsty h' w
tabWidth
([(c, wsty) | c <- T.unpack prompt] ++ bufData ++ [(' ', wsty)])
-- we always add one character which can be used to position the cursor at the end of file
@@ -272,19 +272,20 @@ stys sty [] cs = [ sty | _ <- cs ]
stys sty ((endPos, sty') : xs) cs = [ sty | _ <- previous ] <> stys sty' xs later
where (previous, later) = break ((endPos <=) . fst) cs
-drawText :: Int -- ^ The height of the part of the window we are in
+drawText :: Vty.Attr -- ^ "Ground" attribute.
+ -> Int -- ^ The height of the part of the window we are in
-> Int -- ^ The width of the part of the window we are in
-> Int -- ^ The number of spaces to represent a tab character with.
-> [(Char, Vty.Attr)] -- ^ The data to draw.
-> [Vty.Image]
-drawText h w tabWidth bufData
+drawText wsty h w tabWidth bufData
| h == 0 || w == 0 = []
| otherwise = renderedLines
where
-- the number of lines that taking wrapping into account,
-- we use this to calculate the number of lines displayed.
- wrapped = concatMap (wrapLine w) $ map (concatMap expandGraphic) $ take h $ lines' bufData
+ wrapped = concatMap (wrapLine w) $ map addSpace $ map (concatMap expandGraphic) $ take h $ lines' bufData
lns0 = take h wrapped
-- fill lines with blanks, so the selection looks ok.
@@ -298,15 +299,24 @@ drawText h w tabWidth bufData
Vty.charFill a ' ' (w - length l) 1
where (_, a) = last l
+
+ addSpace :: [(Char, Vty.Attr)] -> [(Char, Vty.Attr)]
+ addSpace [] = [(' ', wsty)]
+ addSpace l = case (mod lineLength w) of
+ 0 -> l
+ _ -> l ++ [(' ', wsty)]
+ where
+ lineLength = length l
+
-- | Cut a string in lines separated by a '\n' char. Note
- -- that we add a blank character where the \n was, so the
- -- cursor can be positioned there.
+ -- that we remove the newline entirely since it is no longer
+ -- significant for drawing text.
lines' :: [(Char, a)] -> [[(Char, a)]]
lines' [] = []
lines' s = case s' of
[] -> [l]
- ((_,x):s'') -> (l++[(' ',x)]) : lines' s''
+ ((_,x):s'') -> l : lines' s''
where
(l, s') = break ((== '\n') . fst) s
@@ -316,8 +326,9 @@ drawText h w tabWidth bufData
expandGraphic ('\t', p) = replicate tabWidth (' ', p)
expandGraphic (c, p)
- | ord c < 32 = [('^', p), (chr (ord c + 64), p)]
+ | numeric < 32 = [('^', p), (chr (numeric + 64), p)]
| otherwise = [(c, p)]
+ where numeric = ord c
renderTabBar :: UIStyle -> [(T.Text, Bool)] -> Vty.Image
renderTabBar uiStyle = Vty.horizCat . fmap render
diff --git a/src/tests/vimtests/change/V3jc.test b/src/tests/vimtests/change/V3jc.test
new file mode 100644
index 0000000..d038df8
--- /dev/null
+++ b/src/tests/vimtests/change/V3jc.test
@@ -0,0 +1,15 @@
+-- Input
+(2,3)
+aaaaaa
+bbbbbb
+cccccc
+dddddd
+eeeeee
+ffffff
+-- Output
+(2,1)
+aaaaaa
+
+ffffff
+-- Events
+V3jc<Esc> \ No newline at end of file
diff --git a/src/tests/vimtests/change/cc.test b/src/tests/vimtests/change/cc.test
new file mode 100644
index 0000000..d5aad15
--- /dev/null
+++ b/src/tests/vimtests/change/cc.test
@@ -0,0 +1,12 @@
+-- Input
+(1,11)
+Lorem ipsum dolor sit amet
+abc def ghi
+qwe rty uiop
+-- Output
+(1,3)
+man
+abc def ghi
+qwe rty uiop
+-- Events
+ccman<Esc> \ No newline at end of file
diff --git a/src/tests/vimtests/insertion/O3.test b/src/tests/vimtests/insertion/O4.test
index 5440511..5440511 100644
--- a/src/tests/vimtests/insertion/O3.test
+++ b/src/tests/vimtests/insertion/O4.test
diff --git a/yi.cabal b/yi.cabal
index e13ab29..7986e9f 100644
--- a/yi.cabal
+++ b/yi.cabal
@@ -1,5 +1,5 @@
name: yi
-version: 0.11.0
+version: 0.11.1
category: Development, Editor
synopsis: The Haskell-Scriptable Editor
description:
@@ -287,7 +287,8 @@ library
word-trie >= 0.2.0.4,
yi-language >= 0.1.0.7,
oo-prototypes,
- yi-rope >= 0.6.0.0 && < 0.7
+ yi-rope >= 0.7.0.0 && < 0.8,
+ exceptions
ghc-options: -Wall -fno-warn-orphans
ghc-prof-options: -prof -auto-all -rtsopts