packages feed

stylish-haskell 0.7.1.0 → 0.8.0.0

raw patch · 9 files changed

+223/−27 lines, 9 filesdep ~HUnitdep ~aesondep ~sybPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: HUnit, aeson, syb

API changes (from Hackage documentation)

+ Language.Haskell.Stylish.Step.Imports: instance GHC.Classes.Eq l => GHC.Classes.Eq (Language.Haskell.Stylish.Step.Imports.ImportEntity l)
+ Language.Haskell.Stylish.Step.Imports: instance GHC.Classes.Ord l => GHC.Base.Monoid (Language.Haskell.Stylish.Step.Imports.ImportPortion l)
+ Language.Haskell.Stylish.Step.Imports: instance GHC.Classes.Ord l => GHC.Classes.Ord (Language.Haskell.Stylish.Step.Imports.ImportEntity l)

Files

CHANGELOG view
@@ -1,5 +1,19 @@ # CHANGELOG +- 0.8.0.0+    * Remove `MagicHash` from whitelisted language extensions, since it was+      causing parsing errors (by Artyom Kazak)+    * Don't leave a `#-}` hanging on the next line when `language_pragmas`+      is set to `compact` and the `#-}` doesn't fit into character limit+      (by Artyom Kazak)+    * Deduplicate import specs (i.e. `import Foo (a, a, b)` becomes+      `import Foo (a, b)`) (by Artyom Kazak)+    * Take package imports into account when prettifying imports+      (by Artyom Kazak)+    * Bump `aeson` to 1.2+    * Bump `syb` to 0.7+    * Bump `HUnit` to 1.6+ - 0.7.1.0     * Keep `safe` and `{-# SOURCE #-}` import annotations (by Moritz Drexl) 
data/stylish-haskell.yaml view
@@ -41,7 +41,7 @@       # Default: global.       align: global -      # Folowing options affect only import list alignment.+      # The following options affect only import list alignment.       #       # List align has following options:       #@@ -75,7 +75,7 @@       #   short enough to fit to single line. Otherwise it'll be multiline.       #       # - multiline: One line per import list entry.-      #   Type with contructor list acts like single import.+      #   Type with constructor list acts like single import.       #       #   > import qualified Data.Map as M       #   >     ( empty@@ -109,7 +109,7 @@       #   Useful for 'file' and 'group' align settings.       list_padding: 4 -      # Separate lists option affects formating of import list for type+      # Separate lists option affects formatting of import list for type       # or class. The only difference is single space between type and list       # of constructors, selectors and class functions.       #@@ -142,7 +142,7 @@        # Align affects alignment of closing pragma brackets.       #-      # - true: Brackets are aligned in same collumn.+      # - true: Brackets are aligned in same column.       #       # - false: Brackets are not aligned together. There is only one space       #   between actual import and closing bracket.
lib/Language/Haskell/Stylish/Parse.hs view
@@ -24,7 +24,6 @@   [ H.GADTs   , H.HereDocuments   , H.KindSignatures-  , H.MagicHash   , H.NewQualifiedOperators   , H.PatternGuards   , H.StandaloneDeriving
lib/Language/Haskell/Stylish/Step/Imports.hs view
@@ -16,10 +16,13 @@ -------------------------------------------------------------------------------- import           Control.Arrow                   ((&&&)) import           Control.Monad                   (void)+import           Data.Monoid                     ((<>)) import           Data.Char                       (toLower) import           Data.List                       (intercalate, sortBy) import           Data.Maybe                      (isJust, maybeToList) import           Data.Ord                        (comparing)+import qualified Data.Map                        as M+import qualified Data.Set                        as S import qualified Language.Haskell.Exts           as H import qualified Data.Aeson                      as A import qualified Data.Aeson.Types                as A@@ -81,7 +84,17 @@     | Multiline     deriving (Eq, Show) + --------------------------------------------------------------------------------++modifyImportSpecs :: ([H.ImportSpec l] -> [H.ImportSpec l])+                  -> H.ImportDecl l -> H.ImportDecl l+modifyImportSpecs f imp = imp {H.importSpecs = f' <$> H.importSpecs imp}+  where+    f' (H.ImportSpecList l h specs) = H.ImportSpecList l h (f specs)+++-------------------------------------------------------------------------------- imports :: H.Module l -> [H.ImportDecl l] imports (H.Module _ _ _ is _) = is imports _                     = []@@ -91,19 +104,97 @@ importName :: H.ImportDecl l -> String importName i = let (H.ModuleName _ n) = H.importModule i in n +importPackage :: H.ImportDecl l -> Maybe String+importPackage i = H.importPkg i + --------------------------------------------------------------------------------+-- | A "compound import name" is import's name and package (if present). For+-- instance, if you have an import @Foo.Bar@ from package @foobar@, the full+-- name will be @"foobar" Foo.Bar@.+compoundImportName :: H.ImportDecl l -> String+compoundImportName i =+  case importPackage i of+    Nothing  -> importName i+    Just pkg -> show pkg ++ " " ++ importName i+++-------------------------------------------------------------------------------- longestImport :: [H.ImportDecl l] -> Int-longestImport = maximum . map (length . importName)+longestImport = maximum . map (length . compoundImportName)   -------------------------------------------------------------------------------- -- | Compare imports for ordering compareImports :: H.ImportDecl l -> H.ImportDecl l -> Ordering-compareImports = comparing (map toLower . importName &&& H.importQualified)+compareImports =+  comparing (map toLower . importName &&&+             fmap (map toLower) . importPackage &&&+             H.importQualified)   --------------------------------------------------------------------------------+-- | Remove (or merge) duplicated import specs.+--+-- * When something is mentioned twice, it's removed: @A, A@ -> A+-- * More general forms take priority: @A, A(..)@ -> @A(..)@+-- * Sometimes we have to combine imports: @A(x), A(y)@ -> @A(x, y)@+--+-- Import specs are always sorted by subsequent steps so we don't have to care+-- about preserving order.+deduplicateImportSpecs :: Ord l => H.ImportDecl l -> H.ImportDecl l+deduplicateImportSpecs =+  modifyImportSpecs $+    map recomposeImportSpec .+    M.toList . M.fromListWith (<>) .+    map decomposeImportSpec++-- | What we are importing (variable, class, etc)+data ImportEntity l+  -- | A variable+  = ImportVar l (H.Name l)+  -- | Something that can be imported partially+  | ImportClassOrData l (H.Name l)+  -- | Something else ('H.IAbs')+  | ImportOther l (H.Namespace l) (H.Name l)+  deriving (Eq, Ord)++-- | What we are importing from an 'ImportClassOrData'+data ImportPortion l+  = ImportSome [H.CName l]  -- ^ @A(x, y, z)@+  | ImportAll               -- ^ @A(..)@++instance Ord l => Monoid (ImportPortion l) where+  mempty = ImportSome []+  mappend (ImportSome a) (ImportSome b) = ImportSome (setUnion a b)+  mappend _ _                           = ImportAll++-- | O(n log n) union.+setUnion :: Ord a => [a] -> [a] -> [a]+setUnion a b = S.toList (S.fromList a `S.union` S.fromList b)++decomposeImportSpec :: H.ImportSpec l -> (ImportEntity l, ImportPortion l)+decomposeImportSpec x = case x of+  -- I checked and it looks like namespace's 'l' is always equal to x's 'l'+  H.IAbs l space n -> case space of+    H.NoNamespace      _ -> (ImportClassOrData l n, ImportSome [])+    H.TypeNamespace    _ -> (ImportOther l space n, ImportSome [])+    H.PatternNamespace _ -> (ImportOther l space n, ImportSome [])+  H.IVar l n             -> (ImportVar l n, ImportSome [])+  H.IThingAll l n        -> (ImportClassOrData l n, ImportAll)+  H.IThingWith l n names -> (ImportClassOrData l n, ImportSome names)++recomposeImportSpec :: (ImportEntity l, ImportPortion l) -> H.ImportSpec l+recomposeImportSpec (e, p) = case e of+  ImportClassOrData l n -> case p of+    ImportSome []       -> H.IAbs l (H.NoNamespace l) n+    ImportSome names    -> H.IThingWith l n names+    ImportAll           -> H.IThingAll l n+  ImportVar l n         -> H.IVar l n+  ImportOther l space n -> H.IAbs l space n+++-------------------------------------------------------------------------------- -- | The implementation is a bit hacky to get proper sorting for input specs: -- constructors first, followed by functions, and then operators. compareImportSpecs :: H.ImportSpec l -> H.ImportSpec l -> Ordering@@ -119,10 +210,7 @@ -------------------------------------------------------------------------------- -- | Sort the input spec list inside an 'H.ImportDecl' sortImportSpecs :: H.ImportDecl l -> H.ImportDecl l-sortImportSpecs imp = imp {H.importSpecs = sort' <$> H.importSpecs imp}-  where-    sort' (H.ImportSpecList l h specs) = H.ImportSpecList l h $-        sortBy compareImportSpecs specs+sortImportSpecs = modifyImportSpecs (sortBy compareImportSpecs)   --------------------------------------------------------------------------------@@ -221,9 +309,9 @@           . withTail (", " ++))         ++ [")"]) -    paddedBase = base $ padImport $ importName imp+    paddedBase = base $ padImport $ compoundImportName imp -    paddedNoSpecBase = base $ padImportNoSpec $ importName imp+    paddedNoSpecBase = base $ padImportNoSpec $ compoundImportName imp      padImport = if hasExtras && padName         then padRight longest@@ -233,12 +321,11 @@         then padRight longest         else id -    base' baseName importAs hasHiding' = unwords $ concat $ filter (not . null)+    base' baseName importAs hasHiding' = unwords $ concat $         [ ["import"]         , source         , safe         , qualified-        , show <$> maybeToList (H.importPkg imp)         , [baseName]         , importAs         , hasHiding'@@ -248,9 +335,10 @@         ["as " ++ as | H.ModuleName _ as <- maybeToList $ H.importAs imp]         ["hiding" | hasHiding] -    inlineBaseLength = length $ base' (padImport $ importName imp) [] []+    inlineBaseLength = length $+                       base' (padImport $ compoundImportName imp) [] [] -    afterAliasBaseLength = length $ base' (padImport $ importName imp)+    afterAliasBaseLength = length $ base' (padImport $ compoundImportName imp)         ["as " ++ as | H.ModuleName _ as <- maybeToList $ H.importAs imp] []      (hasHiding, importSpecs) = case H.importSpecs imp of@@ -320,7 +408,8 @@     ]     ls   where-    imps    = map sortImportSpecs $ imports $ fmap linesFromSrcSpan module'+    imps    = map (sortImportSpecs . deduplicateImportSpecs) $+              imports $ fmap linesFromSrcSpan module'     longest = longestImport imps     groups  = groupAdjacent [(H.ann i, i) | i <- imps] 
lib/Language/Haskell/Stylish/Step/LanguagePragmas.hs view
@@ -56,7 +56,7 @@ -------------------------------------------------------------------------------- compactPragmas :: Int -> [String] -> Lines compactPragmas columns pragmas' = wrap columns "{-# LANGUAGE" 13 $-    map (++ ",") (init pragmas') ++ [last pragmas', "#-}"]+    map (++ ",") (init pragmas') ++ [last pragmas' ++ " #-}"]   --------------------------------------------------------------------------------
stylish-haskell.cabal view
@@ -1,5 +1,5 @@ Name:          stylish-haskell-Version:       0.7.1.0+Version:       0.8.0.0 Synopsis:      Haskell code prettifier Homepage:      https://github.com/jaspervdj/stylish-haskell License:       BSD3@@ -49,7 +49,7 @@     Paths_stylish_haskell    Build-depends:-    aeson            >= 0.6  && < 1.2,+    aeson            >= 0.6  && < 1.3,     base             >= 4.8  && < 5,     bytestring       >= 0.9  && < 0.11,     containers       >= 0.3  && < 0.6,@@ -57,7 +57,7 @@     filepath         >= 1.1  && < 1.5,     haskell-src-exts >= 1.18 && < 1.20,     mtl              >= 2.0  && < 2.3,-    syb              >= 0.3  && < 0.7,+    syb              >= 0.3  && < 0.8,     yaml             >= 0.7  && < 0.9  Executable stylish-haskell@@ -70,7 +70,7 @@     strict               >= 0.3  && < 0.4,     optparse-applicative >= 0.12 && < 0.14,     -- Copied from regular dependencies...-    aeson            >= 0.6  && < 1.2,+    aeson            >= 0.6  && < 1.3,     base             >= 4.8  && < 5,     bytestring       >= 0.9  && < 0.11,     containers       >= 0.3  && < 0.6,@@ -78,7 +78,7 @@     filepath         >= 1.1  && < 1.5,     haskell-src-exts >= 1.18 && < 1.20,     mtl              >= 2.0  && < 2.3,-    syb              >= 0.3  && < 0.7,+    syb              >= 0.3  && < 0.8,     yaml             >= 0.7  && < 0.9  Test-suite stylish-haskell-tests@@ -112,11 +112,11 @@     Language.Haskell.Stylish.Verbose    Build-depends:-    HUnit                >= 1.2 && < 1.6,+    HUnit                >= 1.2 && < 1.7,     test-framework       >= 0.4 && < 0.9,     test-framework-hunit >= 0.2 && < 0.4,     -- Copied from regular dependencies...-    aeson            >= 0.6  && < 1.2,+    aeson            >= 0.6  && < 1.3,     base             >= 4.8  && < 5,     bytestring       >= 0.9  && < 0.11,     containers       >= 0.3  && < 0.6,@@ -124,7 +124,7 @@     filepath         >= 1.1  && < 1.5,     haskell-src-exts >= 1.18 && < 1.20,     mtl              >= 2.0  && < 2.3,-    syb              >= 0.3  && < 0.7,+    syb              >= 0.3  && < 0.8,     yaml             >= 0.7  && < 0.9  Source-repository head
tests/Language/Haskell/Stylish/Parse/Tests.hs view
@@ -27,6 +27,7 @@     , testCase "StandalonDeriving extension" testStandaloneDeriving     , testCase "UnicodeSyntax extension"     testUnicodeSyntax     , testCase "XmlSyntax regression"        testXmlSyntaxRegression+    , testCase "MagicHash regression"        testMagicHashRegression     ]  --------------------------------------------------------------------------------@@ -118,6 +119,11 @@ testXmlSyntaxRegression :: Assertion testXmlSyntaxRegression = assert $ isRight $ parseModule [] Nothing $ unlines   [ "smaller a b = a <b"+  ]++testMagicHashRegression :: Assertion+testMagicHashRegression = assert $ isRight $ parseModule [] Nothing $ unlines+  [ "xs = \"foo\"#|1#|'a'#|bar#|Nil"   ]  --------------------------------------------------------------------------------
tests/Language/Haskell/Stylish/Step/Imports/Tests.hs view
@@ -47,6 +47,8 @@     , testCase "case 19d" case19c     , testCase "case 19d" case19d     , testCase "case 20" case20+    , testCase "case 21" case21+    , testCase "case 22" case22     ]  @@ -530,4 +532,60 @@         , "import {-# SOURCE #-} qualified Data.Text as T"         , "import qualified   Data.Map as Map"         , "import Data.Set (empty)"+        ]++--------------------------------------------------------------------------------+case21 :: Assertion+case21 = expected+    @=? testStep (step 80 defaultOptions) input'+  where+    expected = unlines+        [ "{-# LANGUAGE ExplicitNamespaces #-}"+        , "import           X1 (A, B, C)"+        , "import           X2 (A, B, C)"+        , "import           X3 (A (..))"+        , "import           X4 (A (..))"+        , "import           X5 (A (..))"+        , "import           X6 (A (a, b, c), B (m, n, o))"+        , "import           X7 (a, b, c)"+        , "import           X8 (type (+), (+))"+        , "import           X9 hiding (x, y, z)"+        ]+    input' = unlines+        [ "{-# LANGUAGE ExplicitNamespaces #-}"+        , "import X1 (A, B, A, C, A, B, A)"+        , "import X2 (C(), B(), A())"+        , "import X3 (A(..))"+        , "import X4 (A, A(..))"+        , "import X5 (A(..), A(x))"+        , "import X6 (A(a,b), B(m,n), A(c), B(o))"+        , "import X7 (a, b, a, c)"+        , "import X8 (type (+), (+))"+        , "import X9 hiding (x, y, z, x)"+        ]++--------------------------------------------------------------------------------+case22 :: Assertion+case22 = expected+    @=? testStep (step 80 defaultOptions) input'+  where+    expected = unlines+        [ "{-# LANGUAGE PackageImports #-}"+        , "import           A"+        , "import           \"blah\" A"+        , "import           \"foo\" A"+        , "import qualified \"foo\" A  as X"+        , "import           \"foo\" B  (shortName, someLongName, someLongerName,"+        , "                           theLongestNameYet)"+        ]+    input' = unlines+        [ "{-# LANGUAGE PackageImports #-}"+        , "import A"+        , "import \"foo\" A"+        , "import \"blah\" A"+        , "import qualified \"foo\" A as X"+        -- this import fits into 80 chats without "foo",+        -- but doesn't fit when "foo" is included into the calculation+        , "import \"foo\" B (someLongName, someLongerName, " +++          "theLongestNameYet, shortName)"         ]
tests/Language/Haskell/Stylish/Step/LanguagePragmas/Tests.hs view
@@ -26,6 +26,8 @@     , testCase "case 06" case06     , testCase "case 07" case07     , testCase "case 08" case08+    , testCase "case 09" case09+    , testCase "case 10" case10     ]  @@ -166,4 +168,32 @@         [ "{-# LANGUAGE DeriveDataTypeable, StandaloneDeriving, " ++           "TemplateHaskell #-}"         , "{-# LANGUAGE TypeOperators, ViewPatterns #-}"+        ]+++--------------------------------------------------------------------------------+case09 :: Assertion+case09 = expected @=? testStep (step 80 Compact True False) input+  where+    input = unlines+        [ "{-# LANGUAGE DefaultSignatures, FlexibleInstances, LambdaCase, " +++          "TypeApplications"+        , "             #-}"+        ]+    expected = unlines+        [ "{-# LANGUAGE DefaultSignatures, FlexibleInstances, LambdaCase,"+        , "             TypeApplications #-}"+        ]++--------------------------------------------------------------------------------+case10 :: Assertion+case10 = expected @=? testStep (step 80 Compact True False) input+  where+    input = unlines+        [ "{-# LANGUAGE NondecreasingIndentation, ScopedTypeVariables,"+        , "             TypeApplications #-}"+        ]+    expected = unlines+        [ "{-# LANGUAGE NondecreasingIndentation, ScopedTypeVariables, " +++          "TypeApplications #-}"         ]