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 +37/−0
- src/library/Yi/Buffer/Misc.hs +28/−1
- src/library/Yi/Buffer/TextUnit.hs +12/−4
- src/library/Yi/Editor.hs +4/−2
- src/library/Yi/Eval.hs +53/−18
- src/library/Yi/File.hs +49/−17
- src/library/Yi/Keymap/Emacs.hs +1/−1
- src/library/Yi/Keymap/Emacs/Utils.hs +1/−1
- src/library/Yi/Keymap/Vim/Ex/Commands/Edit.hs +1/−1
- src/library/Yi/Keymap/Vim/Ex/Commands/Quit.hs +3/−1
- src/library/Yi/Keymap/Vim/Ex/Commands/Substitute.hs +78/−13
- src/library/Yi/Keymap/Vim/Ex/Commands/Write.hs +1/−1
- src/library/Yi/Keymap/Vim/ExMap.hs +1/−0
- src/library/Yi/Keymap/Vim/Motion.hs +2/−0
- src/library/Yi/Keymap/Vim/NormalMap.hs +8/−7
- src/library/Yi/Keymap/Vim/Operator.hs +3/−0
- src/library/Yi/Keymap/Vim/Tag.hs +2/−1
- src/library/Yi/Main.hs +2/−2
- src/library/Yi/Mode/Haskell.hs +1/−1
- src/library/Yi/PersistentState.hs +21/−4
- src/library/Yi/Tag.hs +18/−21
- src/library/Yi/Types.hs +4/−3
- src/library/Yi/UI/Pango.hs +1/−1
- src/library/Yi/UI/SimpleLayout.hs +15/−9
- src/library/Yi/UI/Vty.hs +19/−8
- src/tests/vimtests/change/V3jc.test +15/−0
- src/tests/vimtests/change/cc.test +12/−0
- src/tests/vimtests/insertion/O3.test +0/−11
- src/tests/vimtests/insertion/O4.test +11/−0
- yi.cabal +3/−2
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