diff --git a/src/library/Yi/Buffer/Adjusted.hs b/src/library/Yi/Buffer/Adjusted.hs
--- a/src/library/Yi/Buffer/Adjusted.hs
+++ b/src/library/Yi/Buffer/Adjusted.hs
@@ -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
diff --git a/src/library/Yi/Buffer/HighLevel.hs b/src/library/Yi/Buffer/HighLevel.hs
--- a/src/library/Yi/Buffer/HighLevel.hs
+++ b/src/library/Yi/Buffer/HighLevel.hs
@@ -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
 --
diff --git a/src/library/Yi/Buffer/Implementation.hs b/src/library/Yi/Buffer/Implementation.hs
--- a/src/library/Yi/Buffer/Implementation.hs
+++ b/src/library/Yi/Buffer/Implementation.hs
@@ -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
diff --git a/src/library/Yi/Buffer/Misc.hs b/src/library/Yi/Buffer/Misc.hs
--- a/src/library/Yi/Buffer/Misc.hs
+++ b/src/library/Yi/Buffer/Misc.hs
@@ -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
diff --git a/src/library/Yi/Buffer/TextUnit.hs b/src/library/Yi/Buffer/TextUnit.hs
--- a/src/library/Yi/Buffer/TextUnit.hs
+++ b/src/library/Yi/Buffer/TextUnit.hs
@@ -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)
diff --git a/src/library/Yi/Command.hs b/src/library/Yi/Command.hs
--- a/src/library/Yi/Command.hs
+++ b/src/library/Yi/Command.hs
@@ -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
diff --git a/src/library/Yi/Core.hs b/src/library/Yi/Core.hs
--- a/src/library/Yi/Core.hs
+++ b/src/library/Yi/Core.hs
@@ -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
diff --git a/src/library/Yi/Dired.hs b/src/library/Yi/Dired.hs
--- a/src/library/Yi/Dired.hs
+++ b/src/library/Yi/Dired.hs
@@ -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
diff --git a/src/library/Yi/Editor.hs b/src/library/Yi/Editor.hs
--- a/src/library/Yi/Editor.hs
+++ b/src/library/Yi/Editor.hs
@@ -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
diff --git a/src/library/Yi/Eval.hs b/src/library/Yi/Eval.hs
--- a/src/library/Yi/Eval.hs
+++ b/src/library/Yi/Eval.hs
@@ -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
diff --git a/src/library/Yi/File.hs b/src/library/Yi/File.hs
--- a/src/library/Yi/File.hs
+++ b/src/library/Yi/File.hs
@@ -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)
diff --git a/src/library/Yi/Keymap/Emacs.hs b/src/library/Yi/Keymap/Emacs.hs
--- a/src/library/Yi/Keymap/Emacs.hs
+++ b/src/library/Yi/Keymap/Emacs.hs
@@ -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
diff --git a/src/library/Yi/Keymap/Emacs/Utils.hs b/src/library/Yi/Keymap/Emacs/Utils.hs
--- a/src/library/Yi/Keymap/Emacs/Utils.hs
+++ b/src/library/Yi/Keymap/Emacs/Utils.hs
@@ -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" <> "."
                         ]
