diff --git a/src/Yi/Keymap/Vim/Common.hs b/src/Yi/Keymap/Vim/Common.hs
--- a/src/Yi/Keymap/Vim/Common.hs
+++ b/src/Yi/Keymap/Vim/Common.hs
@@ -1,7 +1,8 @@
-{-# LANGUAGE CPP                #-}
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE DeriveGeneric      #-}
-{-# LANGUAGE TemplateHaskell    #-}
+{-# LANGUAGE CPP                        #-}
+{-# LANGUAGE DeriveDataTypeable         #-}
+{-# LANGUAGE DeriveGeneric              #-}
+{-# LANGUAGE TemplateHaskell            #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# OPTIONS_HADDOCK show-extensions #-}
 
 -- |
@@ -38,6 +39,7 @@
 import           Data.Default              (Default (..))
 import qualified Data.HashMap.Strict       as HM (HashMap)
 import           Data.Monoid               ((<>))
+import           Data.Semigroup            (Semigroup)
 import           Data.String               (IsString (..))
 import qualified Data.Text                 as T (Text, isPrefixOf, pack)
 import qualified Data.Text.Encoding        as E (decodeUtf8, encodeUtf8)
@@ -50,23 +52,15 @@
 import           Yi.Types                  (YiVariable)
 
 
-newtype EventString = Ev { _unEv :: T.Text } deriving (Show, Eq, Ord)
+newtype EventString = Ev { _unEv :: T.Text } deriving (Show, Eq, Ord, Semigroup, Monoid)
 
 instance IsString EventString where
   fromString = Ev . T.pack
 
-newtype OperatorName = Op { _unOp :: T.Text } deriving (Show, Eq)
+newtype OperatorName = Op { _unOp :: T.Text } deriving (Show, Eq, Semigroup, Monoid)
 
 instance IsString OperatorName where
   fromString = Op . T.pack
-
-instance Monoid EventString where
-  mempty = Ev mempty
-  Ev t `mappend` Ev t' = Ev $ t <> t'
-
-instance Monoid OperatorName where
-  mempty = Op mempty
-  Op t `mappend` Op t' = Op $ t <> t'
 
 instance Binary EventString where
   get = Ev . E.decodeUtf8 <$> get
diff --git a/src/Yi/Keymap/Vim/Ex.hs b/src/Yi/Keymap/Vim/Ex.hs
--- a/src/Yi/Keymap/Vim/Ex.hs
+++ b/src/Yi/Keymap/Vim/Ex.hs
@@ -28,6 +28,7 @@
 import qualified Yi.Keymap.Vim.Ex.Commands.Help         as Help (parse)
 import qualified Yi.Keymap.Vim.Ex.Commands.Make         as Make (parse)
 import qualified Yi.Keymap.Vim.Ex.Commands.Nohl         as Nohl (parse)
+import qualified Yi.Keymap.Vim.Ex.Commands.Number       as Number (parse)
 import qualified Yi.Keymap.Vim.Ex.Commands.Paste        as Paste (parse)
 import qualified Yi.Keymap.Vim.Ex.Commands.Quit         as Quit (parse)
 import qualified Yi.Keymap.Vim.Ex.Commands.Read         as Read (parse)
@@ -58,6 +59,7 @@
     , Help.parse
     , Make.parse
     , Nohl.parse
+    , Number.parse
     , Paste.parse
     , Quit.parse
     , Read.parse
diff --git a/src/Yi/Keymap/Vim/Ex/Commands/Number.hs b/src/Yi/Keymap/Vim/Ex/Commands/Number.hs
new file mode 100644
--- /dev/null
+++ b/src/Yi/Keymap/Vim/Ex/Commands/Number.hs
@@ -0,0 +1,52 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# OPTIONS_HADDOCK show-extensions #-}
+
+-- |
+-- Module      :  Yi.Keymap.Vim.Ex.Commands.Number
+-- License     :  GPL-2
+-- Maintainer  :  yi-devel@googlegroups.com
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- Toggles line numbers.
+
+module Yi.Keymap.Vim.Ex.Commands.Number (parse) where
+
+import qualified Data.Attoparsec.Text             as P (string)
+import           Data.Monoid                      ((<>))
+import           Yi.Editor                        (printMsg, withCurrentBuffer)
+import           Yi.Keymap                        (Action (BufferA, EditorA))
+import           Yi.Keymap.Vim.Common             (EventString)
+import           Yi.Keymap.Vim.Ex.Commands.Common (BoolOptionAction (..), parseBoolOption, pureExCommand)
+import qualified Yi.Keymap.Vim.Ex.Commands.Common as Ex (parse)
+import           Yi.Keymap.Vim.Ex.Types           (ExCommand (..), evStringToExCommand)
+import           Yi.String                        (showT)
+import           Yi.UI.LineNumbers                (getDisplayLineNumbersLocal, setDisplayLineNumbersLocal)
+
+-- | Defines the following commands:
+-- - :set [no]number        (toggle buffer-local line numbers)
+-- - :unset number          (make the current buffer use the global setting)
+parse :: EventString -> Maybe ExCommand
+parse = evStringToExCommand
+  [ parseBoolOption "number" actionSet
+  , parseUnset
+  ]
+
+actionSet :: BoolOptionAction -> Action
+actionSet BoolOptionAsk = EditorA $ do
+  mb <- withCurrentBuffer getDisplayLineNumbersLocal
+  printMsg $ "number = " <> case mb of
+    Nothing -> "<unset>"
+    Just b  -> showT b
+actionSet (BoolOptionSet b) = BufferA $ setDisplayLineNumbersLocal (Just b)
+actionSet BoolOptionInvert = BufferA $ do
+  b <- getDisplayLineNumbersLocal
+  setDisplayLineNumbersLocal (fmap not b)
+
+parseUnset :: EventString -> Maybe ExCommand
+parseUnset = Ex.parse $ do
+  _ <- P.string "unset number"
+  return $ pureExCommand
+    { cmdShow = "unset number"
+    , cmdAction = BufferA $ setDisplayLineNumbersLocal Nothing
+    }
diff --git a/yi-keymap-vim.cabal b/yi-keymap-vim.cabal
--- a/yi-keymap-vim.cabal
+++ b/yi-keymap-vim.cabal
@@ -1,5 +1,5 @@
 name:           yi-keymap-vim
-version:        0.17.1
+version:        0.18.0
 synopsis:       Vim keymap for Yi editor
 category:       Yi
 homepage:       https://github.com/yi-editor/yi#readme
@@ -65,8 +65,8 @@
     , text
     , transformers-base
     , unordered-containers
-    , yi-core >= 0.17
-    , yi-language >= 0.17
+    , yi-core >= 0.18
+    , yi-language >= 0.18
     , yi-rope >= 0.10
   exposed-modules:
       Yi.Config.Default.Vim
@@ -89,6 +89,7 @@
       Yi.Keymap.Vim.Ex.Commands.Help
       Yi.Keymap.Vim.Ex.Commands.Make
       Yi.Keymap.Vim.Ex.Commands.Nohl
+      Yi.Keymap.Vim.Ex.Commands.Number
       Yi.Keymap.Vim.Ex.Commands.Paste
       Yi.Keymap.Vim.Ex.Commands.Quit
       Yi.Keymap.Vim.Ex.Commands.Read
@@ -149,8 +150,8 @@
     , text
     , transformers-base
     , unordered-containers
-    , yi-core >= 0.17
-    , yi-language >= 0.17
+    , yi-core >= 0.18
+    , yi-language >= 0.18
     , yi-rope >= 0.10
     , tasty
     , tasty-hunit
