packages feed

yi 0.10.1 → 0.11.0

raw patch · 44 files changed

+610/−272 lines, 44 filesdep ~vtydep ~yi-rope

Dependency ranges changed: vty, yi-rope

Files

src/library/Yi/Buffer/Adjusted.hs view
@@ -82,12 +82,9 @@     (start, lengths) <- shapeOfBlockRegionB reg     moveTo start     forM_ (zip [1..] lengths) $ \(i, l) -> do-        deleteN l+        B.deleteN l         moveTo start         lineMoveRel i-    case lengths of-        [l] -> adjBlock (-l)-        _ -> return ()     return start  deleteRegionWithStyleB reg style = savingPointB $ do
src/library/Yi/Buffer/HighLevel.hs view
@@ -447,10 +447,12 @@            when eol leftB            transposeB Character Forward --- | Delete trailing whitespace from all lines+-- | Delete trailing whitespace from all lines. Uses 'savingPositionB'+-- to get back to where it was. deleteTrailingSpaceB :: BufferM () deleteTrailingSpaceB =-  regionOfB Document >>= modifyRegionB (tru . mapLines stripEnd)+  regionOfB Document >>=+  savingPositionB . modifyRegionB (tru . mapLines stripEnd)   where     -- Strips the space from the end of each line, preserving     -- newlines.@@ -865,11 +867,12 @@ sortLines = modifyExtendedSelectionB Line (onLines sort)  -- | Helper function: revert the buffer contents to its on-disk version-revertB :: YiString -> UTCTime -> BufferM ()-revertB s now = do-    r <- regionOfB Document-    replaceRegionB r s-    markSavedB now+revertB :: YiString -> Maybe R.ConverterName -> UTCTime -> BufferM ()+revertB s cn now = do+  r <- regionOfB Document+  replaceRegionB r s+  encodingConverterNameA .= cn+  markSavedB now  -- get lengths of parts covered by block region --
src/library/Yi/Buffer/Implementation.hs view
@@ -39,7 +39,6 @@   , newBI   , solPoint   , solPoint'-  , eolPoint   , eolPoint'   , charsFromSolBI   , regexRegionBI@@ -347,22 +346,28 @@ -- | Point that's at EOL. Notably, this puts you right before the -- newline character if one exists, and right at the end of the text -- if one does not.-eolPoint :: Int -- ^ Line for which to grab EOL for-         -> BufferImpl syntax -> Point-eolPoint l = Point . checkEol . fst . R.splitAtLine l . mem+eolPoint' :: Point+             -- ^ Point from which we take the line to find the EOL of+          -> BufferImpl syntax+          -> Point+eolPoint' p@(Point ofs) fb = Point . checkEol . fst . R.splitAtLine ln $ mem fb   where-    -- In case we're somewhere without trailing newline, we need to stay where we are-    checkEol t = let l' = R.length t in case R.last t of-      Just '\n' -> l' - 1-      _ -> l'+    ln = lineAt p fb+    -- In case we're somewhere without trailing newline, we need to+    -- stay where we are+    checkEol t =+      let l' = R.length t+      in case R.last t of+          -- We're looking at EOL and we weren't asking for EOL past+          -- this point, so back up one for good visual effect+          Just '\n' | l' > ofs -> l' - 1+          -- We asked for EOL past the last newline so just go to the+          -- very end of content+          _ -> l'  -- | Get begining of the line relatively to @point@. solPoint' :: Point -> BufferImpl syntax -> Point solPoint' point fb = solPoint (lineAt point fb) fb---- | Get end of the line relative to the point.-eolPoint' :: Point -> BufferImpl s -> Point-eolPoint' p fb = eolPoint (lineAt p fb) fb  charsFromSolBI :: Point -> BufferImpl syntax -> YiString charsFromSolBI pnt fb = nelemsBI (fromIntegral $ pnt - sol) sol fb
src/library/Yi/Buffer/Misc.hs view
@@ -107,6 +107,7 @@   , delOverlayLayerB   , savingExcursionB   , savingPointB+  , savingPositionB   , pendingUpdatesA   , highlightSelectionA   , rectangleSelectionA@@ -178,6 +179,8 @@   , decreaseFontSize   , increaseFontSize   , indentSettingsB+  , fontsizeVariationA+  , encodingConverterNameA   ) where  import           Control.Applicative@@ -337,6 +340,9 @@     ro <-use readOnlyA     modeNm <- gets (withMode0 modeName)     unchanged <- gets isUnchangedBuffer+    enc <- use encodingConverterNameA >>= return . \case+      Nothing -> mempty+      Just cn -> T.pack $ R.unCn cn     let pct           | pos == 0 || s == 0 = " Top"           | pos == s = " Bot"@@ -348,7 +354,7 @@         toT = T.pack . show      nm <- gets $ shortIdentString (length prefix)-    return $ T.concat [ readOnly', changed, " ", nm+    return $ T.concat [ enc, " ", readOnly', changed, " ", nm                       , "     ", hexChar, "  "                       , "L", T.justifyRight 5 ' ' (toT ln)                       , "  "@@ -560,6 +566,7 @@             , updateTransactionInFlight = False             , updateTransactionAccum = []             , fontsizeVariation = 0+            , encodingConverterName = Nothing             } }  epoch :: UTCTime@@ -595,7 +602,12 @@ moveTo :: Point -> BufferM () moveTo x = do   forgetPreferCol-  (.= x) . markPointA =<< getInsMark+  maxP <- sizeB+  let p = case () of+        _ | x < 0 -> Point 0+          | x > maxP -> maxP+          | otherwise -> x+  (.= p) . markPointA =<< getInsMark  ------------------------------------------------------------------------ @@ -1024,12 +1036,27 @@   getter b = markPoint $ getMarkValueRaw mark b   setter b pos = modifyMarkRaw mark (\v -> v {markPoint = pos}) b --- | perform an @BufferM a@, and return to the current point+-- | Perform an @BufferM a@, and return to the current point. savingPointB :: BufferM a -> BufferM a savingPointB f = savingPrefCol $ do   p <- pointB   res <- f   moveTo p+  return res++-- | Perform an @BufferM a@, and return to the current line and column+-- number. The difference between this and 'savingPointB' is that here+-- we attempt to return to the specific line and column number, rather+-- than a specific number of characters from the beginning of the+-- buffer.+--+-- In case the column is further away than EOL, the point is left at+-- EOL: 'moveToLineColB' is used internally.+savingPositionB :: BufferM a -> BufferM a+savingPositionB f = savingPrefCol $ do+  (c, l) <- (,) <$> curCol <*> curLn+  res <- f+  moveToLineColB l c   return res  pointAt :: BufferM a -> BufferM Point
src/library/Yi/Buffer/TextUnit.hs view
@@ -314,9 +314,9 @@ genMoveB Document _ Backward = moveTo 0 -- impossible to go outside beginning of doc. genMoveB Character _ Forward  = rightB genMoveB Character _ Backward = leftB-genMoveB VLine     _ Forward  =-  do ofs <- lineMoveRel 1-     when (ofs < 1) (maybeMoveB Line Forward)+genMoveB VLine     _ Forward  = do+  ofs <- lineMoveRel 1+  when (ofs < 1) (maybeMoveB Line Forward) genMoveB VLine _ Backward = lineUp genMoveB unit (boundDir, boundSide) moveDir =   doUntilB_ (genAtBoundaryB unit boundDir boundSide) (moveB Character moveDir)
src/library/Yi/Command.hs view
@@ -108,11 +108,16 @@ cabalRun :: T.Text -> (Either SomeException ExitCode -> YiM x) -> CommandArguments -> YiM () cabalRun cmd onExit (CommandArguments args) = buildRun "cabal" (cmd:args) onExit +makeRun :: (Either SomeException ExitCode -> YiM x) -> CommandArguments -> YiM ()+makeRun onExit (CommandArguments args) = buildRun "make" args onExit+ ----------------------- -- | cabal-build cabalBuildE :: CommandArguments -> YiM () cabalBuildE = cabalRun "build" (const $ return ()) +makeBuildE :: CommandArguments -> YiM ()+makeBuildE = makeRun (const $ return ())  shell :: YiM BufferRef shell = do
src/library/Yi/Core.hs view
@@ -30,6 +30,7 @@   -- * Global editor actions   , errorEditor         -- :: String -> YiM ()   , closeWindow         -- :: YiM ()+  , closeWindowEmacs    -- * Interacting with external commands   , runProcessWithInput          -- :: String -> String -> YiM String@@ -88,7 +89,7 @@ import           Yi.Style (errorStyle, strongHintStyle) import qualified Yi.UI.Common as UI import           Yi.Utils-import           Yi.Window (dummyWindow, bufkey, wkey, winRegion)+import           Yi.Window (dummyWindow, bufkey, wkey, winRegion, isMini) import           Yi.PersistentState (loadPersistentState, savePersistentState)  -- | Make an action suitable for an interactive run.@@ -97,9 +98,9 @@ interactive isRefreshNeeded action = do   evs <- withEditor $ use pendingEventsA   logPutStrLn $ ">>> interactively" <> showEvs evs-  withEditor $ (%=) buffersA (fmap $  undosA %~ addChangeU InteractivePoint)+  withEditor $ buffersA %= (fmap $ undosA %~ addChangeU InteractivePoint)   mapM_ runAction action-  withEditor $ (%=) killringA krEndCmd+  withEditor $ killringA %= krEndCmd   when (isRefreshNeeded == MustRefresh) refreshEditor   logPutStrLn "<<<"   return ()@@ -278,34 +279,39 @@ -- FIXME: since we do IO here we must catch exceptions! checkFileChanges :: Editor -> IO Editor checkFileChanges e0 = do-        now <- getCurrentTime-        -- Find out if any file was modified "behind our back" by-        -- other processes.-        newBuffers <- forM (buffers e0) $ \b ->-          let nothing = return (b, Nothing)-          in if bkey b `elem` visibleBuffers-          then-            case b ^.identA of-               FileBuffer fname -> do-                  fe <- doesFileExist fname-                  if not fe then nothing else do-                  modTime <- fileModTime fname-                  if b ^. lastSyncTimeA < modTime-                     then if isUnchangedBuffer b-                       then do newContents <- R.readFile fname-                               return (snd $ runBuffer (dummyWindow $ bkey b) b (revertB newContents now), Just msg1)-                       else return (b, Just msg2)-                     else nothing-               _ -> nothing-          else nothing-        -- show appropriate update message if applicable-        return $ case getFirst (foldMap (First . snd) newBuffers) of-               Just msg -> (statusLinesA %~ DelayList.insert msg) e0 {buffers = fmap fst newBuffers}-               Nothing -> e0-    where msg1 = (1, (["File was changed by a concurrent process, reloaded!"], strongHintStyle))-          msg2 = (1, (["Disk version changed by a concurrent process"], strongHintStyle))-          visibleBuffers = fmap bufkey $ windows e0-          fileModTime f = posixSecondsToUTCTime . realToFrac . modificationTime <$> getFileStatus f+  now <- getCurrentTime+  -- Find out if any file was modified "behind our back" by+  -- other processes.+  newBuffers <- forM (buffers e0) $ \b ->+    let nothing = return (b, Nothing)+    in if bkey b `elem` visibleBuffers+    then+      case b ^. identA of+         FileBuffer fname -> do+            fe <- doesFileExist fname+            if not fe then nothing else do+            modTime <- fileModTime fname+            if b ^. lastSyncTimeA < modTime+               then if isUnchangedBuffer b+                 then R.readFile fname >>= return . \case+                        Left m ->+                          (runDummy b (readOnlyA .= True), Just $ msg3 m)+                        Right (newContents, c) ->+                          (runDummy b (revertB newContents (Just c) now), Just msg1)+                 else return (b, Just msg2)+               else nothing+         _ -> nothing+    else nothing+  -- show appropriate update message if applicable+  return $ case getFirst (foldMap (First . snd) newBuffers) of+         Just msg -> (statusLinesA %~ DelayList.insert msg) e0 {buffers = fmap fst newBuffers}+         Nothing -> e0+  where msg1 = (1, (["File was changed by a concurrent process, reloaded!"], strongHintStyle))+        msg2 = (1, (["Disk version changed by a concurrent process"], strongHintStyle))+        msg3 x = (1, (["File changed on disk to unknown encoding, not updating buffer: " <> x], strongHintStyle))+        visibleBuffers = fmap bufkey $ windows e0+        fileModTime f = posixSecondsToUTCTime . realToFrac . modificationTime <$> getFileStatus f+        runDummy b act = snd $ runBuffer (dummyWindow $ bkey b) b act  -- | Hide selection, clear "syntax dirty" flag (as appropriate). clearAllSyntaxAndHideSelection :: Editor -> Editor@@ -412,6 +418,23 @@     tabCount <- withEditor $ uses tabsA PL.length     when (winCount == 1 && tabCount == 1) quitEditor     withEditor tryCloseE++-- | This is a like 'closeWindow' but with emacs behaviour of C-x 0:+-- if we're trying to close the minibuffer or last buffer in the+-- editor, then just print a message warning the user about it rather+-- closing mini or quitting editor.+closeWindowEmacs :: YiM ()+closeWindowEmacs = do+  wins <- withEditor $ use windowsA+  let winCount = PL.length wins+  tabCount <- withEditor $ uses tabsA PL.length++  case () of+   _ | winCount == 1 && tabCount == 1 ->+         printMsg "Attempt to delete sole ordinary window"+     | isMini (PL._focus wins) ->+         printMsg "Attempt to delete the minibuffer"+     | otherwise -> withEditor tryCloseE  onYiVar :: (Yi -> YiVar -> IO (YiVar, a)) -> YiM a onYiVar f = do
src/library/Yi/Dired.hs view
@@ -195,7 +195,10 @@ -- -- @Yi.File@ module re-exports this, you probably want to import that -- instead.-editFile :: FilePath -> YiM BufferRef+--+-- In case of a decoding failure, failure message is returned instead+-- of the 'BufferRef'.+editFile :: FilePath -> YiM (Either T.Text BufferRef) editFile filename = do     f <- io $ userToCanonPath filename @@ -206,27 +209,34 @@      b <- case dupBufs of       [] -> if dirExists-               then diredDirBuffer f-               else setupMode f =<< if fileExists-                                       then fileToNewBuffer f-                                       else newEmptyBuffer f-      (h:_) -> return $ bkey h+            then Right <$> diredDirBuffer f+            else do+              nb <- if fileExists+                    then fileToNewBuffer f+                    else Right <$> newEmptyBuffer f+              case nb of+                Left m -> return $ Left m+                Right buf -> Right <$> setupMode f buf -    withEditor $ switchToBufferE b >> addJumpHereE-    return b-  where-    fileToNewBuffer :: FilePath -> YiM BufferRef-    fileToNewBuffer f = do-      now <- io getCurrentTime-      contents <- io $ R.readFile f-      permissions <- io $ getPermissions f+      (h:_) -> return . Right $ bkey h -      b <- stringToNewBuffer (FileBuffer f) contents-      withGivenBuffer b $ markSavedB now+    case b of+     Left m -> return $ Left m+     Right bf -> withEditor (switchToBufferE bf >> addJumpHereE) >> return b+  where+    fileToNewBuffer :: FilePath -> YiM (Either T.Text BufferRef)+    fileToNewBuffer f = io getCurrentTime >>= \n -> io (R.readFile f) >>= \case+      Left m -> return $ Left m+      Right (contents, conv) -> do+        permissions <- io $ getPermissions f -      unless (writable permissions) (withGivenBuffer b $ assign readOnlyA True)+        b <- stringToNewBuffer (FileBuffer f) contents+        withGivenBuffer b $ do+          encodingConverterNameA .= Just conv+          markSavedB n+          unless (writable permissions) (readOnlyA .= True) -      return b+        return $ Right b      newEmptyBuffer :: FilePath -> YiM BufferRef     newEmptyBuffer f =@@ -896,7 +906,7 @@       diredRefresh       printMsg $ showT (st ^. diredOpSucCnt) <> " of "                   <> showT total <> " item(s) moved."-    showNothing _ = (withEditor . printMsg) "Quit"+    showNothing _ = printMsg "Quit"     total = length fs  -- | copy selected files in a given directory to the target location given
src/library/Yi/Editor.hs view
@@ -133,9 +133,6 @@ import           Yi.Utils hiding ((+~)) import           Yi.Window -liftEditor :: MonadEditor m => EditorM a -> m a-liftEditor = withEditor- instance Binary Editor where   put (Editor bss bs supply ts dv _sl msh kr _re _dir _ev _cwa ) =     let putNE (x :| xs) = put x >> put xs@@ -426,8 +423,8 @@   b <- case bs of          (b':_) -> return $ bkey b'          [] -> stringToNewBuffer (MemBuffer "messages") mempty-  let m = '(' `R.cons` listify (R.fromText <$> fst s) Mon.<> ", <function>)"-  withGivenBuffer b $ botB >> insertN m+  let m = listify $ R.fromText <$> fst s+  withGivenBuffer b $ botB >> insertN (m `R.snoc` '\n')  -- --------------------------------------------------------------------- -- kill-register (vim-style) interface to killring.@@ -486,7 +483,7 @@  -- | Create a new zero size window on a given buffer newZeroSizeWindow :: Bool -> BufferRef -> WindowRef -> Window-newZeroSizeWindow mini bk ref = Window mini bk [] 0 emptyRegion ref 0 Nothing+newZeroSizeWindow mini bk ref = Window mini bk [] 0 0 emptyRegion ref 0 Nothing  -- | Create a new window onto the given buffer. newWindowE :: Bool -> BufferRef -> EditorM Window
src/library/Yi/Eval.hs view
@@ -194,7 +194,7 @@ publishAction :: (YiAction a x, Show x) => String -> a -> ConfigM () publishAction s a = publishedActions %= M.insert s (makeAction a) --- Evaluator based on a fixed list of published actions. Has a few+-- | Evaluator based on a fixed list of published actions. Has a few -- differences from 'ghciEvaluator': -- -- * expressions can't be evaluated@@ -218,9 +218,8 @@         -> Int -- ^ Line to jump to.         -> Int -- ^ Column to jump to.         -> YiM ()-jumpToE filename line column = do-  _ <- editFile filename-  withCurrentBuffer $ gotoLn line >> moveXorEol column+jumpToE filename line column =+  openingNewFile filename $ gotoLn line >> moveXorEol column  -- | Regex parsing the error message format. errorRegex :: Regex
src/library/Yi/File.hs view
@@ -11,7 +11,8 @@  module Yi.File (   -- * File-based actions-  editFile,       -- :: YiM BufferRef+  editFile,+  openingNewFile,    viWrite, viWriteTo, viSafeWriteTo,   fwriteE,        -- :: YiM ()@@ -22,11 +23,13 @@   revertE,        -- :: YiM ()    -- * Helper functions-  setFileName+  setFileName,+  deservesSave  ) where  import           Control.Applicative-import           Control.Lens+import           Control.Lens hiding (act)+import           Control.Monad (void) import           Control.Monad.Base import           Data.Monoid import qualified Data.Text as T@@ -43,19 +46,33 @@ import           Yi.String import           Yi.Utils +-- | Tries to open a new buffer with 'editFile' and runs the given+-- action on the buffer handle if it succeeds.+--+-- If the 'editFile' fails, just the failure message is printed.+openingNewFile :: FilePath -> BufferM a -> YiM ()+openingNewFile fp act = editFile fp >>= \case+  Left m -> printMsg m+  Right ref -> void $ withGivenBuffer ref act+ -- | Revert to the contents of the file on disk revertE :: YiM () revertE = do   withCurrentBuffer (gets file) >>= \case     Just fp -> do       now <- io getCurrentTime-      s <- liftBase $ R.readFile fp-      withCurrentBuffer $ revertB s now-      printMsg ("Reverted from " <> showT fp)+      rf <- liftBase $ R.readFile fp >>= \case+        Left m -> print ("Can't revert: " <> m) >> return Nothing+        Right (c, cv) -> return $ Just (c, Just cv)+      case rf of+       Nothing -> return ()+       Just (s, conv) -> do+         withCurrentBuffer $ revertB s conv now+         printMsg ("Reverted from " <> showT fp)     Nothing -> printMsg "Can't revert, no file associated with buffer."  --- | Try to write a file in the manner of vi\/vim+-- | Try to write a file in the manner of vi/vim -- Need to catch any exception to avoid losing bindings viWrite :: YiM () viWrite = do@@ -96,15 +113,21 @@ -- | Write a given buffer to disk if it is associated with a file. fwriteBufferE :: BufferRef -> YiM () fwriteBufferE bufferKey = do-  nameContents <- withGivenBuffer bufferKey ((,) <$> gets file-                                                 <*> streamB Forward 0)+  nameContents <- withGivenBuffer bufferKey $ do+    fl <- gets file+    st <- streamB Forward 0+    conv <- use encodingConverterNameA+    return (fl, st, conv)+   case nameContents of-    (Just f, contents) -> io (doesDirectoryExist f) >>= \case+    (Just f, contents, conv) -> io (doesDirectoryExist f) >>= \case       True -> printMsg "Can't save over a directory, doing nothing."       False -> do-        liftBase $ R.writeFile f contents+        liftBase $ case conv of+          Nothing -> R.writeFileUsingText f contents+          Just cn -> R.writeFile f contents cn         io getCurrentTime >>= withGivenBuffer bufferKey . markSavedB-    (Nothing, _c)      -> printMsg "Buffer not associated with a file"+    (Nothing, _, _)      -> printMsg "Buffer not associated with a file"  -- | Write current buffer to disk as @f@. The file is also set to @f@. fwriteToE :: T.Text -> YiM ()@@ -130,3 +153,17 @@ setFileName b filename = do   cfn <- liftBase $ userToCanonPath filename   withGivenBuffer b $ assign identA $ FileBuffer cfn++-- | Checks if the given buffer deserves a save: whether it's a file+-- buffer and whether it's pointing at a file rather than a directory.+deservesSave :: FBuffer -> YiM Bool+deservesSave b+   | isUnchangedBuffer b = return False+   | otherwise = isFileBuffer b++-- | Is there a proper file associated with the buffer?+-- In other words, does it make sense to offer to save it?+isFileBuffer :: FBuffer -> YiM Bool+isFileBuffer b = case b ^. identA of+  MemBuffer _ -> return False+  FileBuffer fn -> not <$> liftBase (doesDirectoryExist fn)
src/library/Yi/Keymap/Emacs.hs view
@@ -35,7 +35,8 @@ import Data.Text () import Yi.Buffer import Yi.Command (shellCommandE)-import Yi.Core (closeWindow, runAction, suspendEditor, userForceRefresh, withSyntax)+import Yi.Core (closeWindowEmacs, runAction, suspendEditor,+                userForceRefresh, withSyntax) import Yi.Dired import Yi.Editor import Yi.File@@ -183,7 +184,7 @@          , ctrlCh 'c' ?>>      ctrlC           -- All The key-bindings of the form M-c where 'c' is some character.-         , metaCh ' '           ?>>! justOneSep+         , metaCh ' '           ?>>! justOneSep univArg          , metaCh 'v'           ?>>! scrollUpE univArg          , metaCh '!'           ?>>! shellCommandE          , metaCh '<'           ?>>! repeatingArg topB@@ -255,7 +256,7 @@   -- These keybindings are all preceded by a 'C-x' so for example to   -- quit the editor we do a 'C-x C-c'   ctrlX = choice [ ctrlCh 'o'    ?>>! deleteBlankLinesB-                 , char '0'      ?>>! closeWindow+                 , char '0'      ?>>! closeWindowEmacs                  , char '1'      ?>>! closeOtherE                  , char '2'      ?>>! splitE                  , char 'h'      ?>>! selectAll
src/library/Yi/Keymap/Emacs/Utils.hs view
@@ -98,18 +98,6 @@ getModifiedBuffers :: YiM [FBuffer] getModifiedBuffers = filterM deservesSave =<< gets bufferSet -deservesSave :: FBuffer -> YiM Bool-deservesSave b-   | isUnchangedBuffer b = return False-   | otherwise = isFileBuffer b---- | Is there a proper file associated with the buffer?--- In other words, does it make sense to offer to save it?-isFileBuffer :: (Functor m, MonadBase IO m) => FBuffer -> m Bool-isFileBuffer b = case b ^. identA of-  MemBuffer _ -> return False-  FileBuffer fn -> not <$> liftBase (doesDirectoryExist fn)- -------------------------------------------------- -- Takes in a list of buffers which have been identified -- as modified since their last save.@@ -266,30 +254,28 @@  -- | Finds file and runs specified action on the resulting buffer findFileAndDo :: T.Text -- ^ Prompt-              -> (BufferRef -> YiM a) -- ^ Action to run on the resulting buffer+              -> BufferM a -- ^ Action to run on the resulting buffer               -> YiM () findFileAndDo prompt act = promptFile prompt $ \filename -> do-  (withEditor . printMsg) $ "loading " <> filename-  void $ editFile (T.unpack filename) >>= act+  printMsg $ "loading " <> filename+  openingNewFile (T.unpack filename) act  -- | Open a file using the minibuffer. We have to set up some stuff to -- allow hints and auto-completion. findFile :: YiM ()-findFile = findFileAndDo "find file:" return+findFile = findFileAndDo "find file:" $ return ()  -- | Like 'findFile' but sets the resulting buffer to read-only. findFileReadOnly :: YiM ()-findFileReadOnly = findFileAndDo "find file (read only):" $ \b ->-  withGivenBuffer b (readOnlyA .= True)+findFileReadOnly = findFileAndDo "find file (read only):" $ readOnlyA .= True  -- | Open a file in a new tab using the minibuffer. findFileNewTab :: YiM () findFileNewTab = promptFile "find file (new tab): " $ \filename -> do   withEditor newTabE-  (withEditor . printMsg) $ "loading " <> filename+  printMsg $ "loading " <> filename   void . editFile $ T.unpack filename - scrollDownE :: UnivArgument -> BufferM () scrollDownE a = case a of                  Nothing -> downScreenB@@ -329,27 +315,38 @@   -- | If on separators (space, tab, unicode seps), reduce multiple--- separators to just a single separator. If we aren't looking at a separator,--- insert a single space. This kind of behaves as emacs ‘just-one-space’--- function with the argument of ‘1’ but it prefers to use the separator we're--- looking at instead of assuming a space.-justOneSep :: BufferM ()-justOneSep = readB >>= \c ->+-- separators to just a single separator (or however many given+-- through 'UniversalArgument').+--+-- If we aren't looking at a separator, insert a single space. This is+-- like emacs ‘just-one-space’ but doesn't deal with negative argument+-- case but works with other separators than just space. What counts+-- as a separator is decided by 'isAnySep' modulo @\n@ character.+--+-- Further, it will only reduce a single type of separator at once: if+-- we have hard tabs followed by spaces, we are able to reduce one and+-- not the other.+justOneSep :: UnivArgument -> BufferM ()+justOneSep u = readB >>= \c ->   pointB >>= \point -> case point of-    Point 0 -> if isAnySep c then deleteSeparators else insertB ' '+    Point 0 -> if isSep c then deleteSeparators else insertMult c     Point x ->-      if isAnySep c+      if isSep c       then deleteSeparators       else readAtB (Point $ x - 1) >>= \d ->         -- We weren't looking at separator but there might be one behind us-        if isAnySep d+        if isSep d           then moveB Character Backward >> deleteSeparators-          else insertB ' ' -- no separators, insert a space just like emacs does+          else insertMult ' ' -- no separators, insert a space just+                              -- like emacs does   where+    isSep c = c /= '\n' && isAnySep c+    insertMult c = insertN $ R.replicateChar (maybe 1 (max 1) u) c+     deleteSeparators = do       genMaybeMoveB unitSepThisLine (Backward, InsideBound) Backward       moveB Character Forward-      doIfCharB isAnySep $ deleteB unitSepThisLine Forward+      doIfCharB isSep $ deleteB unitSepThisLine Forward   @@ -358,7 +355,7 @@ joinLinesE Nothing = return () joinLinesE (Just _) = do   moveB VLine Forward-  moveToSol >> transformB (const " ") Character Backward >> justOneSep+  moveToSol >> transformB (const " ") Character Backward >> justOneSep Nothing  -- | Shortcut to use a default list when a blank list is given. -- Used for default values to emacs queries@@ -394,11 +391,8 @@ gotoTag tag =     visitTagTable $ \tagTable ->         case lookupTag tag tagTable of-          Nothing -> fail $ "No tags containing " ++ unTag' tag-          Just (filename, line) -> do-            void $ editFile filename-            void $ withCurrentBuffer $ gotoLn line-            return ()+          [] -> printMsg $ "No tags containing " <> _unTag tag+          (filename, line):_ -> openingNewFile filename $ gotoLn line  -- | Call continuation @act@ with the TagTable. Uses the global table -- and prompts the user if it doesn't exist@@ -425,7 +419,7 @@     t <- withCurrentBuffer $ getRectangle >>= \(reg, _, _) -> readRegionB reg     let nls = R.countNewLines t     return (if nls == 0 then 1 else nls, length $ R.words t, R.length t)-  (withEditor . printMsg) $ T.unwords [ "Region has", showT l, p l "line" <> ","+  printMsg $ T.unwords [ "Region has", showT l, p l "line" <> ","                         , showT w, p w "word" <> ", and"                         , showT c, p w "character" <> "."                         ]
src/library/Yi/Keymap/Vim/Ex.hs view
@@ -24,10 +24,12 @@ import qualified Yi.Keymap.Vim.Ex.Commands.Edit as Edit import qualified Yi.Keymap.Vim.Ex.Commands.Global as Global import qualified Yi.Keymap.Vim.Ex.Commands.GotoLine as GotoLine+import qualified Yi.Keymap.Vim.Ex.Commands.Make as Make import qualified Yi.Keymap.Vim.Ex.Commands.Nohl as Nohl import qualified Yi.Keymap.Vim.Ex.Commands.Paste as Paste import qualified Yi.Keymap.Vim.Ex.Commands.Quit as Quit import qualified Yi.Keymap.Vim.Ex.Commands.Reload as Reload+import qualified Yi.Keymap.Vim.Ex.Commands.Shell as Shell import qualified Yi.Keymap.Vim.Ex.Commands.Substitute as Substitute import qualified Yi.Keymap.Vim.Ex.Commands.Tag as Tag import qualified Yi.Keymap.Vim.Ex.Commands.Write as Write@@ -45,11 +47,13 @@     , Edit.parse     , Global.parse     , GotoLine.parse+    , Make.parse     , Nohl.parse     , Paste.parse     , Quit.parse     , Reload.parse     , Substitute.parse+    , Shell.parse     , Tag.parse     , Write.parse     , Yi.parse
src/library/Yi/Keymap/Vim/Ex/Commands/Cabal.hs view
@@ -27,7 +27,7 @@ parse :: EventString -> Maybe ExCommand parse = Common.parse $ do     void $ P.try (P.string "cabal build") <|> P.try (P.string "cabal")-    args <- map T.pack <$> P.many (P.many1 P.space *> P.many1 P.anyChar)+    args <- Common.commandArgs     return $ Common.impureExCommand {         cmdShow = T.pack "cabal build"       , cmdAction = YiA $ cabalBuildE $ CommandArguments args
src/library/Yi/Keymap/Vim/Ex/Commands/Common.hs view
@@ -23,6 +23,8 @@     , pureExCommand     , impureExCommand     , errorNoWrite+    , commandArgs+    , needsSaving     ) where  import           Control.Applicative@@ -35,6 +37,7 @@ import           Text.Read (readMaybe) import           Yi.Buffer import           Yi.Editor+import           Yi.File import           Yi.Keymap import           Yi.Keymap.Vim.Common import           Yi.Keymap.Vim.Ex.Types@@ -130,7 +133,7 @@     -- actual file is in the second buffer in bufferStack     gets bufferStack >>= \case       _ :| [] -> do-        withEditor $ printMsg "filenameComplete: Expected to see minibuffer!"+        printMsg "filenameComplete: Expected to see minibuffer!"         return []       _ :| bufferRef : _ -> do         currentFileName <- fmap T.pack . withGivenBuffer bufferRef $@@ -173,3 +176,35 @@ -- | Show the common error message about an unsaved file on the status line. errorNoWrite :: EditorM () errorNoWrite = errorEditor "No write since last change (add ! to override)"++-- | Useful parser for any Ex command that acts kind of like a shell+commandArgs :: P.GenParser Char () [T.Text]+commandArgs = P.many commandArg++-- | Parse a single command, with a space in front+commandArg :: P.GenParser Char () T.Text+commandArg = fmap mconcat $ P.many1 P.space *> normArg++-- | Unquoted arg, allows for escaping of \, ", ', and space. Includes quoted arg+-- as a subset, because of things like aa"bbb"+normArg :: P.GenParser Char () [T.Text]+normArg = P.many1 $+        quoteArg '\"'+    <|> quoteArg '\"'+    <|> T.singleton <$> escapeChar+    <|> T.singleton <$> P.noneOf " \"\'\\"++-- | Quoted arg with char delim. Allows same escapes, but doesn't require escaping+-- of the opposite kind or space. However, it does allow escaping opposite kind like+-- normal, as well as allowing escaping of space (is this normal behavior?).+quoteArg :: Char -> P.GenParser Char () T.Text+quoteArg delim = fmap T.pack $ P.char delim +    *> (P.many1 $ P.noneOf (delim:"\\") <|> escapeChar)+    <* P.char delim++-- | Parser for a single escape character+escapeChar :: P.GenParser Char () Char+escapeChar = P.char '\\' *> P.oneOf " \"\'\\"++needsSaving :: BufferRef -> YiM Bool+needsSaving = findBuffer >=> maybe (return False) deservesSave
+ src/library/Yi/Keymap/Vim/Ex/Commands/Make.hs view
@@ -0,0 +1,28 @@+{-# OPTIONS_HADDOCK show-extensions #-}++-- |+-- Module      :  Yi.Keymap.Vim.Ex.Commands.Make+-- License     :  GPL-2+-- Maintainer  :  yi-devel@googlegroups.com+-- Stability   :  experimental+-- Portability :  portable++module Yi.Keymap.Vim.Ex.Commands.Make (parse) where++import           Control.Applicative+import qualified Data.Text as T+import qualified Text.ParserCombinators.Parsec as P+import           Yi.Command+import           Yi.Keymap+import           Yi.Keymap.Vim.Common+import qualified Yi.Keymap.Vim.Ex.Commands.Common as Common+import           Yi.Keymap.Vim.Ex.Types+import           Yi.MiniBuffer++parse :: EventString -> Maybe ExCommand+parse = Common.parse $ do+    args <- P.string "make" *> Common.commandArgs+    return $ Common.impureExCommand {+        cmdShow = T.pack "make"+      , cmdAction = YiA $ makeBuildE $ CommandArguments args+      }
src/library/Yi/Keymap/Vim/Ex/Commands/Quit.hs view
@@ -18,7 +18,7 @@ import           Control.Lens import           Control.Monad import           Data.Foldable (find)-import           Data.List.NonEmpty (NonEmpty(..))+import qualified Data.List.PointedList.Circular as PL import           Data.Monoid import qualified Data.Text as T import qualified Text.ParserCombinators.Parsec as P@@ -70,33 +70,30 @@  quitWindowE :: YiM () quitWindowE = do-    nw <- withCurrentBuffer needsAWindowB+    nw <- gets currentBuffer >>= Common.needsSaving     ws <- withEditor $ use currentWindowA >>= windowsOnBufferE . bufkey     if length ws == 1 && nw        then errorEditor "No write since last change (add ! to override)"-       else closeWindow+       else do+         winCount <- withEditor $ uses windowsA PL.length+         tabCount <- withEditor $ uses tabsA PL.length+         if winCount == 1 && tabCount == 1+            -- if its the last window, quitting will quit the editor+            then quitAllE+            else closeWindow  quitAllE :: YiM () quitAllE = do-  a :| as <- readEditor bufferStack-  let needsWindow b = (b,) <$> withEditor (withGivenBuffer b needsAWindowB)-  bs <- mapM needsWindow (a:as)+  let needsWindow b = (b,) <$> deservesSave b+  bs <- readEditor bufferSet >>= mapM needsWindow   -- Vim only shows the first modified buffer in the error.   case find snd bs of       Nothing -> quitEditor       Just (b, _) -> do-          bufferName <- withEditor $ withGivenBuffer b $ gets file+          bufferName <- withEditor $ withGivenBuffer (bkey b) $ gets file           errorEditor $ "No write since last change for buffer "                         <> showT bufferName                         <> " (add ! to override)"  saveAndQuitAllE :: YiM () saveAndQuitAllE = Common.forAllBuffers fwriteBufferE >> quitEditor--needsAWindowB :: BufferM Bool-needsAWindowB = do-  isWorthless <- gets (^. identA) >>= return . \case-    MemBuffer _ -> True-    FileBuffer _ -> False-  canClose <- gets isUnchangedBuffer-  return (not (isWorthless || canClose))
+ src/library/Yi/Keymap/Vim/Ex/Commands/Shell.hs view
@@ -0,0 +1,30 @@+{-# OPTIONS_HADDOCK show-extensions #-}++-- |+-- Module      :  Yi.Keymap.Vim.Ex.Commands.Shell+-- License     :  GPL-2+-- Maintainer  :  yi-devel@googlegroups.com+-- Stability   :  experimental+-- Portability :  portable++module Yi.Keymap.Vim.Ex.Commands.Shell (parse) where++import           Control.Applicative+import           Control.Monad+import qualified Data.Text as T+import qualified Text.ParserCombinators.Parsec as P+import           Yi.Command+import           Yi.Keymap+import           Yi.Keymap.Vim.Common+import qualified Yi.Keymap.Vim.Ex.Commands.Common as Common+import           Yi.Keymap.Vim.Ex.Types++parse :: EventString -> Maybe ExCommand+parse = Common.parse $ do+    void $ P.char '!'+    cmd <- T.pack <$> P.many1 (P.noneOf " ")+    args <- Common.commandArgs+    return $ Common.impureExCommand {+        cmdShow = T.pack "!"+      , cmdAction = YiA $ buildRun cmd args (const $ return ())+      }
src/library/Yi/Keymap/Vim/Ex/Commands/Tag.hs view
@@ -10,6 +10,7 @@  module Yi.Keymap.Vim.Ex.Commands.Tag (parse) where +import           Control.Applicative import           Control.Monad import           Data.Monoid import qualified Data.Text as T@@ -23,7 +24,12 @@  parse :: EventString -> Maybe ExCommand parse = Common.parse $ do-  void $ P.string "ta"+    void $ P.string "t"+    parseTag <|> parseNext++parseTag :: P.GenParser Char () ExCommand+parseTag = do+  void $ P.string "a"   void . P.optionMaybe $ P.string "g"   t <- P.optionMaybe $ do       void $ P.many1 P.space@@ -32,6 +38,11 @@     Nothing -> P.eof >> return (tag Nothing)     Just t' -> return $! tag (Just (Tag (T.pack t'))) +parseNext :: P.GenParser Char () ExCommand+parseNext = do+  void $ P.string "next"+  return next+ tag :: Maybe Tag -> ExCommand tag Nothing = Common.impureExCommand {     cmdShow = "tag"@@ -40,6 +51,13 @@   } tag (Just (Tag t)) = Common.impureExCommand {     cmdShow = "tag " <> t-  , cmdAction = YiA . gotoTag $ Tag t+  , cmdAction = YiA $ gotoTag (Tag t) 0 Nothing   , cmdComplete = (fmap . fmap) (mappend "tag ") $ completeVimTag t+  }++next :: ExCommand+next = Common.impureExCommand {+    cmdShow = "tnext"+  , cmdAction = YiA nextTag+  , cmdComplete = return ["tnext"]   }
src/library/Yi/Keymap/Vim/Ex/Commands/Write.hs view
@@ -15,6 +15,8 @@ import           Data.Monoid import qualified Data.Text as T import qualified Text.ParserCombinators.Parsec as P+import           Yi.Buffer+import           Yi.Editor import           Yi.File import           Yi.Keymap import           Yi.Keymap.Vim.Common@@ -23,14 +25,13 @@  parse :: EventString -> Maybe ExCommand parse = Common.parse $-               P.choice [parseWrite, parseWriteAs]+               (P.try (P.string "write") <|> P.string "w")+            *> (parseWriteAs <|> parseWrite)     where parseWrite = do-            void $ P.try ( P.string "write") <|> P.string "w"             alls <- P.many (P.try ( P.string "all") <|> P.string "a")             return $! writeCmd $ not (null alls)            parseWriteAs = do-            void $ P.try ( P.string "write") <|> P.string "w"             void $ P.many1 P.space             filename <- T.pack <$> P.many1 P.anyChar             return $! writeAsCmd filename@@ -38,7 +39,9 @@ writeCmd :: Bool -> ExCommand writeCmd allFlag = Common.impureExCommand {     cmdShow = "write" <> if allFlag then "all" else ""-  , cmdAction = YiA $ if allFlag then Common.forAllBuffers fwriteBufferE else viWrite+  , cmdAction = YiA $ if allFlag+      then Common.forAllBuffers tryWriteBuffer >> printMsg "All files written"+      else viWrite   }  writeAsCmd :: T.Text -> ExCommand@@ -46,3 +49,8 @@     cmdShow = "write " <> filename   , cmdAction = YiA $ viWriteTo filename   }++tryWriteBuffer :: BufferRef -> YiM ()+tryWriteBuffer buf = do+    ns <- Common.needsSaving buf+    when ns $ fwriteBufferE buf
src/library/Yi/Keymap/Vim/ExMap.hs view
@@ -60,7 +60,7 @@           ss -> do               let s = commonTPrefix' ss               updateCommand s-              withEditor . printMsg . T.unwords . fmap (dropToLastWordOf s) $ ss+              printMsg . T.unwords . fmap (dropToLastWordOf s) $ ss      updateCommand :: T.Text -> YiM ()     updateCommand s = do@@ -116,7 +116,7 @@ finishPrereq commandParsers cmdPred evs s =     matchFromBool . and $         [ vsMode s == Ex-        , evs == "<CR>"+        , evs `elem` ["<CR>", "<C-m>"]         , case evStringToExCommand commandParsers (vsOngoingInsertEvents s) of             Just cmd -> cmdPred cmd             _ -> False
src/library/Yi/Keymap/Vim/InsertMap.hs view
@@ -18,7 +18,8 @@ import           Data.Monoid import qualified Data.Text as T import           Prelude hiding (head)-import           Yi.Buffer.Adjusted hiding (Insert)+import qualified Yi.Buffer as B+import           Yi.Buffer.Adjusted as BA hiding (Insert) import           Yi.Editor import           Yi.Event import           Yi.Keymap.Vim.Common@@ -151,11 +152,19 @@     let allCursors = currentCursor :| secondaryCursors     marks <- withCurrentBuffer $ forM' allCursors $ \cursor -> do         moveTo cursor-        -- getMarkB $ Just $ "v_I" <> show cursor         getMarkB Nothing +    -- Using autoindenting with multiple cursors+    -- is just too broken.+    let (insertB', insertN', deleteB', bdeleteB', deleteRegionB') =+            if null secondaryCursors+            then (BA.insertB, BA.insertN, BA.deleteB,+                BA.bdeleteB, BA.deleteRegionB)+            else (B.insertB, B.insertN, B.deleteB,+                B.bdeleteB, B.deleteRegionB)+     let bufAction = case T.unpack . _unEv $ evs of-          (c:[]) -> insertB c+          (c:[]) -> insertB' c           "<CR>" -> do               isOldLineEmpty <- isCurrentLineEmptyB               shouldTrimOldLine <- isCurrentLineAllWhiteSpaceB@@ -172,18 +181,18 @@           "<Tab>" -> do               IndentSettings et _ts sw <- indentSettingsB               if et-              then insertN . R.fromString $ replicate sw ' '-              else insertB '\t'+              then insertN' . R.fromString $ replicate sw ' '+              else insertB' '\t'           "<C-t>" -> shiftIndentOfRegionB 1 =<< regionOfB Line           "<C-d>" -> shiftIndentOfRegionB (-1) =<< regionOfB Line           "<C-e>" -> insertCharWithBelowB           "<C-y>" -> insertCharWithAboveB-          "<BS>"  -> bdeleteB-          "<C-h>" -> bdeleteB-          "<Del>" -> deleteB Character Forward-          "<C-w>" -> deleteRegionB =<< regionOfPartNonEmptyB unitViWordOnLine Backward+          "<BS>"  -> bdeleteB'+          "<C-h>" -> bdeleteB'+          "<Del>" -> deleteB' Character Forward+          "<C-w>" -> deleteRegionB' =<< regionOfPartNonEmptyB unitViWordOnLine Backward           "<C-u>" -> bdeleteLineB-          "<lt>" -> insertB '<'+          "<lt>" -> insertB' '<'           evs' -> error $ "Unhandled event " <> show evs' <> " in insert mode"      updatedCursors <- withCurrentBuffer $ do
src/library/Yi/Keymap/Vim/Motion.hs view
@@ -200,6 +200,7 @@  matchGotoCharMove :: String -> MatchResult Move matchGotoCharMove (m:[]) | m `elem` "fFtT" = PartialMatch+matchGotoCharMove (m:"<lt>") | m `elem` "fFtT" = matchGotoCharMove (m:"<") matchGotoCharMove (m:c:[]) | m `elem` "fFtT" = WholeMatch $ Move style False action     where (dir, style, move) =               case m of
src/library/Yi/Keymap/Vim/NormalMap.hs view
@@ -75,7 +75,8 @@  tagJumpBinding :: VimBinding tagJumpBinding = mkBindingY Normal (Event (KASCII ']') [MCtrl], f, id)-   where f = withCurrentBuffer readCurrentWordB >>= gotoTag . Tag . R.toText+   where f = withCurrentBuffer readCurrentWordB >>= g . Tag . R.toText+         g tag = gotoTag tag 0 Nothing  tagPopBinding :: VimBinding tagPopBinding = mkBindingY Normal (Event (KASCII 't') [MCtrl], f, id)@@ -276,9 +277,9 @@       , switchMode Ex)      -- Undo-    , (char 'u', withCountOnBuffer0 undoB >> withCurrentBuffer leftOnEol, id)-    , (char 'U', withCountOnBuffer0 undoB >> withCurrentBuffer leftOnEol, id) -- TODO-    , (ctrlCh 'r', withCountOnBuffer0 redoB >> withCurrentBuffer leftOnEol, id)+    , (char 'u', withCountOnBuffer undoB >> withCurrentBuffer leftOnEol, id)+    , (char 'U', withCountOnBuffer undoB >> withCurrentBuffer leftOnEol, id) -- TODO+    , (ctrlCh 'r', withCountOnBuffer redoB >> withCurrentBuffer leftOnEol, id)      -- scrolling     ,(ctrlCh 'b', getCountE >>= withCurrentBuffer . upScreensB, id)@@ -450,7 +451,7 @@  openFileUnderCursor :: Maybe (EditorM ()) -> YiM () openFileUnderCursor editorAction = do-  fileName <- fmap R.toString . withEditor . withCurrentBuffer $ readUnitB unitViWORD+  fileName <- fmap R.toString . withCurrentBuffer $ readUnitB unitViWORD   fileExists <- io $ doesFileExist fileName   if (not fileExists) then       withEditor . fail $ "Can't find file \"" <> fileName <> "\""@@ -505,5 +506,5 @@ withCount :: EditorM () -> EditorM () withCount action = flip replicateM_ action =<< getCountE -withCountOnBuffer0 :: BufferM () -> EditorM ()-withCountOnBuffer0 action = withCount $ withCurrentBuffer action+withCountOnBuffer :: BufferM () -> EditorM ()+withCountOnBuffer action = withCount $ withCurrentBuffer action
src/library/Yi/Keymap/Vim/NormalOperatorPendingMap.hs view
@@ -112,11 +112,12 @@ escBinding :: VimBinding escBinding = mkBindingE ReplaceSingleChar Drop (spec KEsc, return (), resetCount . switchMode Normal) -data OperandParseResult = JustTextObject !CountedTextObject-                         | JustMove !CountedMove-                         | JustOperator !Int !RegionStyle -- ^ like dd and d2vd-                         | PartialOperand-                         | NoOperand+data OperandParseResult+    = JustTextObject !CountedTextObject+    | JustMove !CountedMove+    | JustOperator !Int !RegionStyle -- ^ like dd and d2vd+    | PartialOperand+    | NoOperand  parseOperand :: EventString -> String -> OperandParseResult parseOperand opChar s = parseCommand mcount styleMod opChar commandString@@ -139,6 +140,9 @@ parseCommand _ _ _ "g" = PartialOperand parseCommand n sm o s | o' == s = JustOperator (fromMaybe 1 n) (sm LineWise)   where o' = T.unpack . _unEv $ o+parseCommand n sm _ "0" =+  let m = Move Exclusive False (const moveToSol)+  in JustMove (CountedMove n (changeMoveStyle sm m)) parseCommand n sm _ s = case stringToMove . Ev $ T.pack s of   WholeMatch m -> JustMove $ CountedMove n $ changeMoveStyle sm m   PartialMatch -> PartialOperand@@ -147,16 +151,19 @@                $ changeTextObjectStyle sm to     Nothing -> NoOperand -+-- TODO: setup doctests -- Parse event string that can go after operator -- w -> (Nothing, "", "w") -- 2w -> (Just 2, "", "w") -- V2w -> (Just 2, "V", "w") -- v2V3<C-v>w -> (Just 6, "<C-v>", "w") -- vvvvvvvvvvvvvw -> (Nothing, "v", "w")+-- 0 -> (Nothing, "", "0")+-- V0 -> (Nothing, "V", "0") splitCountModifierCommand :: String -> (Maybe Int, String, String) splitCountModifierCommand = go "" Nothing [""]-    where go ds count mods (h:t) | isDigit h = go (ds <> [h]) count mods t+    where go "" Nothing mods "0" = (Nothing, head mods, "0")+          go ds count mods (h:t) | isDigit h = go (ds <> [h]) count mods t           go ds@(_:_) count mods s@(h:_) | not (isDigit h) = go [] (maybeMult count (Just (read ds))) mods s           go [] count mods (h:t) | h `elem` "vV" = go [] count ([h]:mods) t           go [] count mods s | "<C-v>" `isPrefixOf` s = go [] count ("<C-v>":mods) (drop 5 s)
src/library/Yi/Keymap/Vim/Tag.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-}@@ -16,6 +17,7 @@ module Yi.Keymap.Vim.Tag     ( completeVimTag     , gotoTag+    , nextTag     , popTag     , unpopTag     ) where@@ -30,6 +32,7 @@ import           GHC.Generics (Generic) #endif import           Data.Maybe+import           Data.Monoid import qualified Data.Text as T import           Data.Typeable import           System.Directory (doesFileExist)@@ -47,7 +50,7 @@ -- | List of tags and the file/line/char that they originate from. -- (the location that :tag or Ctrl-[ was called from). data VimTagStack = VimTagStack {-        tagStackList :: [(Tag, FilePath, Int, Int)]+        tagStackList :: [(Tag, Int, FilePath, Int, Int)]       , tagStackIndex :: Int }     deriving Typeable @@ -63,7 +66,8 @@ instance Binary VimTagStack #endif -getTagList :: EditorM [(Tag, FilePath, Int, Int)]+-- | Returns tag, tag index, filepath, line number, char number+getTagList :: EditorM [(Tag, Int, FilePath, Int, Int)] getTagList = do     VimTagStack ts _ <- getEditorDyn     return ts@@ -73,7 +77,7 @@     VimTagStack _ ti <- getEditorDyn     return ti -setTagList :: [(Tag, FilePath, Int, Int)] -> EditorM ()+setTagList :: [(Tag, Int, FilePath, Int, Int)] -> EditorM () setTagList tl =  do     t@(VimTagStack _ _) <- getEditorDyn     putEditorDyn $ t { tagStackList = tl }@@ -84,16 +88,16 @@     putEditorDyn $ t { tagStackIndex = ti }  -- | Push tag at index.-pushTagStack :: Tag -> FilePath -> Int -> Int -> EditorM ()-pushTagStack tag fp ln cn = do+pushTagStack :: Tag -> Int -> FilePath -> Int -> Int -> EditorM ()+pushTagStack tag ind fp ln cn = do     tl <- getTagList     ti <- getTagIndex-    setTagList $ (take ti tl) ++ [(tag, fp, ln, cn)]+    setTagList $ (take ti tl) ++ [(tag, ind, fp, ln, cn)]     setTagIndex $ ti + 1  -- | Get tag and decrement index (so that when a new push is done, the current -- tag is popped)-popTagStack :: EditorM (Maybe (Tag, FilePath, Int, Int))+popTagStack :: EditorM (Maybe (Tag, Int, FilePath, Int, Int)) popTagStack = do     tl <- getTagList     ti <- getTagIndex@@ -105,20 +109,32 @@  -- | Opens the file that contains @tag@. Uses the global tag table or uses -- the first valid tag file in @TagsFileList@.-gotoTag :: Tag -> YiM ()-gotoTag tag =-    void . visitTagTable $ \tagTable ->-        case lookupTag tag tagTable of-          Nothing -> errorEditor $ "tag not found: " `T.append` _unTag tag-          Just (filename, line) -> do+gotoTag :: Tag -> Int -> Maybe (FilePath, Int, Int) -> YiM ()+gotoTag tag ind ret =+    void . visitTagTable $ \tagTable -> do+        let lis = lookupTag tag tagTable+        if (length lis) <= ind+          then errorEditor $ "tag not found: " <> _unTag tag+          else do             bufinf <- withCurrentBuffer bufInfoB-            let ln = bufInfoLineNo bufinf-                cn = bufInfoColNo bufinf-                fn = bufInfoFileName bufinf-            withEditor $ pushTagStack tag fn ln cn-            void $ editFile filename-            void . withCurrentBuffer $ gotoLn line +            let (filename, line) = lis !! ind+                (fn, ln, cn) = case ret of+                   Just ret' -> ret'+                   Nothing -> (bufInfoFileName bufinf, +                               bufInfoLineNo bufinf, +                               bufInfoColNo bufinf)+            withEditor $ pushTagStack tag ind fn ln cn+            openingNewFile filename $ gotoLn line++-- | Goes to the next tag. (:tnext)+nextTag :: YiM ()+nextTag = do+    prev <- withEditor popTagStack +    case prev of+        Nothing -> errorEditor $ "tag stack empty"+        Just (tag, ind, fn, ln, cn) -> gotoTag tag (ind + 1) (Just (fn, ln, cn))+ -- | Return to location from before last tag jump. popTag :: YiM () popTag = do@@ -129,9 +145,7 @@             posloc <- withEditor popTagStack             case posloc of                 Nothing -> errorEditor "at bottom of tag stack"-                Just (_, fn, ln, cn) -> do-                    void $ editFile fn-                    void . withCurrentBuffer $ moveToLineColB ln cn+                Just (_, _, fn, ln, cn) -> openingNewFile fn $ moveToLineColB ln cn  -- | Go to next tag in the tag stack. Represents :tag without any -- specified tag.@@ -141,22 +155,23 @@   ti <- withEditor getTagIndex   if ti >= length tl     then case tl of-            [] -> errorEditor "at top of tag stack"-            _ -> errorEditor "tag stack empty"-    else let (tag, _, _, _) = tl !! ti-         in void . visitTagTable $ \tagTable ->-             case lookupTag tag tagTable of-               Nothing -> errorEditor $ "tag not found: " `T.append` _unTag tag-               Just (filename, line) -> do+            [] -> errorEditor "tag stack empty"+            _ -> errorEditor "at top of tag stack"+    else let (tag, ind, _, _, _) = tl !! ti+         in void . visitTagTable $ \tagTable -> do+             let lis =  lookupTag tag tagTable+             if (length lis) <= ind+               then errorEditor $ "tag not found: " <> _unTag tag+               else do                    bufinf <- withCurrentBuffer bufInfoB-                   let ln = bufInfoLineNo bufinf+                   let (filename, line) = lis !! ind+                       ln = bufInfoLineNo bufinf                        cn = bufInfoColNo bufinf                        fn = bufInfoFileName bufinf                        tl' = take ti tl-                               ++ (tag, fn, ln, cn):(drop (ti + 1) tl)+                               ++ (tag, ind, fn, ln, cn):(drop (ti + 1) tl)                    withEditor $ setTagList tl'-                   void $ editFile filename-                   void . withCurrentBuffer $ gotoLn line+                   openingNewFile filename $ gotoLn line  completeVimTag :: T.Text -> YiM [T.Text] completeVimTag s =
src/library/Yi/Keymap/Vim/VisualMap.hs view
@@ -25,9 +25,12 @@ import           Yi.Keymap.Vim.Operator import           Yi.Keymap.Vim.StateUtils import           Yi.Keymap.Vim.StyledRegion+import           Yi.Keymap.Vim.Tag import           Yi.Keymap.Vim.Utils import           Yi.MiniBuffer import           Yi.Monad+import qualified Yi.Rope as R+import           Yi.Tag import           Yi.Utils  defVisualMap :: [VimOperator] -> [VimBinding]@@ -36,6 +39,7 @@     ++ [chooseRegisterBinding]     ++ operatorBindings operators ++ digitBindings ++ [replaceBinding, switchEdgeBinding]     ++ [insertBinding, exBinding, shiftDBinding]+    ++ [tagJumpBinding]  escAction :: EditorM RepeatToken escAction = do@@ -241,4 +245,15 @@                   modifyStateE $ \s -> s { vsSecondaryCursors = drop 1 cursors }                   switchModeE $ Insert (head evs)                   return Continue+          f _ _ = NoMatch++tagJumpBinding :: VimBinding+tagJumpBinding = VimBindingY (f . T.unpack . _unEv)+    where f "<C-]>" (VimState { vsMode = (Visual _) })+            = WholeMatch $ do +                 tag <- Tag . R.toText <$> withCurrentBuffer+                            (regionOfSelectionB >>= readRegionB)+                 withEditor $ switchModeE Normal+                 gotoTag tag 0 Nothing+                 return Finish           f _ _ = NoMatch
src/library/Yi/Main.hs view
@@ -133,9 +133,9 @@                          []     -> fail "The `-l' option must come after a file argument"        File filename -> if shouldOpenInTabs && not (null (startActions cfg)) then-                         prependActions [YiA (editFile filename), EditorA newTabE]+                         prependActions [YiA (void $ editFile filename), EditorA newTabE]                        else-                         prependAction (editFile filename)+                         prependAction (void $ editFile filename)        EditorNm emul -> case lookup (fmap toLower emul) editors of              Just modifyCfg -> return (modifyCfg cfg, cfgcon)
src/library/Yi/Misc.hs view
@@ -196,7 +196,7 @@  -- | Shows current working directory. Also see 'cd'. pwd :: YiM ()-pwd = io getCurrentDirectory >>= withEditor . printMsg . T.pack+pwd = io getCurrentDirectory >>= printMsg . T.pack  rot13Char :: Char -> Char rot13Char = onCharLetterCode (+13)
src/library/Yi/Mode/Compilation.hs view
@@ -16,7 +16,7 @@ import           Yi.Buffer import           Yi.Core (withSyntax) import           Yi.Editor-import           Yi.File (editFile)+import           Yi.File (openingNewFile) import           Yi.Lexer.Alex (Tok(..), Posn(..)) import qualified Yi.Lexer.Compilation as Compilation import           Yi.Keymap@@ -36,6 +36,5 @@         Just t@Tok {tokT = Compilation.Report filename line col _} -> do           withCurrentBuffer . moveTo . posnOfs $ tokPosn t           shiftOtherWindow-          _ <- editFile filename-          withCurrentBuffer $ gotoLn line >> rightN col+          openingNewFile filename $ gotoLn line >> rightN col         _ -> return ()
src/library/Yi/Modes.hs view
@@ -70,11 +70,16 @@   , modeGotoDeclaration = do        currentPoint <- pointB        currentWord <- readCurrentWordB-       gotoLn 0+       currentWordBeginningPoint <- regionStart <$> regionOfB unitWord+       _ <- gotoLn 0        word <- return $ makeSimpleSearch currentWord        searchResults <- regexB Forward word        case searchResults of-           (declarationRegion : _) -> moveTo $ regionStart declarationRegion+           (declarationRegion : _) -> do+               searchPoint <- return $ regionStart declarationRegion+               if currentWordBeginningPoint /= searchPoint+               then moveTo searchPoint+               else moveTo currentPoint            [] -> moveTo currentPoint   } 
src/library/Yi/Tag.hs view
@@ -42,9 +42,10 @@ import           GHC.Generics (Generic) #endif import           Data.Default+import qualified Data.Foldable as F import           Data.List (isPrefixOf) import           Data.List.Split (splitOn)-import           Data.Map (Map, fromList, lookup, keys)+import           Data.Map (Map, fromListWith, lookup, keys) import           Data.Maybe (mapMaybe) import qualified Data.Text as T import qualified Data.Text.Encoding as E@@ -83,7 +84,7 @@                            , tagBaseDir :: FilePath                            -- ^ path to the tag file directory                            -- tags are relative to this path-                           , tagFileMap :: Map Tag (FilePath, Int)+                           , tagFileMap :: Map Tag [(FilePath, Int)]                            -- ^ map from tags to files                            , tagTrie :: Trie.Trie                            -- ^ trie to speed up tag hinting@@ -91,20 +92,20 @@  -- | Find the location of a tag using the tag table. -- Returns a full path and line number-lookupTag :: Tag -> TagTable -> Maybe (FilePath, Int)+lookupTag :: Tag -> TagTable -> [(FilePath, Int)] lookupTag tag tagTable = do-  (file, line) <- Data.Map.lookup tag $ tagFileMap tagTable+  (file, line) <- F.concat . Data.Map.lookup tag $ tagFileMap tagTable   return (tagBaseDir tagTable </> file, line)  -- | Super simple parsing CTag format 1 parsing algorithm -- TODO: support search patterns in addition to lineno-readCTags :: String -> Map Tag (FilePath, Int)+readCTags :: String -> Map Tag [(FilePath, Int)] readCTags =-    fromList . mapMaybe (parseTagLine . words) . lines+    fromListWith (++) . mapMaybe (parseTagLine . words) . lines     where parseTagLine (tag:tagfile:lineno:_) =               -- remove ctag control lines               if "!_TAG_" `isPrefixOf` tag then Nothing-              else Just (mkTag tag, (tagfile, fst . head . reads $ lineno))+              else Just (mkTag tag, [(tagfile, fst . head . reads $ lineno)])           parseTagLine _ = Nothing  -- | Read in a tag file from the system
src/library/Yi/Types.hs view
@@ -226,6 +226,7 @@                 , updateTransactionInFlight :: !Bool                 , updateTransactionAccum    :: ![Update]                 , fontsizeVariation         :: !Int+                , encodingConverterName     :: Maybe R.ConverterName                   -- ^ How many points (frontend-specific) to change                   -- the font by in this buffer                 } deriving Typeable@@ -233,16 +234,16 @@  instance Binary Yi.Types.Attributes where     put (Yi.Types.Attributes n b u bd pc pu selectionStyle_-         _proc wm law lst ro ins _dc _pfw isTransacPresent transacAccum fv) = do+         _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 law >> putTime lst >> B.put ro >> B.put ins >> B.put _dc-      B.put isTransacPresent >> B.put transacAccum >> B.put fv+      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           <*> getTime <*> B.get <*> B.get <*> B.get-          <*> pure (const False) <*> B.get <*> B.get <*> B.get+          <*> pure (const False) <*> B.get <*> B.get <*> B.get <*> B.get       where         getTime = UTCTime <$> (toEnum <$> B.get) <*> (toEnum <$> B.get) 
src/library/Yi/UI/Pango.hs view
@@ -576,29 +576,32 @@     updateCache ui e     tabs <- readIORef $ tabCache ui     f <- readIORef (uiFont ui)-    heights <- fold <$> mapM (getHeightsInTab ui f e) tabs+    dims <- fold <$> mapM (getDimensionsInTab ui f e) tabs     let e' = (tabsA %~ fmap (mapWindows updateWin)) e-        updateWin w = case M.lookup (wkey w) heights of+        updateWin w = case M.lookup (wkey w) dims of                           Nothing -> w-                          Just (h,rgn) -> w { height = h, winRegion = rgn }+                          Just (wi,h,rgn) -> w { width = wi, height = h, winRegion = rgn }      -- Don't leak references to old Windows     let forceWin x w = height w `seq` winRegion w `seq` x     return $ (foldl . tabFoldl) forceWin e' (e' ^. tabsA) -getHeightsInTab :: UI -> FontDescription -> Editor-                -> TabInfo -> IO (M.Map WindowRef (Int,Region))-getHeightsInTab ui f e tab = do+-- | Width, Height+getDimensionsInTab :: UI -> FontDescription -> Editor+                -> TabInfo -> IO (M.Map WindowRef (Int,Int,Region))+getDimensionsInTab ui f e tab = do   wCache <- readIORef (windowCache tab)   forM wCache $ \wi -> do-    (_, h) <- widgetGetSize $ textview wi+    (wid, h) <- widgetGetSize $ textview wi     win <- readIORef (coreWin wi)     let metrics = winMetrics wi         lineHeight = ascent metrics + descent metrics-    let b0 = findBufferWith (bufkey win) e+        charWidth = max (approximateCharWidth metrics) (approximateDigitWidth metrics)+        width = round $ fromIntegral wid / charWidth+        height = round $ fromIntegral h / lineHeight+        b0 = findBufferWith (bufkey win) e     rgn <- shownRegion ui f wi b0-    let ret= (round $ fromIntegral h / lineHeight, rgn)-    return ret+    return (width, height, rgn)  shownRegion :: UI -> FontDescription -> WinInfo -> FBuffer -> IO Region shownRegion ui f w b = modifyMVar (winLayoutInfo w) $ \wli -> do
src/library/Yi/UI/Pango/Control.hs view
@@ -238,28 +238,32 @@     updateCache e     cacheRef <- asks tabCache     tabs <- liftBase $ readIORef cacheRef-    heights <- concat <$> mapM (getHeightsInTab e) tabs+    dims <- concat <$> mapM (getDimensionsInTab e) tabs     let e' = (tabsA %~ fmap (mapWindows updateWin)) e-        updateWin w = case find (\(ref,_,_) -> (wkey w == ref)) heights of+        updateWin w = case find (\(ref,_,_,_) -> (wkey w == ref)) dims of                           Nothing -> w-                          Just (_,h,rgn) -> w { height = h, winRegion = rgn }-+                          Just (_, wi, h,rgn) -> w { width = wi+                                                   , height = h+                                                   , winRegion = rgn }     -- Don't leak references to old Windows     let forceWin x w = height w `seq` winRegion w `seq` x     return $ (foldl . tabFoldl) forceWin e' (e' ^. tabsA) -getHeightsInTab :: Editor -> TabInfo -> ControlM [(WindowRef,Int,Region)]-getHeightsInTab e tab = do+-- | Width, Height+getDimensionsInTab :: Editor -> TabInfo -> ControlM [(WindowRef,Int,Int,Region)]+getDimensionsInTab e tab = do   viewsRef <- asks views   vs <- liftBase $ readIORef viewsRef   foldlM (\a w ->         case Map.lookup (wkey w) vs of             Just v -> do-                (_, h) <- liftBase $ widgetGetSize $ drawArea v+                (wi, h) <- liftBase $ widgetGetSize $ drawArea v                 let lineHeight = ascent (metrics v) + descent (metrics v)-                let b0 = findBufferWith (viewFBufRef v) e+                    charWidth = Gtk.approximateCharWidth $ metrics v+                    b0 = findBufferWith (viewFBufRef v) e                 rgn <- shownRegion e v b0-                let ret= (windowRef v, round $ fromIntegral h / lineHeight, rgn)+                let ret= (windowRef v, round $ fromIntegral wi / charWidth, +                          round $ fromIntegral h / lineHeight, rgn)                 return $ a <> [ret]             Nothing -> return a)       [] (coreTab tab ^. tabWindowsA)
src/library/Yi/UI/SimpleLayout.hs view
@@ -18,6 +18,7 @@ import Control.Monad.State (evalState, get, put) import Data.Foldable import Data.List (partition)+import Data.Maybe (fromJust) import qualified Data.List.PointedList.Circular as PL import qualified Data.Map.Strict as M import Data.Monoid@@ -78,7 +79,8 @@                     heights         miniWindowsWithHeights =             fmap (\win -> layoutWindow win e colCount 1) miniWs-        Just newWindows = PL.fromList (miniWindowsWithHeights <> bigWindowsWithHeights)+        newWindows =+            merge (miniWindowsWithHeights <> bigWindowsWithHeights) (windows e)         winRects = M.fromList (bigWindowsWithRects <> miniWindowsWithRects)         bigWindowsWithRects =             zipWith (\w offset -> (wkey w, Rect 0 (offset + tabbarHeight) colCount (height w)))@@ -87,10 +89,16 @@         miniWindowsWithRects =             map (\w -> (wkey w, Rect 0 (rowCount - 1) colCount 1))                 miniWindowsWithHeights+        merge :: [Window] -> PL.PointedList Window -> PL.PointedList Window+        merge updates =+            let replace (Window { wkey = k }) = fromJust (find ((== k) . wkey) updates)+            in fmap replace + layoutWindow :: Window -> Editor -> Int -> Int -> Window layoutWindow win e w h = win     { height = h+    , width = w     , winRegion = mkRegion fromMarkPoint toMarkPoint     , actualLines = dispLnCount     }
src/library/Yi/UI/Vty.hs view
@@ -179,10 +179,12 @@                            (SL.offsetY promptRect)                            (Vty.vertCat (fmap formatCmdLine niceCmd))         cursorPos =-            case (\(w, r) -> (isMini w, cursor r)) (PL._focus windowsAndImages) of-                (False, Just (y, x)) -> Vty.Cursor (toEnum x) (toEnum y)-                (True, Just (_, x)) -> Vty.Cursor (toEnum x) (toEnum (rowCount - 1))-                (_, Nothing) -> Vty.NoCursor+            let (w, image) = PL._focus windowsAndImages+            in case (isMini w, cursor image) of+                  (False, Just (y, x)) ->+                      Vty.Cursor (toEnum x) (toEnum y)+                  (True, Just (_, x)) -> Vty.Cursor (toEnum x) (toEnum (rowCount - 1))+                  (_, Nothing) -> Vty.NoCursor     logPutStrLn "refreshing screen."     Vty.update (fsVty fs)         (Vty.picForLayers ([tabBarImage, cmdImage] ++ bigImages ++ miniImages))
src/library/Yi/Window.hs view
@@ -33,6 +33,7 @@       -- accessed one is first element     , height    :: !Int -- ^ height of the window (in number of screen                        -- lines displayed)+    , width     :: !Int -- ^ width of the window (in number of chars)     , winRegion :: !Region -- ^ view area. note that the top point is                           -- also available as a buffer mark.     , wkey      :: !WindowRef -- ^ identifier for the window (for UI sync)@@ -50,10 +51,10 @@ makeLensesWithSuffix "A" ''Window  instance Binary Window where-    put (Window mini bk bl _h _rgn key lns jl) =+    put (Window mini bk bl _w _h _rgn key lns jl) =         put mini >> put bk >> put bl >> put key >> put lns >> put jl     get = Window <$> get <*> get <*> get-                   <*> return 0 <*> return emptyRegion+                   <*> return 0 <*> return 0 <*> return emptyRegion                    <*> get <*> get <*> get  @@ -77,4 +78,4 @@  -- | Return a "fake" window onto a buffer. dummyWindow :: BufferRef -> Window-dummyWindow b = Window False b [] 0 emptyRegion def 0 Nothing+dummyWindow b = Window False b [] 0 0 emptyRegion def 0 Nothing
+ src/tests/vimtests/delete/d00.test view
@@ -0,0 +1,12 @@+-- Input+(1,6)+abc def ghi+123 456 789+lorem ipsum+-- Output+(1,1)+ef ghi+123 456 789+lorem ipsum+-- Events+d0
+ src/tests/vimtests/find/f5.test view
@@ -0,0 +1,12 @@+-- Input+(1,1)+Lorem ipsum dolor s<t amet+abc def ghi+qwe rty uiop+-- Output+(1,20)+Lorem ipsum dolor s<t amet+abc def ghi+qwe rty uiop+-- Events+f<lt>
+ src/tests/vimtests/insertion/O3.test view
@@ -0,0 +1,11 @@+-- Input+(2,1)+++-- Output+(2,1)++++-- Events+O<Esc>
+ src/tests/vimtests/insertion/o3.test view
@@ -0,0 +1,11 @@+-- Input+(2,1)+++-- Output+(3,1)++++-- Events+o<Esc>
yi.cabal view
@@ -1,5 +1,5 @@ name:           yi-version:        0.10.1+version:        0.11.0 category:       Development, Editor synopsis:       The Haskell-Scriptable Editor description:@@ -169,10 +169,12 @@     Yi.Keymap.Vim.Ex.Commands.Edit     Yi.Keymap.Vim.Ex.Commands.Global     Yi.Keymap.Vim.Ex.Commands.GotoLine+    Yi.Keymap.Vim.Ex.Commands.Make     Yi.Keymap.Vim.Ex.Commands.Nohl     Yi.Keymap.Vim.Ex.Commands.Paste     Yi.Keymap.Vim.Ex.Commands.Quit     Yi.Keymap.Vim.Ex.Commands.Reload+    Yi.Keymap.Vim.Ex.Commands.Shell     Yi.Keymap.Vim.Ex.Commands.Substitute     Yi.Keymap.Vim.Ex.Commands.Tag     Yi.Keymap.Vim.Ex.Commands.Write@@ -285,7 +287,7 @@     word-trie >= 0.2.0.4,     yi-language >= 0.1.0.7,     oo-prototypes,-    yi-rope >= 0.4.1.0+    yi-rope >= 0.6.0.0 && < 0.7    ghc-options: -Wall -fno-warn-orphans   ghc-prof-options: -prof -auto-all -rtsopts@@ -333,7 +335,7 @@       Yi.UI.Vty.Conversions     build-depends:       unix-compat >=0.1 && <0.5,-      vty >= 5.2.2 && < 6+      vty >= 5.2.4 && < 6     cpp-options: -DFRONTEND_VTY    other-modules: