summaryrefslogtreecommitdiffhomepage
path: root/lib
diff options
context:
space:
mode:
authorJasper Van der Jeugt <m@jaspervdj.be>2016-07-03 14:17:33 +0200
committerJasper Van der Jeugt <m@jaspervdj.be>2016-07-03 18:15:57 +0200
commitd56edbd043ac3d6f67d9f8cdf54b2c826f6da2e2 (patch)
tree01ec7e3c1d5b04148161aa3833c7c0cb31ea6fcd /lib
parentad677e6a22d22041d83162e714c5551c9a4d62d8 (diff)
downloadstylish-haskell-d56edbd043ac3d6f67d9f8cdf54b2c826f6da2e2.tar.gz
Put Align in a separate helper module
Diffstat (limited to 'lib')
-rw-r--r--lib/Language/Haskell/Stylish/Align.hs96
-rw-r--r--lib/Language/Haskell/Stylish/Step/Records.hs66
2 files changed, 99 insertions, 63 deletions
diff --git a/lib/Language/Haskell/Stylish/Align.hs b/lib/Language/Haskell/Stylish/Align.hs
new file mode 100644
index 0000000..bfee9d2
--- /dev/null
+++ b/lib/Language/Haskell/Stylish/Align.hs
@@ -0,0 +1,96 @@
+--------------------------------------------------------------------------------
+-- | This module is useful for aligning things.
+module Language.Haskell.Stylish.Align
+ ( Alignable (..)
+ , align
+ ) where
+
+
+--------------------------------------------------------------------------------
+import Data.Char (isSpace)
+import Data.List (nub)
+import qualified Language.Haskell.Exts.Annotated as H
+
+
+--------------------------------------------------------------------------------
+import Language.Haskell.Stylish.Editor
+import Language.Haskell.Stylish.Util
+
+
+--------------------------------------------------------------------------------
+-- | This represent a single line which can be aligned. We have something on
+-- the left and the right side, e.g.:
+--
+-- > [x] -> x + 1
+-- > ^^^^ ^^^^^
+-- > LEFT RIGHT
+--
+-- We also have the container which holds the entire line:
+--
+-- > [x] -> x + 1
+-- > ^^^^^^^^^^^^^
+-- > CONTAINER
+--
+-- And then we have a "right lead" which is just represented by an 'Int', since
+-- @haskell-src-exts@ often does not allow us to access it. In the example this
+-- is:
+--
+-- > [x] -> x + 1
+-- > ^^^
+-- > RLEAD
+--
+-- This info is enough to align a bunch of these lines. Users of this module
+-- should construct a list of 'Alignable's representing whatever they want to
+-- align, and then call 'align' on that.
+data Alignable a = Alignable
+ { aContainer :: !a
+ , aLeft :: !a
+ , aRight :: !a
+ -- | This is the minimal number of columns we need for the leading part not
+ -- included in our right string. For example, for datatype alignment, this
+ -- leading part is the string ":: " so we use 3.
+ , aRightLead :: !Int
+ } deriving (Show)
+
+
+--------------------------------------------------------------------------------
+-- | Create changes that perform the alignment.
+align
+ :: Int -- ^ Max columns
+ -> [Alignable H.SrcSpan] -- ^ Alignables
+ -> [Change String] -- ^ Changes performing the alignment.
+align maxColumns alignment
+ -- Do not make any change if we would go past the maximum number of columns.
+ | longestLeft + longestRight > maxColumns = []
+ | not (fixable alignment) = []
+ | otherwise = map align' alignment
+ where
+ -- The longest thing in the left column.
+ longestLeft = maximum $ map (H.srcSpanEndColumn . aLeft) alignment
+
+ -- The longest thing in the right column.
+ longestRight = maximum
+ [ H.srcSpanEndColumn (aRight a) - H.srcSpanStartColumn (aRight a)
+ + aRightLead a
+ | a <- alignment
+ ]
+
+ align' a = changeLine (H.srcSpanStartLine $ aContainer a) $ \str ->
+ let column = H.srcSpanEndColumn $ aLeft a
+ (pre, post) = splitAt column str
+ in [padRight longestLeft (trimRight pre) ++ trimLeft post]
+
+ trimLeft = dropWhile isSpace
+ trimRight = reverse . trimLeft . reverse
+
+
+--------------------------------------------------------------------------------
+-- | Checks that all the alignables appear on a single line, and that they do
+-- not overlap.
+fixable :: [Alignable H.SrcSpan] -> Bool
+fixable [] = False
+fixable fields = all singleLine containers && nonOverlapping containers
+ where
+ containers = map aContainer fields
+ singleLine s = H.srcSpanStartLine s == H.srcSpanEndLine s
+ nonOverlapping ss = length ss == length (nub $ map H.srcSpanStartLine ss)
diff --git a/lib/Language/Haskell/Stylish/Step/Records.hs b/lib/Language/Haskell/Stylish/Step/Records.hs
index 1c46024..bbfb895 100644
--- a/lib/Language/Haskell/Stylish/Step/Records.hs
+++ b/lib/Language/Haskell/Stylish/Step/Records.hs
@@ -5,15 +5,13 @@ module Language.Haskell.Stylish.Step.Records
--------------------------------------------------------------------------------
-import Data.Char (isSpace)
-import Data.List (nub)
import qualified Language.Haskell.Exts.Annotated as H
--------------------------------------------------------------------------------
+import Language.Haskell.Stylish.Align
import Language.Haskell.Stylish.Editor
import Language.Haskell.Stylish.Step
-import Language.Haskell.Stylish.Util
--------------------------------------------------------------------------------
@@ -27,18 +25,6 @@ records modu =
--------------------------------------------------------------------------------
-data Alignable a = Alignable
- { aContainer :: !a
- , aLeft :: !a
- , aRight :: !a
- -- | This is the minimal number of columns we need for the leading part not
- -- included in our right string. For example, for datatype alignment, this
- -- leading part is the string ":: " so we use 3.
- , aRightLead :: !Int
- } deriving (Show)
-
-
---------------------------------------------------------------------------------
fieldDeclToAlignable :: H.FieldDecl a -> Alignable a
fieldDeclToAlignable (H.FieldDecl ann names ty) = Alignable
{ aContainer = ann
@@ -49,53 +35,7 @@ fieldDeclToAlignable (H.FieldDecl ann names ty) = Alignable
--------------------------------------------------------------------------------
--- | Align the type of a field
-align :: Int -> [Alignable H.SrcSpan] -> [Change String]
-align maxColumns alignment
- -- Do not make any change if we would go past the maximum number of columns.
- | longestLeft + longestRight > maxColumns = info []
- | otherwise = info $ map align' alignment
- where
- info =
- id
- -- trace ("Alignable: " ++ show alignment) .
- -- trace ("longestLeft: " ++ show longestLeft) .
- -- trace ("longestRight: " ++ show longestRight)
-
- -- The longest thing in the left column.
- longestLeft = maximum $ map (H.srcSpanEndColumn . aLeft) alignment
-
- -- The longest thing in the right column.
- longestRight = maximum
- [ H.srcSpanEndColumn (aRight a) - H.srcSpanStartColumn (aRight a)
- + aRightLead a
- | a <- alignment
- ]
-
- align' a = changeLine (H.srcSpanStartLine $ aContainer a) $ \str ->
- let column = H.srcSpanEndColumn $ aLeft a
- (pre, post) = splitAt column str
- in [padRight longestLeft (trimRight pre) ++ trimLeft post]
-
- trimLeft = dropWhile isSpace
- trimRight = reverse . trimLeft . reverse
-
-
---------------------------------------------------------------------------------
--- | Checks that all no field of the record appears on more than one line,
--- amonst other things
-fixable :: [Alignable H.SrcSpan] -> Bool
-fixable [] = False
-fixable fields = all singleLine containers && nonOverlapping containers
- where
- containers = map aContainer fields
- singleLine s = H.srcSpanStartLine s == H.srcSpanEndLine s
- nonOverlapping ss = length ss == length (nub $ map H.srcSpanStartLine ss)
-
-
---------------------------------------------------------------------------------
step :: Int -> Step
step maxColumns = makeStep "Records" $ \ls (module', _) ->
- let module'' = fmap H.srcInfoSpan module'
- fixableRecords = filter fixable $ records module''
- in applyChanges (fixableRecords >>= align maxColumns) ls
+ let module'' = fmap H.srcInfoSpan module' in
+ applyChanges (records module'' >>= align maxColumns) ls