{-# LANGUAGE UnicodeSyntax, PatternGuards, ScopedTypeVariables, TypeSynonymInstances, ViewPatterns, FlexibleContexts, RecordWildCards, MultiParamTypeClasses #-} module Editing.Execute (execute) where import qualified Data.Set as Set import qualified Cxx.Parse import Editing.EditsPreparation (FindResult(..), FoundIn(..), findInStr) import Control.Monad (foldM) import Data.Monoid (Monoid(..)) import Control.Applicative ((<|>)) import Control.Arrow ((&&&)) import Request (EditableRequest(..), EditableRequestKind(..), RequestEdit(..), addEvalOpt) import Cxx.Basics (GeordiRequest) import Util ((.), E, MaybeApply(..), Apply(..), MyMonadError(..)) import Prelude hiding ((.)) import Editing.Basics import Editing.Commands editRequestBody :: (String → String) → (EditableRequest → EditableRequest) editRequestBody f (EditableRequest k s) = EditableRequest k (f s) instance MaybeApply RequestEdit EditableRequest where mapply e er@EditableRequest{..} = case e of TextEdit te → return $ editRequestBody (apply te) er RemoveOptions opts | Evaluate f ← kind → return er{ kind = Evaluate $ (Set.\\) f $ Set.fromList opts } | otherwise → throwError $ "Cannot remove evaluation options from \"" ++ show kind ++ "\" request." AddOptions opts | Evaluate f ← kind → return er{ kind = Evaluate $ foldr addEvalOpt f opts } | otherwise → throwError $ "Cannot use evaluation options for \"" ++ show kind ++ "\" request." data FoldState = FoldState { adjust_since_start :: Adjuster Char , current_request :: EditableRequest , milepost :: E WellFormedMilepost } data WellFormedMilepost = WellFormedMilepost { tree :: GeordiRequest , adjust_to_wf :: Adjuster Char , adjust_since_wf :: Adjuster Char } -- The earliest well-formed AST of the request body, its String version, an adjuster adjusting anchors in the original request to anchors in the well-formed request, and an adjuster adjusting edits in the well-formed request to edits in the current request. fold_edit :: RequestEdit → FoldState → E FoldState -- The edit must be relative to the current request in the fold state (sequence_edit's job). fold_edit e fs = do r ← mapply e $ current_request fs let f req = WellFormedMilepost req (adjust_since_start new) mempty a = case e of TextEdit te → adjuster (editable_body $ current_request fs) te; _ → mempty new = FoldState (adjust_since_start fs `mappend` a) r (((\mp → mp { adjust_since_wf = adjust_since_wf mp `mappend` a }) . milepost fs) <|> f . Cxx.Parse.parseRequest (editable_body r)) return new sequence_edit :: FoldState → FindResult RequestEdit → E FoldState sequence_edit fs (Found f e) = do a :: Adjuster Char ← case f of InGiven → return $ adjust_since_start fs InWf → adjust_since_wf . milepost fs case e of TextEdit e' → do t ← (TextEdit .) . editAdjuster a e' maybe return fold_edit t fs _ → fold_edit e fs exec_cmd :: Maybe (TextEdit Char) -> String → FoldState → Command → E FoldState exec_cmd fixit s fs = (>>= foldM sequence_edit fs) . findInStr s fixit ((tree &&& anchorAdjuster . adjust_to_wf) . milepost fs) execute :: Maybe (TextEdit Char) -> [Command] → EditableRequest → E EditableRequest execute fixit l r@(EditableRequest _ s) = current_request . foldM (exec_cmd fixit s) fs l where f t = WellFormedMilepost t mempty mempty fs = (FoldState mempty r $ f . Cxx.Parse.parseRequest s)