Skip to content

Commit 23aaaa1

Browse files
committed
Add support for post qualified import formatting.
Adds an option to use post qualified module imports. Related to haskell#284 Resolves haskell#334
1 parent 2d54b73 commit 23aaaa1

File tree

4 files changed

+102
-42
lines changed

4 files changed

+102
-42
lines changed

data/stylish-haskell.yaml

+14-10
Original file line numberDiff line numberDiff line change
@@ -261,21 +261,25 @@ steps:
261261
# Default: false
262262
space_surround: false
263263

264-
# Enabling this argument will use the new GHC lib parse to format imports.
264+
# Post qualify option moves any qualifies found in import declarations
265+
# to the end of the declaration. This also adjust padding for any
266+
# unqualified import declarations.
265267
#
266-
# This currently assumes a few things, it will assume that you want post
267-
# qualified imports. It is also not as feature complete as the old
268-
# imports formatting.
268+
# - true: Qualified as <module name> is moved to the end of the
269+
# declaration.
269270
#
270-
# It does not remove redundant lines or merge lines. As such, the full
271-
# feature scope is still pending.
271+
# > import Data.Bar
272+
# > import Data.Foo qualified as F
272273
#
273-
# It _is_ however, a fine alternative if you are using features that are
274-
# not parseable by haskell src extensions and you're comfortable with the
275-
# presets.
274+
# - false: Qualified remains in the default location and unqualified
275+
# imports are padded to align with qualified imports.
276+
#
277+
# > import Data.Bar
278+
# > import qualified Data.Foo as F
276279
#
277280
# Default: false
278-
ghc_lib_parser: false
281+
post_qualify: false
282+
279283

280284
# Language pragmas
281285
- language_pragmas:

lib/Language/Haskell/Stylish/Config.hs

+1
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ parseImports config o = fmap (Imports.step columns) $ Imports.Options
274274
<*> (o A..:? "list_padding" >>= maybe (pure $ def Imports.listPadding) parseListPadding)
275275
<*> o A..:? "separate_lists" A..!= def Imports.separateLists
276276
<*> o A..:? "space_surround" A..!= def Imports.spaceSurround
277+
<*> o A..:? "post_qualify" A..!= def Imports.postQualified
277278
where
278279
def f = f Imports.defaultOptions
279280

lib/Language/Haskell/Stylish/Step/Imports.hs

+20-8
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ data Options = Options
6161
, listPadding :: ListPadding
6262
, separateLists :: Bool
6363
, spaceSurround :: Bool
64+
, postQualified :: Bool
6465
} deriving (Eq, Show)
6566

6667
defaultOptions :: Options
@@ -73,6 +74,7 @@ defaultOptions = Options
7374
, listPadding = LPConstant 4
7475
, separateLists = True
7576
, spaceSurround = False
77+
, postQualified = False
7678
}
7779

7880
data ListPadding
@@ -143,8 +145,8 @@ formatImports
143145
-> NonEmpty (Located Import) -> Lines
144146
formatImports maxCols options m moduleStats rawGroup =
145147
runPrinter_ (PrinterConfig maxCols) [] m do
146-
let
147-
148+
let
149+
148150
group
149151
= NonEmpty.sortWith unLocated rawGroup
150152
& mergeImports
@@ -177,10 +179,10 @@ printQualified Options{..} padNames stats (L _ decl) = do
177179

178180
when (isSafe decl) (putText "safe" >> space)
179181

180-
case (isQualified decl, isAnyQualified stats) of
181-
(True, _) -> putText "qualified" >> space
182-
(_, True) -> putText " " >> space
183-
_ -> pure ()
182+
case (postQualified, isQualified decl, isAnyQualified stats) of
183+
(False, True, _) -> putText "qualified" >> space
184+
(False, _, True) -> putText " " >> space
185+
_ -> pure ()
184186

