packages feed

reprinter 0.1.0.0 → 0.2.0.0

raw patch · 3 files changed

+226/−392 lines, 3 filesdep +textdep −bytestringdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: text

Dependencies removed: bytestring

Dependency ranges changed: base

API changes (from Hackage documentation)

- Text.Reprinter: Position :: Int -> Int -> Position
- Text.Reprinter: [posColumn] :: Position -> Int
- Text.Reprinter: [posLine] :: Position -> Int
- Text.Reprinter: data Position
- Text.Reprinter: instance Data.Data.Data Text.Reprinter.Position
- Text.Reprinter: instance GHC.Show.Show Text.Reprinter.Position
- Text.Reprinter: splitBySpan :: (Position, Position) -> Source -> (Source, Source)
- Text.Reprinter: type Reprinting m = forall b. Typeable b => b -> m (Maybe (RefactorType, Source, (Position, Position)))
+ Text.Reprinter: advanceCol :: Position -> Position
+ Text.Reprinter: advanceLine :: Position -> Position
+ Text.Reprinter: initCol :: Col
+ Text.Reprinter: initLine :: Line
+ Text.Reprinter: instance Data.Data.Data Text.Reprinter.Col
+ Text.Reprinter: instance Data.Data.Data Text.Reprinter.Line
+ Text.Reprinter: instance GHC.Classes.Eq Text.Reprinter.Col
+ Text.Reprinter: instance GHC.Classes.Eq Text.Reprinter.Line
+ Text.Reprinter: instance GHC.Classes.Ord Text.Reprinter.Col
+ Text.Reprinter: instance GHC.Classes.Ord Text.Reprinter.Line
+ Text.Reprinter: instance GHC.Show.Show Text.Reprinter.Col
+ Text.Reprinter: instance GHC.Show.Show Text.Reprinter.Line
+ Text.Reprinter: instance GHC.Show.Show Text.Reprinter.RefactorType
+ Text.Reprinter: mkCol :: Int -> Either String Col
+ Text.Reprinter: mkLine :: Int -> Either String Line
+ Text.Reprinter: reprintSort :: (Monad m, Data ast) => Reprinting m -> ast -> Source -> m Source
+ Text.Reprinter: type Position = (Line, Col)
+ Text.Reprinter: type Span = (Position, Position)
+ Text.Reprinter: type Reprinting m = forall node. Typeable node => node -> m (Maybe (RefactorType, Source, Span))
- Text.Reprinter: genReprinting :: (Monad m, Refactorable t, Typeable t) => (t -> m Source) -> t -> m (Maybe (RefactorType, Source, (Position, Position)))
+ Text.Reprinter: genReprinting :: (Monad m, Refactorable t, Typeable t) => (t -> m Source) -> t -> m (Maybe (RefactorType, Source, Span))
- Text.Reprinter: getSpan :: Refactorable t => t -> (Position, Position)
+ Text.Reprinter: getSpan :: Refactorable t => t -> Span
- Text.Reprinter: reprint :: (Monad m, Data p) => Reprinting m -> p -> Source -> m Source
+ Text.Reprinter: reprint :: (Monad m, Data ast) => Reprinting m -> ast -> Source -> m Source
- Text.Reprinter: type Source = ByteString
+ Text.Reprinter: type Source = Text

Files

