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
skipOptional :: Alternative f => f a -> f ()
skipOptional p = P.option () (() <$ p)
parse :: EventString -> Maybe ExCommand
parse = Common.parse $ do
(rangeText, rangeB) <- over _2 (fromMaybe $ regionOfB Line) <$> P.match 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 s@(Substitution from to global caseInsensitive confirm) delimiter regionText regionB = 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
}