185187
moduleNamePosition <- length <$> getCurrentLine
186188
forM_ (ideclPkgQual decl') $ \pkg -> putText (stringLiteral pkg) >> space
@@ -194,8 +196,11 @@ printQualified Options{..} padNames stats (L _ decl) = do
194196
replicate (isLongestImport stats - importModuleNameLength decl) ' '
195197

196198
beforeAliasPosition <- length <$> getCurrentLine
197-
forM_ (ideclAs decl') \(L _ name) ->
198-
space >> putText "as" >> space >> putText (moduleNameString name)
199+
if not postQualified then
200+
forM_ (ideclAs decl') \(L _ name) ->
201+
space >> putText "as" >> space >> putText (moduleNameString name)
202+
else
203+
pure ()
199204
afterAliasPosition <- length <$> getCurrentLine
200205

201206
when (isHiding decl) (space >> putText "hiding")
@@ -301,6 +306,13 @@ printQualified Options{..} padNames stats (L _ decl) = do
301306
modifyCurrentLine trimRight
302307
newline >> putOffset >> printAsSingleLine)
303308
printAsMultiLine)
309+
if postQualified && isQualified decl
310+
then do
311+
space
312+
putText "qualified"
313+
forM_ (ideclAs decl') \(L _ name) ->
314+
space >> putText "as" >> space >> putText (moduleNameString name)
315+
else pure ()
304316
where
305317
-- We cannot wrap/repeat 'hiding' imports since then we would get multiple
306318
-- imports hiding different things.

tests/Language/Haskell/Stylish/Step/Imports/Tests.hs

+67-24
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ tests = testGroup "Language.Haskell.Stylish.Step.Imports.Tests"
6262
, testCase "case 28" case28
6363
, testCase "case 29" case29
6464
, testCase "case 30" case30
65+
, testCase "case 31" case31
66+
, testCase "case 32" case32
67+
, testCase "case 33" case33
6568
]
6669

6770

@@ -190,7 +193,7 @@ case07 = assertSnippet (step (Just 80) $ fromImportAlign File)
190193
case08 :: Assertion
191194
case08 =
192195
let
193-
options = Options Global WithAlias True Inline Inherit (LPConstant 4) True False
196+
options = Options Global WithAlias True Inline Inherit (LPConstant 4) True False False
194197
in
195198
assertSnippet (step (Just 80) options) input
196199
[ "module Herp where"
@@ -214,7 +217,7 @@ case08 =
214217
case08b :: Assertion
215218
case08b =
216219
let
217-
options = Options Global WithModuleName True Inline Inherit (LPConstant 4) True False
220+
options = Options Global WithModuleName True Inline Inherit (LPConstant 4) True False False
218221
in
219222
assertSnippet (step (Just 80) options) input
220223
["module Herp where"
@@ -237,7 +240,7 @@ case08b =
237240
case09 :: Assertion
238241
case09 =
239242
let
240-
options = Options Global WithAlias True Multiline Inherit (LPConstant 4) True False
243+
options = Options Global WithAlias True Multiline Inherit (LPConstant 4) True False False
241244
in
242245
assertSnippet (step (Just 80) options) input
243246
[ "module Herp where"
@@ -272,7 +275,7 @@ case09 =
272275
case10 :: Assertion
273276
case10 =
274277
let
275-
options = Options Group WithAlias True Multiline Inherit (LPConstant 4) True False
278+
options = Options Group WithAlias True Multiline Inherit (LPConstant 4) True False False
276279
in
277280
assertSnippet (step (Just 40) options) input
278281
[ "module Herp where"
@@ -313,7 +316,7 @@ case10 =
313316
case11 :: Assertion
314317
case11 =
315318
let
316-
options = Options Group NewLine True Inline Inherit (LPConstant 4) True False
319+
options = Options Group NewLine True Inline Inherit (LPConstant 4) True False False
317320
in
318321
assertSnippet (step (Just 80) options) input
319322
[ "module Herp where"
@@ -340,7 +343,7 @@ case11 =
340343
case11b :: Assertion
341344
case11b =
342345
let
343-
options = Options Group WithModuleName True Inline Inherit (LPConstant 4) True False
346+
options = Options Group WithModuleName True Inline Inherit (LPConstant 4) True False False
344347
in
345348
assertSnippet (step (Just 80) options) input
346349
[ "module Herp where"
@@ -363,7 +366,7 @@ case11b =
363366
case12 :: Assertion
364367
case12 =
365368
let
366-
options = Options Group NewLine True Inline Inherit (LPConstant 2) True False
369+
options = Options Group NewLine True Inline Inherit (LPConstant 2) True False False
367370
in
368371
assertSnippet (step (Just 80) options)
369372
[ "import Data.List (map)"
@@ -377,7 +380,7 @@ case12 =
377380
case12b :: Assertion
378381
case12b =
379382
let
380-
options = Options Group WithModuleName True Inline Inherit (LPConstant 2) True False
383+
options = Options Group WithModuleName True Inline Inherit (LPConstant 2) True False False
381384
in
382385
assertSnippet (step (Just 80) options)
383386
["import Data.List (map)"]
@@ -388,7 +391,7 @@ case12b =
388391
case13 :: Assertion
389392
case13 =
390393
let
391-
options = Options None WithAlias True InlineWithBreak Inherit (LPConstant 4) True False
394+
options = Options None WithAlias True InlineWithBreak Inherit (LPConstant 4) True False False
392395
in
393396
assertSnippet (step (Just 80) options)
394397
[ "import qualified Data.List as List (concat, foldl, foldr, head, init,"
@@ -402,7 +405,7 @@ case13 =
402405
case13b :: Assertion
403406
case13b =
404407
let
405-
options = Options None WithModuleName True InlineWithBreak Inherit (LPConstant 4) True False
408+
options = Options None WithModuleName True InlineWithBreak Inherit (LPConstant 4) True False False
406409
in
407410
assertSnippet (step (Just 80) options)
408411
[ "import qualified Data.List as List (concat, foldl, foldr, head, init,"
@@ -418,7 +421,7 @@ case13b =
418421
case14 :: Assertion
419422
case14 =
420423
let
421-
options = Options None WithAlias True InlineWithBreak Inherit (LPConstant 10) True False
424+
options = Options None WithAlias True InlineWithBreak Inherit (LPConstant 10) True False False
422425
in
423426
assertSnippet (step (Just 80) options)
424427
[ "import qualified Data.List as List (concat, map, null, reverse, tail, (++))"
@@ -431,7 +434,7 @@ case14 =
431434
case15 :: Assertion
432435
case15 =
433436
let
434-
options = Options None AfterAlias True Multiline Inherit (LPConstant 4) True False
437+
options = Options None AfterAlias True Multiline Inherit (LPConstant 4) True False False
435438
in
436439
assertSnippet (step (Just 80) options)
437440
[ "import Data.Acid (AcidState)"
@@ -456,7 +459,7 @@ case15 =
456459
case16 :: Assertion
457460
case16 =
458461
let
459-
options = Options None AfterAlias True Multiline Inherit (LPConstant 4) False False
462+
options = Options None AfterAlias True Multiline Inherit (LPConstant 4) False False False
460463
in
461464
assertSnippet (step (Just 80) options)
462465
[ "import Data.Acid (AcidState)"
@@ -479,7 +482,7 @@ case16 =
479482
case17 :: Assertion
480483
case17 =
481484
let
482-
options = Options None AfterAlias True Multiline Inherit (LPConstant 4) True False
485+
options = Options None AfterAlias True Multiline Inherit (LPConstant 4) True False False
483486
in
484487
assertSnippet (step (Just 80) options)
485488
[ "import Control.Applicative (Applicative ((<*>),pure))"
@@ -496,7 +499,7 @@ case17 =
496499
case18 :: Assertion
497500
case18 =
498501
let
499-
options = Options None AfterAlias True InlineToMultiline Inherit (LPConstant 4) True False
502+
options = Options None AfterAlias True InlineToMultiline Inherit (LPConstant 4) True False False
500503
in
501504
assertSnippet (step (Just 40) options)
502505
[ "import Data.Foo as Foo (Bar, Baz, Foo)"
@@ -523,7 +526,7 @@ case18 =
523526
case19 :: Assertion
524527
case19 =
525528
let
526-
options = Options Global NewLine True InlineWithBreak RightAfter (LPConstant 17) True False
529+
options = Options Global NewLine True InlineWithBreak RightAfter (LPConstant 17) True False False
527530
in
528531
assertSnippet (step (Just 40) options) case19input
529532
----------------------------------------
@@ -539,7 +542,7 @@ case19 =
539542
case19b :: Assertion
540543
case19b =
541544
let
542-
options = Options File NewLine True InlineWithBreak RightAfter (LPConstant 17) True False
545+
options = Options File NewLine True InlineWithBreak RightAfter (LPConstant 17) True False False
543546
in
544547
assertSnippet (step (Just 40) options) case19input
545548
----------------------------------------
@@ -554,7 +557,7 @@ case19b =
554557
case19c :: Assertion
555558
case19c =
556559
let
557-
options = Options File NewLine True InlineWithBreak RightAfter LPModuleName True False
560+
options = Options File NewLine True InlineWithBreak RightAfter LPModuleName True False False
558561
in
559562
assertSnippet (step (Just 40) options) case19input
560563
----------------------------------------
@@ -569,7 +572,7 @@ case19c =
569572
case19d :: Assertion
570573
case19d =
571574
let
572-
options = Options Global NewLine True InlineWithBreak RightAfter LPModuleName True False
575+
options = Options Global NewLine True InlineWithBreak RightAfter LPModuleName True False False
573576
in
574577
assertSnippet (step (Just 40) options) case19input
575578
----------------------------------------
@@ -665,7 +668,7 @@ case22 = assertSnippet (step (Just 80) defaultOptions)
665668
case23 :: Assertion
666669
case23 =
667670
let
668-
options = Options None AfterAlias False Inline Inherit (LPConstant 4) True True
671+
options = Options None AfterAlias False Inline Inherit (LPConstant 4) True True False
669672
in
670673
assertSnippet (step (Just 40) options)
671674
[ "import Data.Acid (AcidState)"
@@ -690,7 +693,7 @@ case23 =
690693
case23b :: Assertion
691694
case23b =
692695
let
693-
options = Options None WithModuleName False Inline Inherit (LPConstant 4) True True
696+
options = Options None WithModuleName False Inline Inherit (LPConstant 4) True True False
694697
in
695698
assertSnippet (step (Just 40) options)
696699
[ "import Data.Acid (AcidState)"
@@ -716,7 +719,7 @@ case23b =
716719
case24 :: Assertion
717720
case24 =
718721
let
719-
options = Options None AfterAlias False InlineWithBreak Inherit (LPConstant 4) True True
722+
options = Options None AfterAlias False InlineWithBreak Inherit (LPConstant 4) True True False
720723
in
721724
assertSnippet (step (Just 40) options)
722725
[ "import Data.Acid (AcidState)"
@@ -740,7 +743,7 @@ case24 =
740743
case25 :: Assertion
741744
case25 =
742745
let
743-
options = Options Group AfterAlias False Multiline Inherit (LPConstant 4) False False
746+
options = Options Group AfterAlias False Multiline Inherit (LPConstant 4) False False False
744747
in
745748
assertSnippet (step (Just 80) options)
746749
[ "import Data.Acid (AcidState)"
@@ -807,7 +810,7 @@ case28 = assertSnippet (step (Just 80) $ fromImportAlign Global)
807810
, "import Data.Set (empty, nub)"
808811
]
809812
[ "import Control.Monad"
810-
, "import qualified Data.Aeson as JSON"
813+
, "import qualified Data.Aeson as JSON"
811814
, "import Data.Default.Class (Default (def))"
812815
, ""
813816
, "import Data.Maybe (Maybe (Just, Nothing))"
@@ -842,3 +845,43 @@ case30 :: Assertion
842845
case30 = assertSnippet (step Nothing defaultOptions {separateLists = False})
843846
["import Data.Monoid (Monoid (..))"]
844847
["import Data.Monoid (Monoid(..))"]
848+
849+
--------------------------------------------------------------------------------
850+
case31 :: Assertion
851+
case31 = assertSnippet (step Nothing defaultOptions {postQualified = True})
852+
["import Data.Monoid (Monoid (..))"]
853+
["import Data.Monoid (Monoid (..))"]
854+
855+
--------------------------------------------------------------------------------
856+
case32 :: Assertion
857+
case32 = assertSnippet (step Nothing defaultOptions {postQualified = True})
858+
["import qualified Data.Monoid as M"]
859+
["import Data.Monoid qualified as M"]
860+
861+
--------------------------------------------------------------------------------
862+
case33 :: Assertion
863+
case33 = assertSnippet (step Nothing defaultOptions {postQualified = True})
864+
[ "import Data.Default.Class (Default(def))"
865+
, "import qualified Data.Aeson as JSON"
866+
, "import qualified Data.Aeson as JSON"
867+
, "import Control.Monad"
868+
, "import Control.Monad"
869+
, ""
870+
, "import Data.Maybe (Maybe (Just, Nothing))"
871+
, "import qualified Data.Maybe.Extra (Maybe(Just, Nothing))"
872+
, ""
873+
, "import Data.Foo (Foo (Foo,Bar), Goo(Goo))"
874+
, "import Data.Foo (Foo (Foo,Bar))"
875+
, "import Data.Set (empty, intersect)"
876+
, "import Data.Set (empty, nub)"
877+
]
878+
[ "import Control.Monad"
879+
, "import Data.Aeson qualified as JSON"
880+
, "import Data.Default.Class (Default (def))"
881+
, ""
882+
, "import Data.Maybe (Maybe (Just, Nothing))"
883+
, "import Data.Maybe.Extra (Maybe (Just, Nothing)) qualified"
884+
, ""
885+
, "import Data.Foo (Foo (Bar, Foo), Goo (Goo))"
886+
, "import Data.Set (empty, intersect, nub)"
887+
]

0 commit comments

Comments
 (0)