Skip to content

Commit 250e709

Browse files
jaspervdjVBeatriceEncodePandalukasz-golebiewskifelixmulder
committed
Use ghc-lib-parser rather than haskell-src-exts
This patch swaps out the parsing library from `haskell-src-exts` to `ghc-lib-parser`, which gives us better compatibility with GHC. Because almost every module heavily used the Haskell AST provided by `haskell-src-exts`, this was a huge effort and it would not have been possible without Felix Mulder doing an initial port, GSoC student Beatrice Vergani porting several other steps, and Łukasz Gołębiewski and Paweł Szulc who helped me finish up things in the home stretch. I've generally tried to keep styling 100% compatible with what was there before, but some issues may have unintentionally slipped in so please report those. This introduces one new import styling contributed by Felix: when wrapping import lists over multiple lines, you can repeat the module name, e.g.: import Control.Monad.Except as X (ExceptT (..), MonadError (..), liftEither) import Control.Monad.Except as X (runExceptT, withExceptT) This is activated by using `import_align: repeat`. Secondly, a new Step was added, `module_header`, which formats the export list of a module, including the trailing `where` clause. Details for this new step can be found in the `data/stylish-haskell.yaml`. Co-Authored-By: Beatrice Vergani <[email protected]> Co-Authored-By: Paweł Szulc <[email protected]> Co-Authored-By: Łukasz Gołębiewski <[email protected]> Co-Authored-By: Felix Mulder <[email protected]>
1 parent ce3feb1 commit 250e709

File tree

35 files changed

+4591
-1257
lines changed

35 files changed

+4591
-1257
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919

2020
- uses: actions/checkout@v2
2121

22-
- uses: actions/[email protected]
22+
- uses: actions/[email protected].2
2323
name: Setup Haskell Stack
2424
with:
2525
ghc-version: ${{ matrix.ghc }}
@@ -29,7 +29,7 @@ jobs:
2929
name: Cache ~/.stack
3030
with:
3131
path: ~/.stack
32-
key: ${{ runner.os }}-${{ matrix.ghc }}-v2
32+
key: ${{ runner.os }}-${{ matrix.ghc }}-v3
3333

3434
- name: Add ~/.local/bin to PATH
3535
run: echo "::add-path::$HOME/.local/bin"

data/stylish-haskell.yaml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@ steps:
1515
# # true.
1616
# add_language_pragma: true
1717

18+
# Format module header
19+
#
20+
# Currently, this option is not configurable and will format all exports and
21+
# module declarations to minimize diffs
22+
#
23+
# - module_header:
24+
# # How many spaces use for indentation in the module header.
25+
# indent: 4
26+
#
27+
# # Should export lists be sorted? Sorting is only performed within the
28+
# # export section, as delineated by Haddock comments.
29+
# sort: true
30+
1831
# Format record definitions. This is disabled by default.
1932
#
2033
# You can control the layout of record fields. The only rules that can't be configured
@@ -42,6 +55,31 @@ steps:
4255
#
4356
# # How many spaces to insert before "deriving" clause. Deriving clauses are always on separate lines.
4457
# deriving: 2
58+
#
59+
# # How many spaces to insert before "via" clause counted from indentation of deriving clause
60+
# # Possible values:
61+
# # - "same_line" -- "{" and first field goes on the same line as the data constructor.
62+
# # - "indent N" -- insert a new line and N spaces from the beginning of the data constructor
63+
# via: "indent 2"
64+
#
65+
# # Wheter or not to break enums onto several lines
66+
# #
67+
# # Default: false
68+
# break_enums: false
69+
#
70+
# # Whether or not to break single constructor data types before `=` sign
71+
# #
72+
# # Default: true
73+
# break_single_constructors: true
74+
#
75+
# # Whether or not to curry constraints on function.
76+
# #
77+
# # E.g: @allValues :: Enum a => Bounded a => Proxy a -> [a]@
78+
# #
79+
# # Instead of @allValues :: (Enum a, Bounded a) => Proxy a -> [a]@
80+
# #
81+
# # Default: false
82+
# curried_context: false
4583

4684
# Align the right hand side of some elements. This is quite conservative
4785
# and only applies to statements where each element occupies a single
@@ -101,6 +139,11 @@ steps:
101139
# > import qualified Data.List as List
102140
# > (concat, foldl, foldr, head, init, last, length)
103141
#
142+
# - repeat: Repeat the module name to align the import list.
143+
#
144+
# > import qualified Data.List as List (concat, foldl, foldr, head)
145+
# > import qualified Data.List as List (init, last, length)
146+
#
104147
# Default: after_alias
105148
list_align: after_alias
106149