diff --git a/src/library/Yi/Keymap/Vim/Ex.hs b/src/library/Yi/Keymap/Vim/Ex.hs
--- a/src/library/Yi/Keymap/Vim/Ex.hs
+++ b/src/library/Yi/Keymap/Vim/Ex.hs
@@ -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
diff --git a/src/library/Yi/Keymap/Vim/Ex/Commands/Cabal.hs b/src/library/Yi/Keymap/Vim/Ex/Commands/Cabal.hs
--- a/src/library/Yi/Keymap/Vim/Ex/Commands/Cabal.hs
+++ b/src/library/Yi/Keymap/Vim/Ex/Commands/Cabal.hs
@@ -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
diff --git a/src/library/Yi/Keymap/Vim/Ex/Commands/Common.hs b/src/library/Yi/Keymap/Vim/Ex/Commands/Common.hs
--- a/src/library/Yi/Keymap/Vim/Ex/Commands/Common.hs
+++ b/src/library/Yi/Keymap/Vim/Ex/Commands/Common.hs
@@ -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
diff --git a/src/library/Yi/Keymap/Vim/Ex/Commands/Make.hs b/src/library/Yi/Keymap/Vim/Ex/Commands/Make.hs
new file mode 100644
--- /dev/null
+++ b/src/library/Yi/Keymap/Vim/Ex/Commands/Make.hs
@@ -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
+      }
diff --git a/src/library/Yi/Keymap/Vim/Ex/Commands/Quit.hs b/src/library/Yi/Keymap/Vim/Ex/Commands/Quit.hs
--- a/src/library/Yi/Keymap/Vim/Ex/Commands/Quit.hs
+++ b/src/library/Yi/Keymap/Vim/Ex/Commands/Quit.hs
@@ -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))
diff --git a/src/library/Yi/Keymap/Vim/Ex/Commands/Shell.hs b/src/library/Yi/Keymap/Vim/Ex/Commands/Shell.hs
new file mode 100644
--- /dev/null
+++ b/src/library/Yi/Keymap/Vim/Ex/Commands/Shell.hs
@@ -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 ())
+      }
diff --git a/src/library/Yi/Keymap/Vim/Ex/Commands/Tag.hs b/src/library/Yi/Keymap/Vim/Ex/Commands/Tag.hs
--- a/src/library/Yi/Keymap/Vim/Ex/Commands/Tag.hs
+++ b/src/library/Yi/Keymap/Vim/Ex/Commands/Tag.hs
@@ -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"]
   }
diff --git a/src/library/Yi/Keymap/Vim/Ex/Commands/Write.hs b/src/library/Yi/Keymap/Vim/Ex/Commands/Write.hs
--- a/src/library/Yi/Keymap/Vim/Ex/Commands/Write.hs
+++ b/src/library/Yi/Keymap/Vim/Ex/Commands/Write.hs
@@ -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
diff --git a/src/library/Yi/Keymap/Vim/ExMap.hs b/src/library/Yi/Keymap/Vim/ExMap.hs
--- a/src/library/Yi/Keymap/Vim/ExMap.hs
+++ b/src/library/Yi/Keymap/Vim/ExMap.hs
@@ -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
diff --git a/src/library/Yi/Keymap/Vim/InsertMap.hs b/src/library/Yi/Keymap/Vim/InsertMap.hs
--- a/src/library/Yi/Keymap/Vim/InsertMap.hs
+++ b/src/library/Yi/Keymap/Vim/InsertMap.hs
@@ -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
diff --git a/src/library/Yi/Keymap/Vim/Motion.hs b/src/library/Yi/Keymap/Vim/Motion.hs
--- a/src/library/Yi/Keymap/Vim/Motion.hs
+++ b/src/library/Yi/Keymap/Vim/Motion.hs
@@ -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
diff --git a/src/library/Yi/Keymap/Vim/NormalMap.hs b/src/library/Yi/Keymap/Vim/NormalMap.hs
--- a/src/library/Yi/Keymap/Vim/NormalMap.hs
+++ b/src/library/Yi/Keymap/Vim/NormalMap.hs
@@ -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
diff --git a/src/library/Yi/Keymap/Vim/NormalOperatorPendingMap.hs b/src/library/Yi/Keymap/Vim/NormalOperatorPendingMap.hs
--- a/src/library/Yi/Keymap/Vim/NormalOperatorPendingMap.hs
+++ b/src/library/Yi/Keymap/Vim/NormalOperatorPendingMap.hs
@@ -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)
diff --git a/src/library/Yi/Keymap/Vim/Tag.hs b/src/library/Yi/Keymap/Vim/Tag.hs
--- a/src/library/Yi/Keymap/Vim/Tag.hs
+++ b/src/library/Yi/Keymap/Vim/Tag.hs
@@ -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 =
diff --git a/src/library/Yi/Keymap/Vim/VisualMap.hs b/src/library/Yi/Keymap/Vim/VisualMap.hs
--- a/src/library/Yi/Keymap/Vim/VisualMap.hs
+++ b/src/library/Yi/Keymap/Vim/VisualMap.hs
@@ -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
diff --git a/src/library/Yi/Main.hs b/src/library/Yi/Main.hs
--- a/src/library/Yi/Main.hs
+++ b/src/library/Yi/Main.hs
@@ -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)
diff --git a/src/library/Yi/Misc.hs b/src/library/Yi/Misc.hs
--- a/src/library/Yi/Misc.hs
+++ b/src/library/Yi/Misc.hs
@@ -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)
diff --git a/src/library/Yi/Mode/Compilation.hs b/src/library/Yi/Mode/Compilation.hs
--- a/src/library/Yi/Mode/Compilation.hs
+++ b/src/library/Yi/Mode/Compilation.hs
@@ -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 ()
diff --git a/src/library/Yi/Modes.hs b/src/library/Yi/Modes.hs
--- a/src/library/Yi/Modes.hs
+++ b/src/library/Yi/Modes.hs
@@ -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
   }
 
