{-# LANGUAGE RankNTypes #-}
module Camfort.Reprint
( reprint
, subtext
, takeBounds
) where
import Data.Generics.Zipper
import Camfort.Helpers
import qualified Data.ByteString.Char8 as B
import Data.Data
import Control.Monad.Trans.State.Lazy
import Control.Monad.Trans.Class (lift)
import qualified Language.Fortran.Util.Position as FU
type Refactored = Bool
type Refactoring m =
forall b . Typeable b
=> b -> SourceText -> StateT FU.Position m (SourceText, Refactored)
reprint :: (Monad m, Data p)
=> Refactoring m -> p -> SourceText -> m SourceText
reprint :: Refactoring m -> p -> SourceText -> m SourceText
reprint Refactoring m
refactoring p
tree SourceText
input
| SourceText -> Bool
B.null SourceText
input = SourceText -> m SourceText
forall (m :: * -> *) a. Monad m => a -> m a
return SourceText
B.empty
| Bool
otherwise = do
let cursor0 :: Position
cursor0 = Position
FU.initPosition
(SourceText
out, (Position
_, SourceText
remaining)) <- StateT (Position, SourceText) m SourceText
-> (Position, SourceText) -> m (SourceText, (Position, SourceText))
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT (Refactoring m
-> Zipper p -> StateT (Position, SourceText) m SourceText
forall (m :: * -> *) a.
Monad m =>
Refactoring m
-> Zipper a -> StateT (Position, SourceText) m SourceText
enter Refactoring m
refactoring (p -> Zipper p
forall a. Data a => a -> Zipper a
toZipper p
tree)) (Position
cursor0, SourceText
input)
SourceText -> m SourceText
forall (m :: * -> *) a. Monad m => a -> m a
return (SourceText -> m SourceText) -> SourceText -> m SourceText
forall a b. (a -> b) -> a -> b
$ SourceText
out SourceText -> SourceText -> SourceText
`B.append` SourceText
remaining
enter, enterDown, enterRight
:: Monad m
=> Refactoring m -> Zipper a -> StateT (FU.Position, SourceText) m SourceText
enter :: Refactoring m
-> Zipper a -> StateT (Position, SourceText) m SourceText
enter Refactoring m
refactoring Zipper a
z = do
(Position
cursor, SourceText
inp) <- StateT (Position, SourceText) m (Position, SourceText)
forall (m :: * -> *) s. Monad m => StateT s m s
get
((SourceText
p1, Bool
refactored), Position
cursor') <- m ((SourceText, Bool), Position)
-> StateT (Position, SourceText) m ((SourceText, Bool), Position)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m ((SourceText, Bool), Position)
-> StateT (Position, SourceText) m ((SourceText, Bool), Position))
-> m ((SourceText, Bool), Position)
-> StateT (Position, SourceText) m ((SourceText, Bool), Position)
forall a b. (a -> b) -> a -> b
$ StateT Position m (SourceText, Bool)
-> Position -> m ((SourceText, Bool), Position)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT (GenericQ (StateT Position m (SourceText, Bool))
-> Zipper a -> StateT Position m (SourceText, Bool)
forall b a. GenericQ b -> Zipper a -> b
query (a -> SourceText -> StateT Position m (SourceText, Bool)
Refactoring m
`refactoring` SourceText
inp) Zipper a
z) Position
cursor
SourceText
p2 <- if Bool
refactored
then do
(SourceText
_, SourceText
inp') <- (SourceText, SourceText)
-> StateT (Position, SourceText) m (SourceText, SourceText)
forall (m :: * -> *) a. Monad m => a -> m a
return ((SourceText, SourceText)
-> StateT (Position, SourceText) m (SourceText, SourceText))
-> (SourceText, SourceText)
-> StateT (Position, SourceText) m (SourceText, SourceText)
forall a b. (a -> b) -> a -> b
$ (Position, Position) -> SourceText -> (SourceText, SourceText)
takeBounds (Position
cursor, Position
cursor') SourceText
inp
(Position, SourceText) -> StateT (Position, SourceText) m ()
forall (m :: * -> *) s. Monad m => s -> StateT s m ()
put (Position
cursor', SourceText
inp')
SourceText -> StateT (Position, SourceText) m SourceText
forall (m :: * -> *) a. Monad m => a -> m a
return SourceText
B.empty
else do
(Position, SourceText) -> StateT (Position, SourceText) m ()
forall (m :: * -> *) s. Monad m => s -> StateT s m ()
put (Position
cursor', SourceText
inp)
Refactoring m
-> Zipper a -> StateT (Position, SourceText) m SourceText
forall (m :: * -> *) a.
Monad m =>
Refactoring m
-> Zipper a -> StateT (Position, SourceText) m SourceText
enterDown Refactoring m
refactoring Zipper a
z
SourceText
p3 <- Refactoring m
-> Zipper a -> StateT (Position, SourceText) m SourceText
forall (m :: * -> *) a.
Monad m =>
Refactoring m
-> Zipper a -> StateT (Position, SourceText) m SourceText
enterRight Refactoring m
refactoring Zipper a
z
SourceText -> StateT (Position, SourceText) m SourceText
forall (m :: * -> *) a. Monad m => a -> m a
return (SourceText -> StateT (Position, SourceText) m SourceText)
-> SourceText -> StateT (Position, SourceText) m SourceText
forall a b. (a -> b) -> a -> b
$ [SourceText] -> SourceText
B.concat [SourceText
p1, SourceText
p2, SourceText
p3]
enterDown :: Refactoring m
-> Zipper a -> StateT (Position, SourceText) m SourceText
enterDown Refactoring m
refactoring Zipper a
z =
case Zipper a -> Maybe (Zipper a)
forall a. Zipper a -> Maybe (Zipper a)
down' Zipper a
z of
Just Zipper a
dz -> Refactoring m
-> Zipper a -> StateT (Position, SourceText) m SourceText
forall (m :: * -> *) a.
Monad m =>
Refactoring m
-> Zipper a -> StateT (Position, SourceText) m SourceText
enter Refactoring m
refactoring Zipper a
dz
Maybe (Zipper a)
Nothing -> SourceText -> StateT (Position, SourceText) m SourceText
forall (m :: * -> *) a. Monad m => a -> m a
return SourceText
B.empty
enterRight :: Refactoring m
-> Zipper a -> StateT (Position, SourceText) m SourceText
enterRight Refactoring m
refactoring Zipper a
z =
case Zipper a -> Maybe (Zipper a)
forall a. Zipper a -> Maybe (Zipper a)
right Zipper a
z of
Just Zipper a
rz -> Refactoring m
-> Zipper a -> StateT (Position, SourceText) m SourceText
forall (m :: * -> *) a.
Monad m =>
Refactoring m
-> Zipper a -> StateT (Position, SourceText) m SourceText
enter Refactoring m
refactoring Zipper a
rz
Maybe (Zipper a)
Nothing -> SourceText -> StateT (Position, SourceText) m SourceText
forall (m :: * -> *) a. Monad m => a -> m a
return SourceText
B.empty
takeBounds :: (FU.Position, FU.Position) -> SourceText -> (SourceText, SourceText)
takeBounds :: (Position, Position) -> SourceText -> (SourceText, SourceText)
takeBounds (Position
l, Position
u) = (Int, Int)
-> (Int, Int)
-> (Int, Int)
-> SourceText
-> (SourceText, SourceText)
subtext (Int
ll, Int
lc) (Int
ll, Int
lc) (Int
ul, Int
uc)
where (FU.Position Int
_ Int
lc Int
ll String
_ Maybe (Int, String)
_) = Position
l
(FU.Position Int
_ Int
uc Int
ul String
_ Maybe (Int, String)
_) = Position
u
subtext :: (Int, Int) -> (Int, Int) -> (Int, Int) -> B.ByteString -> (B.ByteString, B.ByteString)
subtext :: (Int, Int)
-> (Int, Int)
-> (Int, Int)
-> SourceText
-> (SourceText, SourceText)
subtext (Int, Int)
cursor (Int
lowerLn, Int
lowerCol) (Int
upperLn, Int
upperCol) =
SourceText -> (Int, Int) -> SourceText -> (SourceText, SourceText)
subtext' SourceText
B.empty (Int, Int)
cursor
where
subtext' :: SourceText -> (Int, Int) -> SourceText -> (SourceText, SourceText)
subtext' SourceText
acc (Int
cursorLn, Int
cursorCol) SourceText
input
| Int
cursorLn Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
lowerLn Bool -> Bool -> Bool
&& (Int
cursorCol Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
lowerCol Bool -> Bool -> Bool
==> Int
cursorLn Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
lowerLn) =
case SourceText -> Maybe (Char, SourceText)
B.uncons SourceText
input of
Maybe (Char, SourceText)
Nothing -> (SourceText -> SourceText
B.reverse SourceText
acc, SourceText
input)
Just (Char
'\n', SourceText
input') -> SourceText -> (Int, Int) -> SourceText -> (SourceText, SourceText)
subtext' SourceText
acc (Int
cursorLnInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1, Int
1) SourceText
input'
Just (Char
_, SourceText
input') -> SourceText -> (Int, Int) -> SourceText -> (SourceText, SourceText)
subtext' SourceText
acc (Int
cursorLn, Int
cursorColInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) SourceText
input'
| Int
cursorLn Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
upperLn Bool -> Bool -> Bool
&& (Int
cursorCol Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
upperCol Bool -> Bool -> Bool
==> Int
cursorLn Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
upperLn) =
case SourceText -> Maybe (Char, SourceText)
B.uncons SourceText
input of
Maybe (Char, SourceText)
Nothing -> (SourceText -> SourceText
B.reverse SourceText
acc, SourceText
input)
Just (Char
'\n', SourceText
input') -> SourceText -> (Int, Int) -> SourceText -> (SourceText, SourceText)
subtext' (Char -> SourceText -> SourceText
B.cons Char
'\n' SourceText
acc) (Int
cursorLnInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1, Int
1) SourceText
input'
Just (Char
x, SourceText
input') -> SourceText -> (Int, Int) -> SourceText -> (SourceText, SourceText)
subtext' (Char -> SourceText -> SourceText
B.cons Char
x SourceText
acc) (Int
cursorLn, Int
cursorColInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) SourceText
input'
| Bool
otherwise =
(SourceText -> SourceText
B.reverse SourceText
acc, SourceText
input)
(==>) :: Bool -> Bool -> Bool; infix 2 ==>
Bool
a ==> :: Bool -> Bool -> Bool
==> Bool
b = Bool
a Bool -> Bool -> Bool
forall a. Ord a => a -> a -> Bool
<= Bool
b