packages feed

yi 0.11.0 → 0.11.1

raw patch · 30 files changed

+406/−130 lines, 30 filesdep +exceptionsdep ~yi-rope

Dependencies added: exceptions

Dependency ranges changed: yi-rope

Files

src/library/Yi/Buffer/HighLevel.hs view
@@ -56,6 +56,7 @@     , lastNonSpaceB     , leftEdgesOfRegionB     , leftOnEol+    , lineMoveVisRel     , linePrefixSelectionB     , lineStreamB     , lowercaseWordB@@ -1152,3 +1153,39 @@     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
src/library/Yi/Buffer/Misc.hs view
@@ -100,6 +100,7 @@   , savingPrefCol   , forgetPreferCol   , movingToPrefCol+  , movingToPrefVisCol   , preferColA   , markSavedB   , addOverlayB@@ -552,6 +553,7 @@             , bkey__ = unique             , undos  = emptyU             , preferCol = Nothing+            , preferVisCol = Nothing             , bufferDynamic = mempty             , pendingUpdates = []             , selectionStyle = SelectionStyle False False@@ -855,6 +857,18 @@   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 @@       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 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@@ -973,6 +996,10 @@ -- (This takes into account tabs, unicode chars, etc.) 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
src/library/Yi/Buffer/TextUnit.hs view
@@ -98,10 +98,18 @@ 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 == '_'
src/library/Yi/Editor.hs view
@@ -134,10 +134,10 @@ 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 @@     dv <- get     msh <- get     kr <- get+    re <- get     return $ emptyEditor { bufferStack = bss                          , buffers = bs                          , refSupply = supply@@ -153,6 +154,7 @@                          , dynamic = dv                          , maxStatusHeight = msh                          , killring = kr+                         , currentRegex = re                          }  -- | The initial state
src/library/Yi/Eval.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleContexts #-} {-# OPTIONS_HADDOCK show-extensions #-}  -- |@@ -33,8 +34,12 @@ ) 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.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 @@     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 @@     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
src/library/Yi/File.hs view
@@ -1,5 +1,7 @@+{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-} {-# OPTIONS_HADDOCK show-extensions #-}  -- |@@ -13,6 +15,7 @@   -- * File-based actions   editFile,   openingNewFile,+  openNewFile,    viWrite, viWriteTo, viSafeWriteTo,   fwriteE,        -- :: YiM ()@@ -24,19 +27,25 @@    -- * 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.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 @@   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 @@    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 @@     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 @@    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 ()
src/library/Yi/Keymap/Emacs.hs view
@@ -268,7 +268,7 @@                  , 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
src/library/Yi/Keymap/Emacs/Utils.hs view
@@ -121,7 +121,7 @@                         >>! closeBufferAndWindowE                         -- cancel                       ] ++ [char 'q' ?>>! quitEditor | hasQuit])-  yesAction = do fwriteBufferE (bkey firstBuffer)+  yesAction = do void $ fwriteBufferE (bkey firstBuffer)                  withEditor closeBufferAndWindowE                  continue 
src/library/Yi/Keymap/Vim/Ex/Commands/Edit.hs view
@@ -36,7 +36,7 @@     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)   }
src/library/Yi/Keymap/Vim/Ex/Commands/Quit.hs view
@@ -96,4 +96,6 @@                         <> " (add ! to override)"  saveAndQuitAllE :: YiM ()-saveAndQuitAllE = Common.forAllBuffers fwriteBufferE >> quitEditor+saveAndQuitAllE = do+    succeed <- fwriteAllE+    when succeed $ quitEditor
src/library/Yi/Keymap/Vim/Ex/Commands/Substitute.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# OPTIONS_HADDOCK show-extensions #-} @@ -16,7 +17,10 @@ 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 @@     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
src/library/Yi/Keymap/Vim/Ex/Commands/Write.hs view
@@ -53,4 +53,4 @@ tryWriteBuffer :: BufferRef -> YiM () tryWriteBuffer buf = do     ns <- Common.needsSaving buf-    when ns $ fwriteBufferE buf+    when ns . void $ fwriteBufferE buf
src/library/Yi/Keymap/Vim/ExMap.hs view
@@ -89,6 +89,7 @@     resetCountE     switchModeE Normal     closeBufferAndWindowE+    withCurrentBuffer $ setVisibleSelection False  exitBinding :: VimBinding exitBinding = VimBindingE f
src/library/Yi/Keymap/Vim/Motion.hs view
@@ -89,6 +89,8 @@ 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)
src/library/Yi/Keymap/Vim/NormalMap.hs view
@@ -22,11 +22,12 @@ 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 @@           f _ _ = NoMatch  continueSearching :: (Direction -> Direction) -> EditorM ()-continueSearching fdir = do+continueSearching fdir =   getRegexE >>= \case     Just regex -> do       dir <- fdir <$> use searchDirectionA@@ -452,12 +453,12 @@ 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)
src/library/Yi/Keymap/Vim/Operator.hs view
@@ -108,6 +108,9 @@         withCurrentBuffer $ do             point <- deleteRegionWithStyleB reg style             moveTo point+            when (style == LineWise) $ do+                insertB '\n'+                leftB         switchModeE $ Insert 'c'         return Continue }
src/library/Yi/Keymap/Vim/Tag.hs view
@@ -23,6 +23,7 @@     ) where  import           Control.Applicative+import           Control.Lens (view) import           Control.Monad import           Data.Binary import           Data.Default@@ -181,7 +182,7 @@ -- 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'
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 (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)
src/library/Yi/Mode/Haskell.hs view
@@ -422,7 +422,7 @@ -- | 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"
src/library/Yi/PersistentState.hs view
@@ -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 @@ 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 @@     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
src/library/Yi/Tag.hs view
@@ -28,11 +28,11 @@               , 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           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           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 @@   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 TagTable instance Binary TagsFileList #endif--instance YiVariable Tags--instance YiVariable TagsFileList
src/library/Yi/Types.hs view
@@ -213,6 +213,7 @@                 , 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 @@   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
src/library/Yi/UI/Pango.hs view
@@ -597,7 +597,7 @@     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
src/library/Yi/UI/SimpleLayout.hs view
@@ -125,22 +125,28 @@         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) 
src/library/Yi/UI/Vty.hs view
@@ -232,7 +232,7 @@                              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 ((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 @@                       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 @@      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
+ src/tests/vimtests/change/V3jc.test view
@@ -0,0 +1,15 @@+-- Input+(2,3)+aaaaaa+bbbbbb+cccccc+dddddd+eeeeee+ffffff+-- Output+(2,1)+aaaaaa++ffffff+-- Events+V3jc<Esc>
+ src/tests/vimtests/change/cc.test view
@@ -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>
− src/tests/vimtests/insertion/O3.test
@@ -1,11 +0,0 @@--- Input-(2,1)----- Output-(2,1)------ Events-O<Esc>
+ src/tests/vimtests/insertion/O4.test view
@@ -0,0 +1,11 @@+-- Input+(2,1)+++-- Output+(2,1)++++-- Events+O<Esc>
yi.cabal view
@@ -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 @@     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