diff --git a/src/library/Yi/Tag.hs b/src/library/Yi/Tag.hs
--- a/src/library/Yi/Tag.hs
+++ b/src/library/Yi/Tag.hs
@@ -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
diff --git a/src/library/Yi/Types.hs b/src/library/Yi/Types.hs
--- a/src/library/Yi/Types.hs
+++ b/src/library/Yi/Types.hs
@@ -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)
 
diff --git a/src/library/Yi/UI/Pango.hs b/src/library/Yi/UI/Pango.hs
--- a/src/library/Yi/UI/Pango.hs
+++ b/src/library/Yi/UI/Pango.hs
@@ -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
diff --git a/src/library/Yi/UI/Pango/Control.hs b/src/library/Yi/UI/Pango/Control.hs
--- a/src/library/Yi/UI/Pango/Control.hs
+++ b/src/library/Yi/UI/Pango/Control.hs
@@ -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)
diff --git a/src/library/Yi/UI/SimpleLayout.hs b/src/library/Yi/UI/SimpleLayout.hs
--- a/src/library/Yi/UI/SimpleLayout.hs
+++ b/src/library/Yi/UI/SimpleLayout.hs
@@ -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
     }
diff --git a/src/library/Yi/UI/Vty.hs b/src/library/Yi/UI/Vty.hs
--- a/src/library/Yi/UI/Vty.hs
+++ b/src/library/Yi/UI/Vty.hs
@@ -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))
diff --git a/src/library/Yi/Window.hs b/src/library/Yi/Window.hs
--- a/src/library/Yi/Window.hs
+++ b/src/library/Yi/Window.hs
@@ -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
diff --git a/src/tests/vimtests/delete/d00.test b/src/tests/vimtests/delete/d00.test
new file mode 100644
--- /dev/null
+++ b/src/tests/vimtests/delete/d00.test
@@ -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
diff --git a/src/tests/vimtests/find/f5.test b/src/tests/vimtests/find/f5.test
new file mode 100644
--- /dev/null
+++ b/src/tests/vimtests/find/f5.test
@@ -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>
diff --git a/src/tests/vimtests/insertion/O3.test b/src/tests/vimtests/insertion/O3.test
new file mode 100644
--- /dev/null
+++ b/src/tests/vimtests/insertion/O3.test
@@ -0,0 +1,11 @@
+-- Input
+(2,1)
+
+
+-- Output
+(2,1)
+
+
+
+-- Events
+O<Esc>
diff --git a/src/tests/vimtests/insertion/o3.test b/src/tests/vimtests/insertion/o3.test
new file mode 100644
--- /dev/null
+++ b/src/tests/vimtests/insertion/o3.test
@@ -0,0 +1,11 @@
+-- Input
+(2,1)
+
+
+-- Output
+(3,1)
+
+
+
+-- Events
+o<Esc>
diff --git a/yi.cabal b/yi.cabal
--- a/yi.cabal
+++ b/yi.cabal
@@ -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:
