    {-# LANGUAGE OverloadedStrings #-}
    {-# OPTIONS_HADDOCK show-extensions #-}

    -- |
    -- Module      :  Yi.Keymap.Vim.Ex.Commands.Buffer
    -- License     :  GPL-2
    -- Maintainer  :  yi-devel@googlegroups.com
    -- Stability   :  experimental
    -- Portability :  portable
    --
    -- :buffer ex command to switch to named or numbered buffer.

    module Yi.Keymap.Vim.Ex.Commands.Buffer (parse,bufferIdentifier) where

    import           Control.Applicative              (Alternative ((<|>)))
    import           Control.Monad                    (void)
    import           Control.Monad.State              (gets)
    import qualified Data.Attoparsec.Text             as P (Parser, anyChar, choice,
                                                            digit, endOfInput, many', many1,
                                                            parseOnly, space, string)
    import           Yi.Buffer.Basic                  (BufferRef (..))
    import qualified Data.Text                        as T (Text, pack, unpack)
    import           Yi.Buffer.Misc                   (bkey, isUnchangedBuffer)
    import           Yi.Editor
    import           Yi.Keymap                        (Action (EditorA))
    import           Yi.Keymap.Vim.Common             (EventString)
    import qualified Yi.Keymap.Vim.Ex.Commands.Common as Common (errorNoWrite, parseWithBangAndCount, pureExCommand)
    import           Yi.Keymap.Vim.Ex.Types           (ExCommand (cmdAction, cmdShow))

    parse :: EventString -> Maybe ExCommand
    parse :: EventString -> Maybe ExCommand
    parse = Parser ()
    -> (() -> Bool -> Maybe Int -> Parser ExCommand)
    -> EventString
    -> Maybe ExCommand
    forall a.
    Parser a
    -> (a -> Bool -> Maybe Int -> Parser ExCommand)
    -> EventString
    -> Maybe ExCommand
    Common.parseWithBangAndCount Parser ()
    nameParser ((() -> Bool -> Maybe Int -> Parser ExCommand)
     -> EventString -> Maybe ExCommand)
    -> (() -> Bool -> Maybe Int -> Parser ExCommand)
    -> EventString
    -> Maybe ExCommand
    forall a b. (a -> b) -> a -> b
    $ \ ()
    _ Bool
    bang Maybe Int
    mcount -> do
      bufIdent <- Parser Text
    bufferIdentifier
      return $ Common.pureExCommand {
          cmdShow = "buffer"
        , cmdAction = EditorA $ do
            unchanged <- withCurrentBuffer $ gets isUnchangedBuffer
            if bang || unchanged
              then case mcount of
                Maybe Int
    Nothing -> Text -> EditorM ()
    switchToBuffer Text
    bufIdent
                Just Int
    i  -> BufferRef -> EditorM ()
    switchByRef (BufferRef -> EditorM ()) -> BufferRef -> EditorM ()
    forall a b. (a -> b) -> a -> b
    $ Int -> BufferRef
    BufferRef Int
    i
              else Common.errorNoWrite
        }

    bufferSymbol :: P.Parser T.Text
    bufferSymbol :: Parser Text
    bufferSymbol = Text -> Parser Text
    P.string Text
    "%" Parser Text -> Parser Text -> Parser Text
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> Text -> Parser Text
    P.string Text
    "#"

    bufferIdentifier :: P.Parser T.Text
    bufferIdentifier :: Parser Text
    bufferIdentifier = (String -> Text
    T.pack (String -> Text) -> Parser Text String -> Parser Text
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Parser Text Char -> Parser Text String
    forall (f :: * -> *) a. Alternative f => f a -> f [a]
    P.many1 Parser Text Char
    P.digit) Parser Text -> Parser Text -> Parser Text
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> Parser Text
    bufferSymbol Parser Text -> Parser Text -> Parser Text
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|>
        (String -> Text
    T.pack (String -> Text) -> Parser Text String -> Parser Text
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Parser Text Char -> Parser Text String
    forall (f :: * -> *) a. Alternative f => f a -> f [a]
    P.many1 Parser Text Char
    P.space) Parser Text -> Parser Text -> Parser Text
    forall a b. Parser Text a -> Parser Text b -> Parser Text b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> (String -> Text
    T.pack (String -> Text) -> Parser Text String -> Parser Text
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Parser Text Char -> Parser Text String
    forall (m :: * -> *) a. MonadPlus m => m a -> m [a]
    P.many' Parser Text Char
    P.anyChar) Parser Text -> Parser Text -> Parser Text
    forall a. Parser Text a -> Parser Text a -> Parser Text a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|>
        Parser ()
    forall t. Chunk t => Parser t ()
    P.endOfInput Parser () -> Parser Text -> Parser Text
    forall a b. Parser Text a -> Parser Text b -> Parser Text b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> Text -> Parser Text
    forall a. a -> Parser Text a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Text
    ""

    nameParser :: P.Parser ()
    nameParser :: Parser ()
    nameParser = Parser Text -> Parser ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (Parser Text -> Parser ())
    -> ([Text] -> Parser Text) -> [Text] -> Parser ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Parser Text] -> Parser Text
    forall (f :: * -> *) a. Alternative f => [f a] -> f a
    P.choice ([Parser Text] -> Parser Text)
    -> ([Text] -> [Parser Text]) -> [Text] -> Parser Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Text -> Parser Text) -> [Text] -> [Parser Text]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Text -> Parser Text
    P.string ([Text] -> Parser ()) -> [Text] -> Parser ()
    forall a b. (a -> b) -> a -> b
    $ [Text
    "buffer", Text
    "buf", Text
    "bu", Text
    "b"]

    switchToBuffer :: T.Text -> EditorM ()
    switchToBuffer :: Text -> EditorM ()
    switchToBuffer Text
    s =
        case Parser BufferRef -> Text -> Either String BufferRef
    forall a. Parser a -> Text -> Either String a
    P.parseOnly Parser BufferRef
    bufferRef Text
    s of
            Right BufferRef
    ref -> BufferRef -> EditorM ()
    switchByRef BufferRef
    ref
            Left String
    _e   -> String -> EditorM ()
    switchByName (String -> EditorM ()) -> String -> EditorM ()
    forall a b. (a -> b) -> a -> b
    $ Text -> String
    T.unpack Text
    s
      where
        bufferRef :: Parser BufferRef
    bufferRef = Int -> BufferRef
    BufferRef (Int -> BufferRef) -> (String -> Int) -> String -> BufferRef
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Int
    forall a. Read a => String -> a
    read (String -> BufferRef) -> Parser Text String -> Parser BufferRef
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Parser Text Char -> Parser Text String
    forall (f :: * -> *) a. Alternative f => f a -> f [a]
    P.many1 Parser Text Char
    P.digit

    switchByName :: String -> EditorM ()
    switchByName :: String -> EditorM ()
    switchByName String
    ""      = () -> EditorM ()
    forall a. a -> EditorM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
    switchByName String
    "%"     = () -> EditorM ()
    forall a. a -> EditorM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
    switchByName String
    "#"     = Text -> EditorM ()
    switchToBufferWithNameE Text
    ""
    switchByName String
    bufName = Text -> EditorM ()
    switchToBufferWithNameE (String -> Text
    T.pack String
    bufName)

    switchByRef :: BufferRef -> EditorM ()
    switchByRef :: BufferRef -> EditorM ()
    switchByRef BufferRef
    ref = do
        mBuf <- BufferRef -> EditorM (Maybe FBuffer)
    forall (m :: * -> *).
    MonadEditor m =>
    BufferRef -> m (Maybe FBuffer)
    findBuffer BufferRef
    ref
        maybe (return ()) (switchToBufferE . bkey) mBuf