mirror of
https://github.com/tweag/ormolu.git
synced 2024-09-11 13:16:13 +03:00
Support explicit package names in module re-exports in .ormolu
Support explicit mention of target package name in module re-exports. Even if the exported package is not specified as a direct dependency of the component being formatted it will be taken into account correctly.
This commit is contained in:
parent
fe98934c05
commit
9fabd8cfe1
@ -1,4 +1,4 @@
|
||||
## Unreleased
|
||||
## Ormolu 0.7.1.0
|
||||
|
||||
* Include `base` fixity information when formatting a Haskell file that's
|
||||
not mentioned in an existing cabal file. [Issue
|
||||
@ -9,6 +9,11 @@
|
||||
|
||||
* Ormolu is now aware of more common module re-exports by default.
|
||||
|
||||
* Support explicit mention of target package name in module re-exports. Even
|
||||
if the exported package is not specified as a direct dependency of the
|
||||
component being formatted it will still be taken into account correctly.
|
||||
[Issue 1037](https://github.com/tweag/ormolu/issues/1037).
|
||||
|
||||
## Ormolu 0.7.0.0
|
||||
|
||||
* Inference of operator fixity information is now more precise and takes
|
||||
|
@ -200,11 +200,12 @@ Here is an example:
|
||||
|
||||
```haskell
|
||||
module Control.Lens exports Control.Lens.At
|
||||
module Control.Lens exports Control.Lens.Lens
|
||||
module Control.Lens exports "lens" Control.Lens.Lens
|
||||
```
|
||||
|
||||
Module re-export declarations can be mixed freely with fixity overrides, as
|
||||
long as each declaration is on its own line.
|
||||
long as each declaration is on its own line. As of Ormolu 0.7.1.0 explicit
|
||||
package names are allowed in re-export declarations (see the example above).
|
||||
|
||||
Finally, all of the above-mentioned parameters can be controlled from the
|
||||
command line:
|
||||
|
@ -18,6 +18,7 @@ import Data.Set qualified as Set
|
||||
import Data.Text.IO qualified as TIO
|
||||
import Data.Version (showVersion)
|
||||
import Distribution.ModuleName (ModuleName)
|
||||
import Distribution.Types.PackageName (PackageName)
|
||||
import Language.Haskell.TH.Env (envQ)
|
||||
import Options.Applicative
|
||||
import Ormolu
|
||||
@ -392,7 +393,8 @@ parseFixityDeclaration :: ReadM [(OpName, FixityInfo)]
|
||||
parseFixityDeclaration = eitherReader parseFixityDeclarationStr
|
||||
|
||||
-- | Parse a module reexport declaration.
|
||||
parseModuleReexportDeclaration :: ReadM (ModuleName, NonEmpty ModuleName)
|
||||
parseModuleReexportDeclaration ::
|
||||
ReadM (ModuleName, NonEmpty (Maybe PackageName, ModuleName))
|
||||
parseModuleReexportDeclaration = eitherReader parseModuleReexportDeclarationStr
|
||||
|
||||
-- | Parse 'ColorMode'.
|
||||
|
@ -90,7 +90,7 @@ ormolu cfgWithIndices path originalInput = do
|
||||
cfg = regionIndicesToDeltas totalLines <$> cfgWithIndices
|
||||
fixityMap =
|
||||
packageFixityMap
|
||||
(cfgDependencies cfg) -- memoized on the set of dependencies
|
||||
(overapproximatedDependencies cfg) -- memoized on the set of dependencies
|
||||
(warnings, result0) <-
|
||||
parseModule' cfg fixityMap OrmoluParsingFailed path originalInput
|
||||
when (cfgDebug cfg) $ do
|
||||
|
@ -1,3 +1,4 @@
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
|
||||
-- | Configuration options used by the tool.
|
||||
@ -8,12 +9,14 @@ module Ormolu.Config
|
||||
RegionDeltas (..),
|
||||
SourceType (..),
|
||||
defaultConfig,
|
||||
overapproximatedDependencies,
|
||||
regionIndicesToDeltas,
|
||||
DynOption (..),
|
||||
dynOptionToLocatedStr,
|
||||
)
|
||||
where
|
||||
|
||||
import Data.Map.Strict qualified as Map
|
||||
import Data.Set (Set)
|
||||
import Data.Set qualified as Set
|
||||
import Distribution.Types.PackageName (PackageName)
|
||||
@ -94,6 +97,21 @@ defaultConfig =
|
||||
}
|
||||
}
|
||||
|
||||
-- | Return all dependencies of the module. This includes both the declared
|
||||
-- dependencies of the component we are working with and all potential
|
||||
-- module re-export targets.
|
||||
overapproximatedDependencies :: Config region -> Set PackageName
|
||||
overapproximatedDependencies Config {..} =
|
||||
Set.union cfgDependencies potentialReexportTargets
|
||||
where
|
||||
potentialReexportTargets =
|
||||
Set.fromList
|
||||
. concatMap toTargetPackages
|
||||
$ Map.elems (unModuleReexports cfgModuleReexports)
|
||||
toTargetPackages = concatMap $ \case
|
||||
(Nothing, _) -> []
|
||||
(Just x, _) -> [x]
|
||||
|
||||
-- | Convert 'RegionIndices' into 'RegionDeltas'.
|
||||
regionIndicesToDeltas ::
|
||||
-- | Total number of lines in the input
|
||||
|
@ -83,9 +83,9 @@ applyModuleReexports (ModuleReexports reexports) imports = imports >>= expand
|
||||
case Map.lookup (fimportModule i) reexports of
|
||||
Nothing -> pure i
|
||||
Just exports ->
|
||||
let exportToImport mmodule =
|
||||
let exportToImport (mpackageName, mmodule) =
|
||||
i
|
||||
{ fimportPackage = Nothing,
|
||||
{ fimportPackage = mpackageName,
|
||||
fimportModule = mmodule
|
||||
}
|
||||
in NE.toList exports >>= expand . exportToImport
|
||||
|
@ -166,7 +166,7 @@ defaultFixityOverrides = FixityOverrides Map.empty
|
||||
|
||||
-- | Module re-exports
|
||||
newtype ModuleReexports = ModuleReexports
|
||||
{ unModuleReexports :: Map ModuleName (NonEmpty ModuleName)
|
||||
{ unModuleReexports :: Map ModuleName (NonEmpty (Maybe PackageName, ModuleName))
|
||||
}
|
||||
deriving stock (Eq, Show)
|
||||
|
||||
@ -175,7 +175,8 @@ defaultModuleReexports :: ModuleReexports
|
||||
defaultModuleReexports =
|
||||
ModuleReexports . Map.fromList $
|
||||
[ ( "Control.Lens",
|
||||
NE.fromList
|
||||
l
|
||||
"lens"
|
||||
[ "Control.Lens.At",
|
||||
"Control.Lens.Cons",
|
||||
"Control.Lens.Each",
|
||||
@ -201,12 +202,14 @@ defaultModuleReexports =
|
||||
]
|
||||
),
|
||||
( "Servant",
|
||||
NE.fromList
|
||||
l
|
||||
"servant"
|
||||
[ "Servant.API"
|
||||
]
|
||||
),
|
||||
( "Optics",
|
||||
NE.fromList
|
||||
l
|
||||
"optics"
|
||||
[ "Optics.Fold",
|
||||
"Optics.Operators",
|
||||
"Optics.IxAffineFold",
|
||||
@ -216,11 +219,14 @@ defaultModuleReexports =
|
||||
]
|
||||
),
|
||||
( "Test.Hspec",
|
||||
NE.fromList
|
||||
l
|
||||
"hspec-expectations"
|
||||
[ "Test.Hspec.Expectations"
|
||||
]
|
||||
)
|
||||
]
|
||||
where
|
||||
l packageName xs = (Just packageName,) <$> NE.fromList xs
|
||||
|
||||
-- | Fixity information that is specific to a package being formatted. It
|
||||
-- requires module-specific imports in order to be usable.
|
||||
|
@ -70,7 +70,7 @@ parseModuleReexportDeclaration ::
|
||||
-- | Parse result
|
||||
Either
|
||||
(ParseErrorBundle Text Void)
|
||||
(ModuleName, NonEmpty ModuleName)
|
||||
(ModuleName, NonEmpty (Maybe PackageName, ModuleName))
|
||||
parseModuleReexportDeclaration = runParser (pModuleReexport <* eof) ""
|
||||
|
||||
pDotOrmolu :: Parser (FixityOverrides, ModuleReexports)
|
||||
@ -128,7 +128,7 @@ pOperator = OpName <$> (tickedOperator <|> normalOperator)
|
||||
normalOperator =
|
||||
takeWhile1P (Just "operator character") isOperatorConstituent
|
||||
|
||||
pModuleReexport :: Parser (ModuleName, NonEmpty ModuleName)
|
||||
pModuleReexport :: Parser (ModuleName, NonEmpty (Maybe PackageName, ModuleName))
|
||||
pModuleReexport = do
|
||||
void (string "module")
|
||||
hidden hspace1
|
||||
@ -136,9 +136,12 @@ pModuleReexport = do
|
||||
hidden hspace1
|
||||
void (string "exports")
|
||||
hidden hspace1
|
||||
mexportedPackage <-
|
||||
optional $
|
||||
between (char '\"') (char '\"') pPackageName <* hidden hspace1
|
||||
exportedModule <- pModuleName
|
||||
hidden hspace
|
||||
return (exportingModule, NE.singleton exportedModule)
|
||||
return (exportingModule, NE.singleton (mexportedPackage, exportedModule))
|
||||
|
||||
pModuleName :: Parser ModuleName
|
||||
pModuleName =
|
||||
|
@ -1,3 +1,4 @@
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
|
||||
@ -20,6 +21,7 @@ import Data.Text.Lazy.Builder qualified as B
|
||||
import Data.Text.Lazy.Builder.Int qualified as B
|
||||
import Distribution.ModuleName (ModuleName)
|
||||
import Distribution.ModuleName qualified as ModuleName
|
||||
import Distribution.Types.PackageName
|
||||
import Ormolu.Fixity
|
||||
|
||||
-- | Print out a textual representation of an @.ormolu@ file.
|
||||
@ -53,19 +55,23 @@ renderSingleFixityOverride (OpName operator, FixityInfo {..}) =
|
||||
isTickedOperator = maybe True (Char.isLetter . fst) . T.uncons
|
||||
|
||||
renderSingleModuleReexport ::
|
||||
(ModuleName, NonEmpty ModuleName) ->
|
||||
(ModuleName, NonEmpty (Maybe PackageName, ModuleName)) ->
|
||||
Builder
|
||||
renderSingleModuleReexport (exportingModule, exports) =
|
||||
sconcat (renderSingle <$> exports)
|
||||
where
|
||||
renderSingle exportedModule =
|
||||
renderSingle (mexportedPackage, exportedModule) =
|
||||
mconcat
|
||||
[ "module ",
|
||||
renderModuleName exportingModule,
|
||||
" exports ",
|
||||
renderOptionalPackageName mexportedPackage,
|
||||
renderModuleName exportedModule,
|
||||
"\n"
|
||||
]
|
||||
renderOptionalPackageName = \case
|
||||
Nothing -> mempty
|
||||
Just x -> "\"" <> B.fromString (unPackageName x) <> "\" "
|
||||
|
||||
renderModuleName :: ModuleName -> Builder
|
||||
renderModuleName = B.fromString . intercalate "." . ModuleName.components
|
||||
|
@ -16,6 +16,7 @@ import Data.Map.Strict (Map)
|
||||
import Data.Map.Strict qualified as Map
|
||||
import Data.Text qualified as T
|
||||
import Distribution.ModuleName (ModuleName)
|
||||
import Distribution.Types.PackageName (PackageName)
|
||||
import Ormolu.Exception
|
||||
import Ormolu.Fixity
|
||||
import Ormolu.Fixity.Parser
|
||||
@ -82,6 +83,6 @@ parseModuleReexportDeclarationStr ::
|
||||
-- | Input to parse
|
||||
String ->
|
||||
-- | Parse result
|
||||
Either String (ModuleName, NonEmpty ModuleName)
|
||||
Either String (ModuleName, NonEmpty (Maybe PackageName, ModuleName))
|
||||
parseModuleReexportDeclarationStr =
|
||||
first errorBundlePretty . parseModuleReexportDeclaration . T.pack
|
||||
|
@ -78,7 +78,7 @@ spec = do
|
||||
""
|
||||
( T.unlines
|
||||
[ "module Control.Lens exports Control.Lens.Lens",
|
||||
"module Control.Lens exports Control.Lens.At",
|
||||
"module Control.Lens exports \"lens\" Control.Lens.At",
|
||||
"module Text.Megaparsec exports Control.Monad.Combinators"
|
||||
]
|
||||
)
|
||||
@ -93,7 +93,7 @@ spec = do
|
||||
"infixl 4 <$",
|
||||
"",
|
||||
"",
|
||||
"module Control.Lens exports Control.Lens.At",
|
||||
"module Control.Lens exports \"lens\" Control.Lens.At",
|
||||
"infixr 9 .",
|
||||
"module Text.Megaparsec exports Control.Monad.Combinators",
|
||||
"infixl 1 >>, >>=",
|
||||
@ -170,7 +170,12 @@ spec = do
|
||||
it "parses a re-export declaration" $
|
||||
parseModuleReexportDeclaration "module Control.Lens exports Control.Lens.Lens"
|
||||
`shouldParse` ( "Control.Lens",
|
||||
"Control.Lens.Lens" :| []
|
||||
(Nothing, "Control.Lens.Lens") :| []
|
||||
)
|
||||
it "parses a re-export declaration (explicit package)" $
|
||||
parseModuleReexportDeclaration "module Control.Lens exports \"lens\" Control.Lens.Lens"
|
||||
`shouldParse` ( "Control.Lens",
|
||||
(Just "lens", "Control.Lens.Lens") :| []
|
||||
)
|
||||
it "fails with correct parse error (keyword wrong)" $
|
||||
parseModuleReexportDeclaration "foo Control.Lens exports Control.Lens.Lens"
|
||||
@ -223,10 +228,10 @@ exampleModuleReexports :: ModuleReexports
|
||||
exampleModuleReexports =
|
||||
ModuleReexports . Map.fromList $
|
||||
[ ( "Control.Lens",
|
||||
"Control.Lens.At" :| ["Control.Lens.Lens"]
|
||||
(Nothing, "Control.Lens.Lens") :| [(Just "lens", "Control.Lens.At")]
|
||||
),
|
||||
( "Text.Megaparsec",
|
||||
"Control.Monad.Combinators" :| []
|
||||
(Nothing, "Control.Monad.Combinators") :| []
|
||||
)
|
||||
]
|
||||
|
||||
|
@ -234,7 +234,7 @@ spec = do
|
||||
ModuleReexports $
|
||||
Map.insert
|
||||
"Foo"
|
||||
("Control.Lens" :| [])
|
||||
((Nothing, "Control.Lens") :| [])
|
||||
(unModuleReexports defaultModuleReexports)
|
||||
checkFixities
|
||||
["lens"]
|
||||
|
@ -50,7 +50,6 @@ checkExample srcPath' = it (fromRelFile srcPath' ++ " works") . withNiceExceptio
|
||||
[ "base",
|
||||
"esqueleto",
|
||||
"hspec",
|
||||
"hspec-expectations",
|
||||
"lens",
|
||||
"servant"
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user