@@ -203,6 +246,22 @@ steps:
203246
# Default: false
204247
space_surround: false
205248

249+
# Enabling this argument will use the new GHC lib parse to format imports.
250+
#
251+
# This currently assumes a few things, it will assume that you want post
252+
# qualified imports. It is also not as feature complete as the old
253+
# imports formatting.
254+
#
255+
# It does not remove redundant lines or merge lines. As such, the full
256+
# feature scope is still pending.
257+
#
258+
# It _is_ however, a fine alternative if you are using features that are
259+
# not parseable by haskell src extensions and you're comfortable with the
260+
# presets.
261+
#
262+
# Default: false
263+
ghc_lib_parser: false
264+
206265
# Language pragmas
207266
- language_pragmas:
208267
# We can generate different styles of language pragma lists.

lib/Language/Haskell/Stylish.hs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,19 @@ unicodeSyntax = UnicodeSyntax.step
9191

9292
--------------------------------------------------------------------------------
9393
runStep :: Extensions -> Maybe FilePath -> Lines -> Step -> Either String Lines
94-
runStep exts mfp ls step =
95-
stepFilter step ls <$> parseModule exts mfp (unlines ls)
96-
94+
runStep exts mfp ls = \case
95+
Step _name step ->
96+
step ls <$> parseModule exts mfp (unlines ls)
9797

9898
--------------------------------------------------------------------------------
99-
runSteps :: Extensions -> Maybe FilePath -> [Step] -> Lines
100-
-> Either String Lines
101-
runSteps exts mfp steps ls = foldM (runStep exts mfp) ls steps
99+
runSteps ::
100+
Extensions
101+
-> Maybe FilePath
102+
-> [Step]
103+
-> Lines
104+
-> Either String Lines
105+
runSteps exts mfp steps ls =
106+
foldM (runStep exts mfp) ls steps
102107

103108
newtype ConfigPath = ConfigPath { unConfigPath :: FilePath }
104109

lib/Language/Haskell/Stylish/Align.hs

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module Language.Haskell.Stylish.Align
88

99
--------------------------------------------------------------------------------
1010
import Data.List (nub)
11-
import qualified Language.Haskell.Exts as H
11+
import qualified SrcLoc as S
1212

1313

1414
--------------------------------------------------------------------------------
@@ -51,49 +51,48 @@ data Alignable a = Alignable
5151
, aRightLead :: !Int
5252
} deriving (Show)
5353

54-
5554
--------------------------------------------------------------------------------
5655
-- | Create changes that perform the alignment.
56+
5757
align
58-
:: Maybe Int -- ^ Max columns
59-
-> [Alignable H.SrcSpan] -- ^ Alignables
60-
-> [Change String] -- ^ Changes performing the alignment.
58+
:: Maybe Int -- ^ Max columns
59+
-> [Alignable S.RealSrcSpan] -- ^ Alignables
60+
-> [Change String] -- ^ Changes performing the alignment
6161
align _ [] = []
6262
align maxColumns alignment
63-
-- Do not make any change if we would go past the maximum number of columns.
64-
| exceedsColumns (longestLeft + longestRight) = []
65-
| not (fixable alignment) = []
66-
| otherwise = map align' alignment
63+
-- Do not make an changes if we would go past the maximum number of columns
64+
| exceedsColumns (longestLeft + longestRight) = []
65+
| not (fixable alignment) = []
66+
| otherwise = map align' alignment
6767
where
6868
exceedsColumns i = case maxColumns of
69-
Nothing -> False -- No number exceeds a maximum column count of
70-
-- Nothing, because there is no limit to exceed.
71-
Just c -> i > c
69+
Nothing -> False
70+
Just c -> i > c
7271

73-
-- The longest thing in the left column.
74-
longestLeft = maximum $ map (H.srcSpanEndColumn . aLeft) alignment
72+
-- The longest thing in the left column
73+
longestLeft = maximum $ map (S.srcSpanEndCol . aLeft) alignment
7574

