module Language.Haskell.Stylish.Align
( Alignable (..)
, align
) where
import Data.List (nub)
import qualified GHC.Types.SrcLoc as GHC
import qualified Language.Haskell.Stylish.Editor as Editor
import Language.Haskell.Stylish.Util
data Alignable a = Alignable
{ forall a. Alignable a -> a
aContainer :: !a
, forall a. Alignable a -> a
aLeft :: !a
, forall a. Alignable a -> a
aRight :: !a
, forall a. Alignable a -> Int
aRightLead :: !Int
} deriving (Int -> Alignable a -> ShowS
forall a. Show a => Int -> Alignable a -> ShowS
forall a. Show a => [Alignable a] -> ShowS
forall a. Show a => Alignable a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Alignable a] -> ShowS
$cshowList :: forall a. Show a => [Alignable a] -> ShowS
show :: Alignable a -> String
$cshow :: forall a. Show a => Alignable a -> String
showsPrec :: Int -> Alignable a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Alignable a -> ShowS
Show)
align
:: Maybe Int
-> [Alignable GHC.RealSrcSpan]
-> Editor.Edits
align :: Maybe Int -> [Alignable RealSrcSpan] -> Edits
align Maybe Int
_ [] = forall a. Monoid a => a
mempty
align Maybe Int
maxColumns [Alignable RealSrcSpan]
alignment
| Int -> Bool
exceedsColumns (Int
longestLeft forall a. Num a => a -> a -> a
+ Int
longestRight) = forall a. Monoid a => a
mempty
| Bool -> Bool
not ([Alignable RealSrcSpan] -> Bool
fixable [Alignable RealSrcSpan]
alignment) = forall a. Monoid a => a
mempty
| Bool
otherwise = forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap Alignable RealSrcSpan -> Edits
align' [Alignable RealSrcSpan]
alignment
where
exceedsColumns :: Int -> Bool
exceedsColumns Int
i = case Maybe Int
maxColumns of
Maybe Int
Nothing -> Bool
False
Just Int
c -> Int
i forall a. Ord a => a -> a -> Bool
> Int
c
longestLeft :: Int
longestLeft = forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map (RealSrcSpan -> Int
GHC.srcSpanEndCol forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Alignable a -> a
aLeft) [Alignable RealSrcSpan]
alignment
longestRight :: Int
longestRight = forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum
[ RealSrcSpan -> Int
GHC.srcSpanEndCol (forall a. Alignable a -> a
aRight Alignable RealSrcSpan
a) forall a. Num a => a -> a -> a
- RealSrcSpan -> Int
GHC.srcSpanStartCol (forall a. Alignable a -> a
aRight Alignable RealSrcSpan
a)
forall a. Num a => a -> a -> a
+ forall a. Alignable a -> Int
aRightLead Alignable RealSrcSpan
a
| Alignable RealSrcSpan
a <- [Alignable RealSrcSpan]
alignment
]
align' :: Alignable RealSrcSpan -> Edits
align' Alignable RealSrcSpan
a = Int -> (String -> [String]) -> Edits
Editor.changeLine (RealSrcSpan -> Int
GHC.srcSpanStartLine forall a b. (a -> b) -> a -> b
$ forall a. Alignable a -> a
aContainer Alignable RealSrcSpan
a) forall a b. (a -> b) -> a -> b
$ \String
str ->
let column :: Int
column = RealSrcSpan -> Int
GHC.srcSpanEndCol forall a b. (a -> b) -> a -> b
$ forall a. Alignable a -> a
aLeft Alignable RealSrcSpan
a
(String
pre, String
post) = forall a. Int -> [a] -> ([a], [a])
splitAt Int
column String
str
in [Int -> ShowS
padRight Int
longestLeft (ShowS
trimRight String
pre) forall a. [a] -> [a] -> [a]
++ ShowS
trimLeft String
post]
fixable :: [Alignable GHC.RealSrcSpan] -> Bool
fixable :: [Alignable RealSrcSpan] -> Bool
fixable [] = Bool
False
fixable [Alignable RealSrcSpan
_] = Bool
False
fixable [Alignable RealSrcSpan]
fields = forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all RealSrcSpan -> Bool
singleLine [RealSrcSpan]
containers Bool -> Bool -> Bool
&& [RealSrcSpan] -> Bool
nonOverlapping [RealSrcSpan]
containers
where
containers :: [RealSrcSpan]
containers = forall a b. (a -> b) -> [a] -> [b]
map forall a. Alignable a -> a
aContainer [Alignable RealSrcSpan]
fields
singleLine :: RealSrcSpan -> Bool
singleLine RealSrcSpan
s = RealSrcSpan -> Int
GHC.srcSpanStartLine RealSrcSpan
s forall a. Eq a => a -> a -> Bool
== RealSrcSpan -> Int
GHC.srcSpanEndLine RealSrcSpan
s
nonOverlapping :: [RealSrcSpan] -> Bool
nonOverlapping [RealSrcSpan]
ss = forall (t :: * -> *) a. Foldable t => t a -> Int
length [RealSrcSpan]
ss forall a. Eq a => a -> a -> Bool
== forall (t :: * -> *) a. Foldable t => t a -> Int
length (forall a. Eq a => [a] -> [a]
nub forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map RealSrcSpan -> Int
GHC.srcSpanStartLine [RealSrcSpan]
ss)