/src/Editing/Execute.hs

http://github.com/Eelis/geordi · Haskell · 79 lines · 63 code · 13 blank · 3 comment · 4 complexity · 1f8474c1330a1b7d955c2f71d5680787 MD5 · raw file

  1. {-# LANGUAGE UnicodeSyntax, PatternGuards, ScopedTypeVariables, TypeSynonymInstances, ViewPatterns, FlexibleContexts, RecordWildCards, MultiParamTypeClasses #-}
  2. module Editing.Execute (execute) where
  3. import qualified Data.Set as Set
  4. import qualified Cxx.Parse
  5. import Editing.EditsPreparation (FindResult(..), FoundIn(..), findInStr)
  6. import Control.Monad (foldM)
  7. import Data.Monoid (Monoid(..))
  8. import Control.Applicative ((<|>))
  9. import Control.Arrow ((&&&))
  10. import Request (EditableRequest(..), EditableRequestKind(..), RequestEdit(..), addEvalOpt)
  11. import Cxx.Basics (GeordiRequest)
  12. import Util ((.), E, MaybeApply(..), Apply(..), MyMonadError(..))
  13. import Prelude hiding ((.))
  14. import Editing.Basics
  15. import Editing.Commands
  16. editRequestBody :: (String String) (EditableRequest EditableRequest)
  17. editRequestBody f (EditableRequest k s) = EditableRequest k (f s)
  18. instance MaybeApply RequestEdit EditableRequest where
  19. mapply e er@EditableRequest{..} = case e of
  20. TextEdit te return $ editRequestBody (apply te) er
  21. RemoveOptions opts
  22. | Evaluate f kind return er{ kind = Evaluate $ (Set.\\) f $ Set.fromList opts }
  23. | otherwise throwError $ "Cannot remove evaluation options from \"" ++ show kind ++ "\" request."
  24. AddOptions opts
  25. | Evaluate f kind return er{ kind = Evaluate $ foldr addEvalOpt f opts }
  26. | otherwise throwError $ "Cannot use evaluation options for \"" ++ show kind ++ "\" request."
  27. data FoldState = FoldState
  28. { adjust_since_start :: Adjuster Char
  29. , current_request :: EditableRequest
  30. , milepost :: E WellFormedMilepost }
  31. data WellFormedMilepost = WellFormedMilepost
  32. { tree :: GeordiRequest
  33. , adjust_to_wf :: Adjuster Char
  34. , adjust_since_wf :: Adjuster Char }
  35. -- 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.
  36. fold_edit :: RequestEdit FoldState E FoldState
  37. -- The edit must be relative to the current request in the fold state (sequence_edit's job).
  38. fold_edit e fs = do
  39. r mapply e $ current_request fs
  40. let
  41. f req = WellFormedMilepost req (adjust_since_start new) mempty
  42. a = case e of TextEdit te adjuster (editable_body $ current_request fs) te; _ mempty
  43. new = FoldState
  44. (adjust_since_start fs `mappend` a)
  45. r
  46. (((\mp mp { adjust_since_wf = adjust_since_wf mp `mappend` a }) . milepost fs) <|>
  47. f . Cxx.Parse.parseRequest (editable_body r))
  48. return new
  49. sequence_edit :: FoldState FindResult RequestEdit E FoldState
  50. sequence_edit fs (Found f e) = do
  51. a :: Adjuster Char case f of
  52. InGiven return $ adjust_since_start fs
  53. InWf adjust_since_wf . milepost fs
  54. case e of
  55. TextEdit e' → do
  56. t (TextEdit .) . editAdjuster a e'
  57. maybe return fold_edit t fs
  58. _ fold_edit e fs
  59. exec_cmd :: Maybe (TextEdit Char) -> String FoldState Command E FoldState
  60. exec_cmd fixit s fs = (>>= foldM sequence_edit fs) .
  61. findInStr s fixit ((tree &&& anchorAdjuster . adjust_to_wf) . milepost fs)
  62. execute :: Maybe (TextEdit Char) -> [Command] EditableRequest E EditableRequest
  63. execute fixit l r@(EditableRequest _ s) = current_request . foldM (exec_cmd fixit s) fs l
  64. where
  65. f t = WellFormedMilepost t mempty mempty
  66. fs = (FoldState mempty r $ f . Cxx.Parse.parseRequest s)