76-
-- The longest thing in the right column.
75+
-- The longest thing in the right column
7776
longestRight = maximum
78-
[ H.srcSpanEndColumn (aRight a) - H.srcSpanStartColumn (aRight a)
79-
+ aRightLead a
80-
| a <- alignment
81-
]
82-
83-
align' a = changeLine (H.srcSpanStartLine $ aContainer a) $ \str ->
84-
let column = H.srcSpanEndColumn $ aLeft a
85-
(pre, post) = splitAt column str
86-
in [padRight longestLeft (trimRight pre) ++ trimLeft post]
77+
[ S.srcSpanEndCol (aRight a) - S.srcSpanStartCol (aRight a)
78+
+ aRightLead a
79+
| a <- alignment
80+
]
8781

82+
align' a = changeLine (S.srcSpanStartLine $ aContainer a) $ \str ->
83+
let column = S.srcSpanEndCol $ aLeft a
84+
(pre, post) = splitAt column str
85+
in [padRight longestLeft (trimRight pre) ++ trimLeft post]
8886

8987
--------------------------------------------------------------------------------
9088
-- | Checks that all the alignables appear on a single line, and that they do
9189
-- not overlap.
92-
fixable :: [Alignable H.SrcSpan] -> Bool
90+
91+
fixable :: [Alignable S.RealSrcSpan] -> Bool
9392
fixable [] = False
9493
fixable [_] = False
9594
fixable fields = all singleLine containers && nonOverlapping containers
9695
where
9796
containers = map aContainer fields
98-
singleLine s = H.srcSpanStartLine s == H.srcSpanEndLine s
99-
nonOverlapping ss = length ss == length (nub $ map H.srcSpanStartLine ss)
97+
singleLine s = S.srcSpanStartLine s == S.srcSpanEndLine s
98+
nonOverlapping ss = length ss == length (nub $ map S.srcSpanStartLine ss)

lib/Language/Haskell/Stylish/Block.hs

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,26 @@ module Language.Haskell.Stylish.Block
44
, LineBlock
55
, SpanBlock
66
, blockLength
7-
, linesFromSrcSpan
8-
, spanFromSrcSpan
97
, moveBlock
108
, adjacent
119
, merge
10+
, mergeAdjacent
1211
, overlapping
1312
, groupAdjacent
1413
) where
1514

1615

1716
--------------------------------------------------------------------------------
18-
import Control.Arrow (arr, (&&&), (>>>))
19-
import qualified Data.IntSet as IS
20-
import qualified Language.Haskell.Exts as H
17+
import qualified Data.IntSet as IS
2118

2219

2320
--------------------------------------------------------------------------------
2421
-- | Indicates a line span
2522
data Block a = Block
2623
{ blockStart :: Int
2724
, blockEnd :: Int
28-
} deriving (Eq, Ord, Show)
25+
}
26+
deriving (Eq, Ord, Show)
2927

3028

3129
--------------------------------------------------------------------------------
@@ -40,21 +38,6 @@ type SpanBlock = Block Char
4038
blockLength :: Block a -> Int
4139
blockLength (Block start end) = end - start + 1
4240

43-
44-
--------------------------------------------------------------------------------
45-
linesFromSrcSpan :: H.SrcSpanInfo -> LineBlock
46-
linesFromSrcSpan = H.srcInfoSpan >>>
47-
H.srcSpanStartLine &&& H.srcSpanEndLine >>>
48-
arr (uncurry Block)
49-
50-
51-
--------------------------------------------------------------------------------
52-
spanFromSrcSpan :: H.SrcSpanInfo -> SpanBlock
53-
spanFromSrcSpan = H.srcInfoSpan >>>
54-
H.srcSpanStartColumn &&& H.srcSpanEndColumn >>>
55-
arr (uncurry Block)
56-
57-
5841
--------------------------------------------------------------------------------
5942
moveBlock :: Int -> Block a -> Block a
6043
moveBlock offset (Block start end) = Block (start + offset) (end + offset)
@@ -94,3 +77,8 @@ groupAdjacent = foldr go []
9477
go (b1, x) gs = case break (adjacent b1 . fst) gs of
9578
(_, []) -> (b1, [x]) : gs
9679
(ys, ((b2, xs) : zs)) -> (merge b1 b2, x : xs) : (ys ++ zs)
80+
81+
mergeAdjacent :: [Block a] -> [Block a]
82+
mergeAdjacent (a : b : rest) | a `adjacent` b = merge a b : mergeAdjacent rest
83+
mergeAdjacent (a : rest) = a : mergeAdjacent rest
84+
mergeAdjacent [] = []

0 commit comments

Comments
 (0)