− LICENSE
@@ -1,202 +0,0 @@--                                 Apache License-                           Version 2.0, January 2004-                        http://www.apache.org/licenses/--   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION--   1. Definitions.--      "License" shall mean the terms and conditions for use, reproduction,-      and distribution as defined by Sections 1 through 9 of this document.--      "Licensor" shall mean the copyright owner or entity authorized by-      the copyright owner that is granting the License.--      "Legal Entity" shall mean the union of the acting entity and all-      other entities that control, are controlled by, or are under common-      control with that entity. For the purposes of this definition,-      "control" means (i) the power, direct or indirect, to cause the-      direction or management of such entity, whether by contract or-      otherwise, or (ii) ownership of fifty percent (50%) or more of the-      outstanding shares, or (iii) beneficial ownership of such entity.--      "You" (or "Your") shall mean an individual or Legal Entity-      exercising permissions granted by this License.--      "Source" form shall mean the preferred form for making modifications,-      including but not limited to software source code, documentation-      source, and configuration files.--      "Object" form shall mean any form resulting from mechanical-      transformation or translation of a Source form, including but-      not limited to compiled object code, generated documentation,-      and conversions to other media types.--      "Work" shall mean the work of authorship, whether in Source or-      Object form, made available under the License, as indicated by a-      copyright notice that is included in or attached to the work-      (an example is provided in the Appendix below).--      "Derivative Works" shall mean any work, whether in Source or Object-      form, that is based on (or derived from) the Work and for which the-      editorial revisions, annotations, elaborations, or other modifications-      represent, as a whole, an original work of authorship. For the purposes-      of this License, Derivative Works shall not include works that remain-      separable from, or merely link (or bind by name) to the interfaces of,-      the Work and Derivative Works thereof.--      "Contribution" shall mean any work of authorship, including-      the original version of the Work and any modifications or additions-      to that Work or Derivative Works thereof, that is intentionally-      submitted to Licensor for inclusion in the Work by the copyright owner-      or by an individual or Legal Entity authorized to submit on behalf of-      the copyright owner. For the purposes of this definition, "submitted"-      means any form of electronic, verbal, or written communication sent-      to the Licensor or its representatives, including but not limited to-      communication on electronic mailing lists, source code control systems,-      and issue tracking systems that are managed by, or on behalf of, the-      Licensor for the purpose of discussing and improving the Work, but-      excluding communication that is conspicuously marked or otherwise-      designated in writing by the copyright owner as "Not a Contribution."--      "Contributor" shall mean Licensor and any individual or Legal Entity-      on behalf of whom a Contribution has been received by Licensor and-      subsequently incorporated within the Work.--   2. Grant of Copyright License. Subject to the terms and conditions of-      this License, each Contributor hereby grants to You a perpetual,-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable-      copyright license to reproduce, prepare Derivative Works of,-      publicly display, publicly perform, sublicense, and distribute the-      Work and such Derivative Works in Source or Object form.--   3. Grant of Patent License. Subject to the terms and conditions of-      this License, each Contributor hereby grants to You a perpetual,-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable-      (except as stated in this section) patent license to make, have made,-      use, offer to sell, sell, import, and otherwise transfer the Work,-      where such license applies only to those patent claims licensable-      by such Contributor that are necessarily infringed by their-      Contribution(s) alone or by combination of their Contribution(s)-      with the Work to which such Contribution(s) was submitted. If You-      institute patent litigation against any entity (including a-      cross-claim or counterclaim in a lawsuit) alleging that the Work-      or a Contribution incorporated within the Work constitutes direct-      or contributory patent infringement, then any patent licenses-      granted to You under this License for that Work shall terminate-      as of the date such litigation is filed.--   4. Redistribution. You may reproduce and distribute copies of the-      Work or Derivative Works thereof in any medium, with or without-      modifications, and in Source or Object form, provided that You-      meet the following conditions:--      (a) You must give any other recipients of the Work or-          Derivative Works a copy of this License; and--      (b) You must cause any modified files to carry prominent notices-          stating that You changed the files; and--      (c) You must retain, in the Source form of any Derivative Works-          that You distribute, all copyright, patent, trademark, and-          attribution notices from the Source form of the Work,-          excluding those notices that do not pertain to any part of-          the Derivative Works; and--      (d) If the Work includes a "NOTICE" text file as part of its-          distribution, then any Derivative Works that You distribute must-          include a readable copy of the attribution notices contained-          within such NOTICE file, excluding those notices that do not-          pertain to any part of the Derivative Works, in at least one-          of the following places: within a NOTICE text file distributed-          as part of the Derivative Works; within the Source form or-          documentation, if provided along with the Derivative Works; or,-          within a display generated by the Derivative Works, if and-          wherever such third-party notices normally appear. The contents-          of the NOTICE file are for informational purposes only and-          do not modify the License. You may add Your own attribution-          notices within Derivative Works that You distribute, alongside-          or as an addendum to the NOTICE text from the Work, provided-          that such additional attribution notices cannot be construed-          as modifying the License.--      You may add Your own copyright statement to Your modifications and-      may provide additional or different license terms and conditions-      for use, reproduction, or distribution of Your modifications, or-      for any such Derivative Works as a whole, provided Your use,-      reproduction, and distribution of the Work otherwise complies with-      the conditions stated in this License.--   5. Submission of Contributions. Unless You explicitly state otherwise,-      any Contribution intentionally submitted for inclusion in the Work-      by You to the Licensor shall be under the terms and conditions of-      this License, without any additional terms or conditions.-      Notwithstanding the above, nothing herein shall supersede or modify-      the terms of any separate license agreement you may have executed-      with Licensor regarding such Contributions.--   6. Trademarks. This License does not grant permission to use the trade-      names, trademarks, service marks, or product names of the Licensor,-      except as required for reasonable and customary use in describing the-      origin of the Work and reproducing the content of the NOTICE file.--   7. Disclaimer of Warranty. Unless required by applicable law or-      agreed to in writing, Licensor provides the Work (and each-      Contributor provides its Contributions) on an "AS IS" BASIS,-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or-      implied, including, without limitation, any warranties or conditions-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A-      PARTICULAR PURPOSE. You are solely responsible for determining the-      appropriateness of using or redistributing the Work and assume any-      risks associated with Your exercise of permissions under this License.--   8. Limitation of Liability. In no event and under no legal theory,-      whether in tort (including negligence), contract, or otherwise,-      unless required by applicable law (such as deliberate and grossly-      negligent acts) or agreed to in writing, shall any Contributor be-      liable to You for damages, including any direct, indirect, special,-      incidental, or consequential damages of any character arising as a-      result of this License or out of the use or inability to use the-      Work (including but not limited to damages for loss of goodwill,-      work stoppage, computer failure or malfunction, or any and all-      other commercial damages or losses), even if such Contributor-      has been advised of the possibility of such damages.--   9. Accepting Warranty or Additional Liability. While redistributing-      the Work or Derivative Works thereof, You may choose to offer,-      and charge a fee for, acceptance of support, warranty, indemnity,-      or other liability obligations and/or rights consistent with this-      License. However, in accepting such obligations, You may act only-      on Your own behalf and on Your sole responsibility, not on behalf-      of any other Contributor, and only if You agree to indemnify,-      defend, and hold each Contributor harmless for any liability-      incurred by, or claims asserted against, such Contributor by reason-      of your accepting any such warranty or additional liability.--   END OF TERMS AND CONDITIONS--   APPENDIX: How to apply the Apache License to your work.--      To apply the Apache License to your work, attach the following-      boilerplate notice, with the fields enclosed by brackets "[]"-      replaced with your own identifying information. (Don't include-      the brackets!)  The text should be enclosed in the appropriate-      comment syntax for the file format. We also recommend that a-      file or class name and description of purpose be included on the-      same "printed page" as the copyright notice for easier-      identification within third-party archives.--   Copyright 2017 Dominic Orchard--   Licensed under the Apache License, Version 2.0 (the "License");-   you may not use this file except in compliance with the License.-   You may obtain a copy of the License at--       http://www.apache.org/licenses/LICENSE-2.0--   Unless required by applicable law or agreed to in writing, software-   distributed under the License is distributed on an "AS IS" BASIS,-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-   See the License for the specific language governing permissions and-   limitations under the License.
reprinter.cabal view
@@ -1,64 +1,37 @@--- Initial reprinter.cabal generated by cabal init.  For further --- documentation, see http://haskell.org/cabal/users-guide/---- The name of the package.-name:                reprinter---- The package version.  See the Haskell package versioning policy (PVP) --- for standards guiding when and how versions should be incremented.--- https://wiki.haskell.org/Package_versioning_policy--- PVP summary:      +-+------- breaking API changes---                   | | +----- non-breaking API additions---                   | | | +--- code changes with no API change-version:             0.1.0.0---- A short (one-line) description of the package.-synopsis:            Scrap Your Reprinter--description:         A datatype generic algorithm for layout-preserving refactoring---- A longer description of the package.--- description:         -license:                Apache-2.0-license-file:           LICENSE---- The package author(s).-author:              Dominic Orchard, Harry Clarke---- An email address to which users can send suggestions, bug reports, and --- patches.-maintainer:          d.a.orchard@kent.ac.uk---- A copyright notice.--- copyright:           --category:            Text--build-type:          Simple+-- This file has been generated from package.yaml by hpack version 0.17.1.+--+-- see: https://github.com/sol/hpack --- Constraint on the version of Cabal needed to build this package.-cabal-version:       >=1.10+name:           reprinter+version:        0.2.0.0+synopsis:       Scrap Your Reprinter+description:    A datatype generic algorithm for layout-preserving refactoring+license:        Apache-2.0+author:         Dominic Orchard, Harry Clarke+maintainer:     d.a.orchard@kent.ac.uk+category:       Text+homepage:       https://github.com/camfort/reprinter#readme+bug-reports:    https://github.com/camfort/reprinter/issues+build-type:     Simple+cabal-version:  >= 1.10  source-repository head   type: git   location: https://github.com/camfort/reprinter  library-  -- Modules exported by the library.-  exposed-modules:     Text.Reprinter-  -  -- Modules included in this library but not exported.-  -- other-modules:       -  -  -- LANGUAGE extensions used by modules in this package.-  other-extensions:    RankNTypes, DeriveDataTypeable, FlexibleInstances, Rank2Types, GADTs, KindSignatures, ConstraintKinds-  -  -- Other library packages from which modules are imported.-  build-depends:       base >=4.9 && <4.10, bytestring >=0.10 && <0.11, transformers >=0.5 && <0.6, syb >=0.6 && <0.7, uniplate >=1.6 && <1.7, mtl >=2.2 && <2.3, syz == 0.2.0.0-  -  -- Directories containing source files.-  hs-source-dirs:      src-  -  -- Base language which the package is written in.-  default-language:    Haskell2010-  +  exposed-modules:+      Text.Reprinter+  other-modules:+      Paths_reprinter+  build-depends:+      base >=4.9 && <5+    , text >=1.2.2 && <2+    , transformers >=0.5 && <0.6+    , syb >=0.6 && <0.7+    , uniplate >=1.6 && <1.7+    , mtl >=2.2 && <2.3+    , syz ==0.2.0.0+  hs-source-dirs:+      src+  default-language: Haskell2010
src/Text/Reprinter.hs view
@@ -2,182 +2,245 @@ {-# LANGUAGE DeriveDataTypeable #-}  module Text.Reprinter-  ( reprint-  , splitBySpan-  , Position(..)+  (+    reprintSort+  , reprint   , Source-  , Reprinting+  , Position   , initPosition+  , initLine+  , initCol+  , mkLine+  , mkCol+  , advanceLine+  , advanceCol+  , Span+  , Reprinting   , catchAll   , genReprinting   , Refactorable(..)   , RefactorType(..)   ) where -import Data.Generics.Zipper-import Debug.Trace-import qualified Data.ByteString.Char8 as B-import Data.Data+import Control.Monad (forM) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.State.Lazy+import qualified Data.Text.Lazy as Text+import Data.Data+import Data.Generics.Zipper+import Data.Monoid ((<>), mempty)+import Data.List (sortOn) -type Source    = B.ByteString+-- | Text from source file+type Source = Text.Text -data Position = Position { posColumn :: Int, posLine :: Int }-  deriving (Data, Show)+-- | A line within the source text+newtype Line = Line Int deriving (Data, Eq, Ord, Show) -initPosition = Position { posColumn = 1, posLine = 1 }+-- | Lines start at 1+initLine :: Line+initLine = Line 1 -type Reprinting m =- forall b . Typeable b-         => b -> m (Maybe (RefactorType, Source, (Position, Position)))+-- | Smart constructor for a Line, checks that line >= 1+mkLine :: Int -> Either String Line+mkLine l+  | l < 1 = Left $ "mkLine: called with: " <> show l <> ". Minimum is 1."+  | otherwise = Right (Line  l) --- | The reprint algorithm takes a refactoring (parameteric in--- | some monad m) and turns an arbitrary pretty-printable type 'p'--- | into a monadic Source transformer.-reprint :: (Monad m, Data p)-        => Reprinting m -> p -> Source -> m Source-reprint reprinting tree input-  -- If the inupt is null then null is returned-  | B.null input = return B.empty+-- | A column within the source text+newtype Col = Col Int deriving (Data, Eq, Ord, Show) -  -- Otherwise go with the normal algorithm-  | otherwise = do-   -- Initial state comprises start cursor and input source-   let state0 = (initPosition, input)-   -- Enter the top-node of a zipper for 'tree'-   (out, (_, remaining)) <- runStateT (enter reprinting (toZipper tree)) state0-   -- Add to the output source the reamining input source-   return $ out `B.append` remaining+-- | Columns start at 1+initCol :: Col+initCol = Col 1 --- The enter, enterDown, enterRight each take a refactoring and a--- zipper producing a stateful Source transformer with Position--- state.+-- | Smart constructor for a Col, checks that column >= 1+mkCol :: Int -> Either String Col+mkCol l+  | l < 1 = Left $ "mkCol: called with: " <> show l <> ". Minimum is 1."+  | otherwise = Right (Col  l) -enter, enterDown, enterRight-  :: Monad m-  => Reprinting m -> Zipper a -> StateT (Position, Source) m Source+-- | A position in a text (imagine a cursor)+type Position = (Line,Col) --- `enter` applies the generic refactoring to the current context--- of the zipper-enter reprinting z = do+-- | The initial position+initPosition :: Position+initPosition = (initLine,initCol) -  -- Step 1.-  -- Apply a refactoring-  refactoringInfo <- lift $ query reprinting z+-- | Given a position, go down a line, going back to the initial column+advanceLine :: Position -> Position+advanceLine (Line x, _) = (Line (x+1), initCol) -  -- Step 2.-  output <--    case refactoringInfo of-      -- No refactoring, so go into the children-      Nothing -> enterDown reprinting z+-- | Given a position, advance by one column+advanceCol :: Position -> Position+advanceCol (ln, Col x) = (ln, Col (x+1)) -      -- A refactoring was applied-      Just (typ, output, (lb, ub)) -> do-        (cursor, inp) <- get-        case typ of-          Replace -> do-             -- Get the soure text up to the start of the refactored expr-             let (p0, inp') = splitBySpan (cursor, lb) inp-             -- Cut out the portion of source text consumed by the refactoring-             let (_, inp'') = splitBySpan (lb, ub) inp'-             put (ub, inp'')-             return $ B.concat [p0, output]-          After -> do-             -- Get the soure text up to the end of the refactored expr-             let (p0, inp') = splitBySpan (cursor, ub) inp-             put (ub, inp')-             return $ B.concat [p0, output]-          Before -> do-             -- Get the soure text up to the start of the refactored expr-             let (p0, inp')  = splitBySpan (cursor, lb) inp-             -- Cut out the portion of source text consumed by the refactoring-             let (p1, inp'') = splitBySpan (lb, ub) inp'-             put (ub, inp'')-             return $ B.concat [p0, output, p1]+-- | Two positions give the lower and upper bounds of a source span+type Span = (Position, Position) -  -- Part 3.-  -- Enter the right sibling of the current context-  output' <- enterRight reprinting z+-- | Type of a reprinting function+type Reprinting m = forall node . Typeable node => node -> m (Maybe (RefactorType, Source, Span)) -  -- Concat the output for the current context, children, and right sibling-  return $ B.concat [output, output']+-- | Specify a refactoring type+data RefactorType = Before | After | Replace+    deriving Show -- for debugging --- `enterDown` navigates to the children of the current context-enterDown reprinting z =-  case down' z of-    -- Go to children-    Just dz -> enter reprinting dz-    -- No children-    Nothing -> return B.empty+-- | The reprint algorithm takes a refactoring (parameteric in+-- | some monad m) and turns an arbitrary pretty-printable type 'ast'+-- | into a monadic Source transformer.+reprint :: (Monad m, Data ast) => Reprinting m -> ast -> Source -> m Source+reprint reprinting ast input+  -- If the input is empty return empty+  | Text.null input = return mempty --- `enterRight` navigates to the right sibling of the current context-enterRight reprinting z =-  case right z of-    -- Go to right sibling-    Just rz -> enter reprinting rz-    -- No right sibling-    Nothing -> return B.empty+  -- Otherwise proceed with the algorithm+  | otherwise = do+    -- Initial state comprises start cursor and input source+    let state_0 = (initPosition, input)+    -- Enter the top-node of a zipper for `ast'+    let comp = enter reprinting (toZipper ast)+    (out, (_, remaining)) <- runStateT comp state_0+    -- Add to the output source the remaining input source+    return (out <> remaining) --- | Given a lower-bound and upper-bound pair of Positions, split the--- | incoming Source based on the distanceF between the Position pairs-splitBySpan :: (Position, Position) -> Source -> (Source, Source)-splitBySpan (l, u) = subtext (ll, lc) (ll, lc) (ul, uc)-  where (Position lc ll) = l-        (Position uc ul) = u+-- | Take a refactoring and a zipper producing a stateful Source transformer with Position state.+enter :: Monad m => Reprinting m -> Zipper ast -> StateT (Position, Source) m Source+enter reprinting zipper = do+    -- Step 1: Apply a refactoring+    refactoringInfo <- lift (query reprinting zipper) -{--  Split a text.+    -- Step 2: Deal with refactored code or go to children+    output <- case refactoringInfo of+      -- No refactoring; go to children+      Nothing -> go down'+      -- A refactoring was applied+      Just r -> splice r+    -- Step 3: Enter the right sibling of the current context+    outputSib <- go right -  Returns a tuple containing:-    1. the bit of input text between upper and lower bounds-    2. the remaining input text+    -- Finally append output of current context/children+    -- and right sibling+    return (output <> outputSib) -  Takes:-    1. current cursor position-    2. lower bound-    3. upper bound-    4. input text--}-subtext :: (Int, Int) -> (Int, Int) -> (Int, Int) -> B.ByteString -> (B.ByteString, B.ByteString)-subtext cursor (lowerLn, lowerCol) (upperLn, upperCol) =-    subtext' B.empty cursor   where-    subtext' acc (cursorLn, cursorCol) input+    go direction =+        case direction zipper of+          -- Go to next node if there is one+          Just zipper -> enter reprinting zipper+          -- Otherwise return the empty string+          Nothing -> return mempty -      | cursorLn <= lowerLn && (cursorCol >= lowerCol ==> cursorLn < lowerLn) =-        case B.uncons input of-          Nothing -> (B.reverse acc, input)-          Just ('\n', input') -> subtext' acc (cursorLn+1, 1) input'-          Just (_, input')    -> subtext' acc (cursorLn, cursorCol+1) input' -      | cursorLn <= upperLn && (cursorCol >= upperCol ==> cursorLn < upperLn) =-        case B.uncons input of-          Nothing -> (B.reverse acc, input)-          Just ('\n', input') -> subtext' (B.cons '\n' acc) (cursorLn+1, 1) input'-          Just (x, input')    -> subtext' (B.cons x acc) (cursorLn, cursorCol+1) input'+-- | The reprint algorithm takes a refactoring (parameteric in+-- | some monad m) and turns an arbitrary pretty-printable type 'ast'+-- | into a monadic Source transformer.+reprintSort :: (Monad m, Data ast) => Reprinting m -> ast -> Source -> m Source+reprintSort reprinting ast input+  -- If the input is empty return empty+  | Text.null input = return mempty -      | otherwise =-        (B.reverse acc, input)+  -- Otherwise proceed with the algorithm+  | otherwise = do+    -- Initial state comprises start cursor and input source+    let state_0 = (initPosition, input)+    -- Enter the top-node of a zipper for `ast'+    let comp = enter' reprinting (toZipper ast)+    (out, (_, remaining)) <- runStateT comp state_0+    -- Add to the output source the remaining input source+    return (out <> remaining) --- Logical implication operator.-(==>) :: Bool -> Bool -> Bool; infix 2 ==>-a ==> b = a <= b --- | Specify a refactoring type-data RefactorType = Before | After | Replace+-- | Take a refactoring and a zipper to produce a list of refactorings+enter' :: Monad m => Reprinting m -> Zipper ast+      -> StateT (Position, Source) m Source+enter' reprinting zipper = do+    -- Step 1: Get refactorings via AST zipper traversal+    rs <- lift $ getRefactorings reprinting zipper []+    -- Step 2: Do the splicing on the sorted refactorings+    srcs <- mapM splice (sortBySpan . reverse $ rs)+    return $ Text.concat srcs+  where+    sortBySpan = sortOn (\(_,_,sp) -> sp) +getRefactorings :: Monad m => Reprinting m -> Zipper ast -> [(RefactorType, Source, Span)]+                    -> m [(RefactorType, Source, Span)]+getRefactorings reprinting zipper acc = do+    -- Step 1: Apply a refactoring+    refactoringInfo <- query reprinting zipper+    -- Step 2: Deal with refactored code or go to children+    acc <- case refactoringInfo of+      -- No refactoring; go to children+      Nothing -> go down' acc+      -- A refactoring was applied, add it to the accumulator+      Just r -> return (r : acc)+    -- Step 3: Enter the left sibling of the current focus+    acc <- go right acc+    -- Finally return the accumulated refactorings+    return acc++  where+    go direction acc =+        case direction zipper of+          -- Go to next node if there is one+          Just zipper -> getRefactorings reprinting zipper acc+          -- Otherwise return the empty string+          Nothing -> return acc++splice :: Monad m => (RefactorType, Source, Span) -> StateT (Position, Source) m Source+splice (typ, output, (lb, ub)) = do+    (cursor, inp) <- get+    case typ of+      Replace -> do+        -- Get soure up to start of refactored node+        let (pre, inp') = splitBySpan (cursor, lb) inp+        -- Remove source covered by refactoring+        let (_, inp'') = splitBySpan (lb, ub) inp'+        put (ub, inp'')+        return (pre <> output)+      After -> do+        -- Get source up to end of the refactored node+        let (pre, inp') = splitBySpan (cursor, ub) inp+        put (ub, inp')+        return (pre <> output)+      Before -> do+        -- Get source up to start of refactored node+        let (pre, inp') = splitBySpan (cursor, lb) inp+        -- Discard portion consumed by the refactoring+        let (post, inp'') = splitBySpan (lb, ub) inp'+        put (ub, inp'')+        return (pre <> output <> post)++-- Given a lower-bound and upper-bound pair of Positions, split the+-- incoming Source based on the distance between the Position pairs+splitBySpan :: Span -> Source -> (Source, Source)+splitBySpan (lower, upper) =+    subtext mempty lower+  where+    subtext acc cursor input+      | cursor < lower =+          case Text.uncons input of+            Nothing -> done+            Just ('\n', input') -> subtext acc (advanceLine cursor) input'+            Just (_, input')    -> subtext acc (advanceCol cursor) input'+      | cursor < upper =+          case Text.uncons input of+            Nothing -> done+            Just ('\n', input') -> subtext (Text.cons '\n' acc) (advanceLine cursor) input'+            Just (x, input')    -> subtext (Text.cons x acc) (advanceCol cursor) input'+      | otherwise = done+      where done = (Text.reverse acc, input)+++ -- | Infrastructure for building the reprinter "plugins" class Refactorable t where   isRefactored :: t -> Maybe RefactorType-  getSpan      :: t -> (Position, Position)+  getSpan      :: t -> Span  -- | Essentially wraps the refactorable interface genReprinting :: (Monad m, Refactorable t, Typeable t)-    => (t -> m Source)-    -> t -> m (Maybe (RefactorType, Source, (Position, Position)))-genReprinting f z = do-  case isRefactored z of+              => (t -> m Source) -> t -> m (Maybe (RefactorType, Source, Span))+genReprinting f z = case isRefactored z of     Nothing -> return Nothing     Just refactorType -> do       output <- f z