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

    -- |
    -- Module      :  Yi.Keymap.Vim.Ex.Commands.Substitute
    -- License     :  GPL-2
    -- Maintainer  :  yi-devel@googlegroups.com
    -- Stability   :  experimental
    -- Portability :  portable

    module Yi.Keymap.Vim.Ex.Commands.Substitute (parse) where

    import           Control.Applicative              (Alternative)
    import           Control.Monad                    (void)
    import qualified Data.Attoparsec.Text             as P (char, inClass, many', match,
                                                            satisfy, string, option,
                                                            (<?>), Parser)
    import           Data.Maybe                       (fromMaybe)
    import           Data.Monoid                      ((<>))
    import qualified Data.Text                        as T (Text, cons, snoc)
    import           Lens.Micro.Platform              (over, _2)
    import           Yi.Buffer
    import           Yi.Keymap                        (Action (EditorA))
    import           Yi.Keymap.Vim.Common             (EventString, Substitution(..))
    import qualified Yi.Keymap.Vim.Ex.Commands.Common as Common (parse, pureExCommand, parseRange)
    import           Yi.Keymap.Vim.Ex.Types           (ExCommand (cmdAction, cmdShow))
    import qualified Yi.Rope                          as R (fromString, toText)
    import           Yi.Keymap.Vim.Substitution

    -- | Skip one or no occurrences of a given parser.
    skipOptional :: Alternative f => f a -> f ()
    skipOptional :: forall (f :: * -> *) a. Alternative f => f a -> f ()
    skipOptional f a
    p = () -> f () -> f ()
    forall (f :: * -> *) a. Alternative f => a -> f a -> f a
    P.option () (() () -> f a -> f ()
    forall a b. a -> f b -> f a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ f a
    p)
    {-# SPECIALIZE skipOptional :: P.Parser a -> P.Parser () #-}

    parse :: EventString -> Maybe ExCommand
    parse :: EventString -> Maybe ExCommand
    parse = Parser ExCommand -> EventString -> Maybe ExCommand
    Common.parse (Parser ExCommand -> EventString -> Maybe ExCommand)
    -> Parser ExCommand -> EventString -> Maybe ExCommand
    forall a b. (a -> b) -> a -> b
    $ do
        (rangeText, rangeB) <- ASetter
      (Text, Maybe (BufferM Region))
      (Text, BufferM Region)
      (Maybe (BufferM Region))
      (BufferM Region)
    -> (Maybe (BufferM Region) -> BufferM Region)
    -> (Text, Maybe (BufferM Region))
    -> (Text, BufferM Region)
    forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
    over ASetter
      (Text, Maybe (BufferM Region))
      (Text, BufferM Region)
      (Maybe (BufferM Region))
      (BufferM Region)
    forall s t a b. Field2 s t a b => Lens s t a b
    Lens
      (Text, Maybe (BufferM Region))
      (Text, BufferM Region)
      (Maybe (BufferM Region))
      (BufferM Region)
    _2 (BufferM Region -> Maybe (BufferM Region) -> BufferM Region
    forall a. a -> Maybe a -> a
    fromMaybe (BufferM Region -> Maybe (BufferM Region) -> BufferM Region)
    -> BufferM Region -> Maybe (BufferM Region) -> BufferM Region
    forall a b. (a -> b) -> a -> b
    $ TextUnit -> BufferM Region
    regionOfB TextUnit
    Line) ((Text, Maybe (BufferM Region)) -> (Text, BufferM Region))
    -> Parser Text (Text, Maybe (BufferM Region))
    -> Parser Text (Text, BufferM Region)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Parser (Maybe (BufferM Region))
    -> Parser Text (Text, Maybe (BufferM Region))
    forall a. Parser a -> Parser (Text, a)
    P.match Parser (Maybe (BufferM Region))
    Common.parseRange
        P.char 's' *>
          skipOptional (P.string "ub" *> skipOptional (P.string "stitute"))
          P.<?> "substitute"
        delimiter <- P.satisfy (`elem` ("!@#$%^&*()[]{}<>/.,~';:?-=" :: String))
        from <- R.fromString <$> P.many' (P.satisfy (/= delimiter))
        void $ P.char delimiter
        to <- R.fromString <$> P.many' (P.satisfy (/= delimiter))
        flagChars <- P.option "" $
          P.char delimiter *> P.many' (P.satisfy $ P.inClass "gic")
        return $! substitute
            (Substitution
                from
                to
                ('g' `elem` flagChars)
                ('i' `elem` flagChars)
                ('c' `elem` flagChars))
            delimiter
            rangeText
            rangeB

    substitute :: Substitution -> Char -> T.Text -> BufferM Region -> ExCommand
    substitute :: Substitution -> Char -> Text -> BufferM Region -> ExCommand
    substitute s :: Substitution
    s@(Substitution YiString
    from YiString
    to Bool
    global Bool
    caseInsensitive Bool
    confirm) Char
    delimiter Text
    regionText BufferM Region
    regionB = ExCommand
    Common.pureExCommand
      { cmdShow = regionText
                  <>       "s"
                  <>       (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 = EditorA $ substituteE s regionB
      }