ormolu 0.5.2.0 → 0.5.3.0
raw patch · 59 files changed
+675/−431 lines, 59 filesdep +th-envdep −gitrevdep ~ansi-terminaldep ~optparse-applicativedep ~textPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: th-env
Dependencies removed: gitrev
Dependency ranges changed: ansi-terminal, optparse-applicative, text
API changes (from Hackage documentation)
- Ormolu.Utils.Cabal: data PackageName
- Ormolu.Utils.Cabal: defaultCabalInfo :: CabalInfo
- Ormolu.Utils.Cabal: unPackageName :: PackageName -> String
+ Ormolu: CabalDidNotMention :: CabalInfo -> CabalSearchResult
+ Ormolu: CabalFound :: CabalInfo -> CabalSearchResult
+ Ormolu: CabalInfo :: !PackageName -> ![DynOption] -> !Set PackageName -> !FilePath -> CabalInfo
+ Ormolu: CabalNotFound :: CabalSearchResult
+ Ormolu: [ciCabalFilePath] :: CabalInfo -> !FilePath
+ Ormolu: [ciDependencies] :: CabalInfo -> !Set PackageName
+ Ormolu: [ciDynOpts] :: CabalInfo -> ![DynOption]
+ Ormolu: [ciPackageName] :: CabalInfo -> !PackageName
+ Ormolu: data CabalInfo
+ Ormolu: data CabalSearchResult
+ Ormolu: getCabalInfoForSourceFile :: MonadIO m => FilePath -> m CabalSearchResult
+ Ormolu: getFixityOverridesForSourceFile :: MonadIO m => CabalInfo -> m FixityMap
+ Ormolu: refineConfig :: SourceType -> Maybe CabalInfo -> Maybe FixityMap -> Config region -> Config region
+ Ormolu: type FixityMap = Map OpName FixityInfo
+ Ormolu.Exception: printOrmoluException :: OrmoluException -> Term ()
+ Ormolu.Fixity: data OpName
+ Ormolu.Fixity: occOpName :: OccName -> OpName
+ Ormolu.Fixity: pattern OpName :: Text -> OpName
+ Ormolu.Fixity: unOpName :: OpName -> Text
+ Ormolu.Fixity.Internal: data OpName
+ Ormolu.Fixity.Internal: instance Data.Binary.Class.Binary Ormolu.Fixity.Internal.OpName
+ Ormolu.Fixity.Internal: instance Data.String.IsString Ormolu.Fixity.Internal.OpName
+ Ormolu.Fixity.Internal: instance GHC.Classes.Eq Ormolu.Fixity.Internal.OpName
+ Ormolu.Fixity.Internal: instance GHC.Classes.Ord Ormolu.Fixity.Internal.OpName
+ Ormolu.Fixity.Internal: instance GHC.Show.Show Ormolu.Fixity.Internal.OpName
+ Ormolu.Fixity.Internal: occOpName :: OccName -> OpName
+ Ormolu.Fixity.Internal: pattern OpName :: Text -> OpName
+ Ormolu.Fixity.Internal: unOpName :: OpName -> Text
+ Ormolu.Utils: textToStringBuffer :: Text -> StringBuffer
+ Ormolu.Utils.Cabal: CabalDidNotMention :: CabalInfo -> CabalSearchResult
+ Ormolu.Utils.Cabal: CabalFound :: CabalInfo -> CabalSearchResult
+ Ormolu.Utils.Cabal: CabalNotFound :: CabalSearchResult
+ Ormolu.Utils.Cabal: data CabalSearchResult
+ Ormolu.Utils.Cabal: instance GHC.Classes.Eq Ormolu.Utils.Cabal.CabalSearchResult
+ Ormolu.Utils.Cabal: instance GHC.Show.Show Ormolu.Utils.Cabal.CabalSearchResult
- Ormolu: Config :: ![DynOption] -> FixityMap -> !Set String -> !Bool -> !Bool -> !Bool -> !SourceType -> !ColorMode -> !region -> Config region
+ Ormolu: Config :: ![DynOption] -> FixityMap -> !Set PackageName -> !Bool -> !Bool -> !Bool -> !SourceType -> !ColorMode -> !region -> Config region
- Ormolu: [cfgDependencies] :: Config region -> !Set String
+ Ormolu: [cfgDependencies] :: Config region -> !Set PackageName
- Ormolu: ormolu :: MonadIO m => Config RegionIndices -> FilePath -> String -> m Text
+ Ormolu: ormolu :: MonadIO m => Config RegionIndices -> FilePath -> Text -> m Text
- Ormolu.Config: Config :: ![DynOption] -> FixityMap -> !Set String -> !Bool -> !Bool -> !Bool -> !SourceType -> !ColorMode -> !region -> Config region
+ Ormolu.Config: Config :: ![DynOption] -> FixityMap -> !Set PackageName -> !Bool -> !Bool -> !Bool -> !SourceType -> !ColorMode -> !region -> Config region
- Ormolu.Config: [cfgDependencies] :: Config region -> !Set String
+ Ormolu.Config: [cfgDependencies] :: Config region -> !Set PackageName
- Ormolu.Fixity: HackageInfo :: Map String FixityMap -> Map String Int -> HackageInfo
+ Ormolu.Fixity: HackageInfo :: Map PackageName FixityMap -> Map PackageName Int -> HackageInfo
- Ormolu.Fixity: bootPackages :: Set String
+ Ormolu.Fixity: bootPackages :: Set PackageName
- Ormolu.Fixity: buildFixityMap :: Float -> Set String -> LazyFixityMap
+ Ormolu.Fixity: buildFixityMap :: Float -> Set PackageName -> LazyFixityMap
- Ormolu.Fixity: buildFixityMap' :: Map String FixityMap -> Map String Int -> Set String -> Float -> Set String -> LazyFixityMap
+ Ormolu.Fixity: buildFixityMap' :: Map PackageName FixityMap -> Map PackageName Int -> Set PackageName -> Float -> Set PackageName -> LazyFixityMap
- Ormolu.Fixity: lookupFixity :: String -> LazyFixityMap -> Maybe FixityInfo
+ Ormolu.Fixity: lookupFixity :: OpName -> LazyFixityMap -> Maybe FixityInfo
- Ormolu.Fixity: packageToOps :: Map String FixityMap
+ Ormolu.Fixity: packageToOps :: Map PackageName FixityMap
- Ormolu.Fixity: packageToPopularity :: Map String Int
+ Ormolu.Fixity: packageToPopularity :: Map PackageName Int
- Ormolu.Fixity: type FixityMap = Map String FixityInfo
+ Ormolu.Fixity: type FixityMap = Map OpName FixityInfo
- Ormolu.Fixity.Internal: HackageInfo :: Map String FixityMap -> Map String Int -> HackageInfo
+ Ormolu.Fixity.Internal: HackageInfo :: Map PackageName FixityMap -> Map PackageName Int -> HackageInfo
- Ormolu.Fixity.Internal: lookupFixity :: String -> LazyFixityMap -> Maybe FixityInfo
+ Ormolu.Fixity.Internal: lookupFixity :: OpName -> LazyFixityMap -> Maybe FixityInfo
- Ormolu.Fixity.Internal: type FixityMap = Map String FixityInfo
+ Ormolu.Fixity.Internal: type FixityMap = Map OpName FixityInfo
- Ormolu.Fixity.Parser: pFixity :: Parser [(String, FixityInfo)]
+ Ormolu.Fixity.Parser: pFixity :: Parser [(OpName, FixityInfo)]
- Ormolu.Fixity.Parser: pOperator :: Parser String
+ Ormolu.Fixity.Parser: pOperator :: Parser OpName
- Ormolu.Fixity.Parser: parseFixityDeclaration :: Text -> Either (ParseErrorBundle Text Void) [(String, FixityInfo)]
+ Ormolu.Fixity.Parser: parseFixityDeclaration :: Text -> Either (ParseErrorBundle Text Void) [(OpName, FixityInfo)]
- Ormolu.Parser: parseModule :: MonadIO m => Config RegionDeltas -> LazyFixityMap -> FilePath -> String -> m ([Warn], Either (SrcSpan, String) [SourceSnippet])
+ Ormolu.Parser: parseModule :: MonadIO m => Config RegionDeltas -> LazyFixityMap -> FilePath -> Text -> m ([Warn], Either (SrcSpan, String) [SourceSnippet])
- Ormolu.Parser.CommentStream: Comment :: Bool -> NonEmpty String -> Comment
+ Ormolu.Parser.CommentStream: Comment :: Bool -> NonEmpty Text -> Comment
- Ormolu.Parser.CommentStream: mkCommentStream :: String -> HsModule -> (Maybe (RealLocated Comment), [([RealLocated Comment], Pragma)], CommentStream)
+ Ormolu.Parser.CommentStream: mkCommentStream :: Text -> HsModule -> (Maybe (RealLocated Comment), [([RealLocated Comment], Pragma)], CommentStream)
- Ormolu.Parser.CommentStream: unComment :: Comment -> NonEmpty String
+ Ormolu.Parser.CommentStream: unComment :: Comment -> NonEmpty Text
- Ormolu.Parser.Pragma: PragmaLanguage :: [String] -> Pragma
+ Ormolu.Parser.Pragma: PragmaLanguage :: [Text] -> Pragma
- Ormolu.Parser.Pragma: PragmaOptionsGHC :: String -> Pragma
+ Ormolu.Parser.Pragma: PragmaOptionsGHC :: Text -> Pragma
- Ormolu.Parser.Pragma: PragmaOptionsHaddock :: String -> Pragma
+ Ormolu.Parser.Pragma: PragmaOptionsHaddock :: Text -> Pragma
- Ormolu.Parser.Pragma: parsePragma :: String -> Maybe Pragma
+ Ormolu.Parser.Pragma: parsePragma :: Text -> Maybe Pragma
- Ormolu.Printer.Operators: OpInfo :: op -> Maybe String -> FixityInfo -> OpInfo op
+ Ormolu.Printer.Operators: OpInfo :: op -> Maybe OpName -> FixityInfo -> OpInfo op
- Ormolu.Printer.Operators: [opiName] :: OpInfo op -> Maybe String
+ Ormolu.Printer.Operators: [opiName] :: OpInfo op -> Maybe OpName
- Ormolu.Processing.Common: linesInRegion :: RegionDeltas -> String -> String
+ Ormolu.Processing.Common: linesInRegion :: RegionDeltas -> Text -> Text
- Ormolu.Processing.Common: removeIndentation :: String -> (String, Int)
+ Ormolu.Processing.Common: removeIndentation :: Text -> (Text, Int)
- Ormolu.Processing.Cpp: cppLines :: String -> IntSet
+ Ormolu.Processing.Cpp: cppLines :: Text -> IntSet
- Ormolu.Processing.Preprocess: preprocess :: Bool -> RegionDeltas -> String -> [Either Text RegionDeltas]
+ Ormolu.Processing.Preprocess: preprocess :: Bool -> RegionDeltas -> Text -> [Either Text RegionDeltas]
- Ormolu.Utils.Cabal: CabalInfo :: !Maybe String -> ![DynOption] -> !Set String -> !Maybe FilePath -> CabalInfo
+ Ormolu.Utils.Cabal: CabalInfo :: !PackageName -> ![DynOption] -> !Set PackageName -> !FilePath -> CabalInfo
- Ormolu.Utils.Cabal: [ciCabalFilePath] :: CabalInfo -> !Maybe FilePath
+ Ormolu.Utils.Cabal: [ciCabalFilePath] :: CabalInfo -> !FilePath
- Ormolu.Utils.Cabal: [ciDependencies] :: CabalInfo -> !Set String
+ Ormolu.Utils.Cabal: [ciDependencies] :: CabalInfo -> !Set PackageName
- Ormolu.Utils.Cabal: [ciPackageName] :: CabalInfo -> !Maybe String
+ Ormolu.Utils.Cabal: [ciPackageName] :: CabalInfo -> !PackageName
- Ormolu.Utils.Cabal: getCabalInfoForSourceFile :: MonadIO m => FilePath -> m CabalInfo
+ Ormolu.Utils.Cabal: getCabalInfoForSourceFile :: MonadIO m => FilePath -> m CabalSearchResult
- Ormolu.Utils.Cabal: parseCabalInfo :: MonadIO m => FilePath -> FilePath -> m CabalInfo
+ Ormolu.Utils.Cabal: parseCabalInfo :: MonadIO m => FilePath -> FilePath -> m (Bool, CabalInfo)
- Ormolu.Utils.Fixity: parseFixityDeclarationStr :: String -> Either String [(String, FixityInfo)]
+ Ormolu.Utils.Fixity: parseFixityDeclarationStr :: String -> Either String [(OpName, FixityInfo)]
Files
- CHANGELOG.md +25/−0
- CONTRIBUTING.md +2/−2
- README.md +20/−18
- app/Main.hs +44/−45
- data/examples/declaration/class/default-signatures-simple-out.hs +1/−1
- data/examples/declaration/class/super-classes-out.hs +1/−1
- data/examples/declaration/data/existential-multiline-out.hs +1/−1
- data/examples/declaration/data/existential-out.hs +1/−1
- data/examples/declaration/instance/contexts-out.hs +1/−1
- data/examples/declaration/instance/newlines-between-methods-out.hs +1/−1
- data/examples/declaration/signature/specialize/specialize-instance-out.hs +1/−1
- data/examples/declaration/signature/specialize/specialize-out.hs +4/−4
- data/examples/declaration/signature/type/unicode-out.hs +1/−1
- data/examples/declaration/value/function/fancy-forall-0-out.hs +2/−2
- data/examples/declaration/value/function/fancy-forall-1-out.hs +2/−2
- data/examples/declaration/value/function/let-multi-line-out.hs +1/−1
- data/examples/other/argument-comment-out.hs +2/−2
- data/examples/other/comment-empty-let-out.hs +6/−0
- data/examples/other/comment-empty-let.hs +6/−0
- data/examples/other/cpp/separation-0a-out.hs +1/−1
- data/examples/other/cpp/separation-0b-out.hs +1/−1
- extract-hackage-info/hackage-info.bin binary
- ormolu.cabal +18/−6
- src/Ormolu.hs +76/−15
- src/Ormolu/Config.hs +2/−1
- src/Ormolu/Diff/ParseResult.hs +2/−2
- src/Ormolu/Exception.hs +1/−0
- src/Ormolu/Fixity.hs +47/−20
- src/Ormolu/Fixity/Internal.hs +49/−5
- src/Ormolu/Fixity/Parser.hs +15/−17
- src/Ormolu/Fixity/Printer.hs +8/−8
- src/Ormolu/Parser.hs +19/−13
- src/Ormolu/Parser/CommentStream.hs +46/−44
- src/Ormolu/Parser/Pragma.hs +21/−24
- src/Ormolu/Printer/Combinators.hs +2/−2
- src/Ormolu/Printer/Comments.hs +2/−3
- src/Ormolu/Printer/Internal.hs +2/−1
- src/Ormolu/Printer/Meat/Declaration.hs +2/−2
- src/Ormolu/Printer/Meat/Declaration/OpTree.hs +1/−1
- src/Ormolu/Printer/Meat/Declaration/Value.hs +7/−4
- src/Ormolu/Printer/Meat/Pragma.hs +9/−9
- src/Ormolu/Printer/Meat/Type.hs +2/−2
- src/Ormolu/Printer/Operators.hs +6/−7
- src/Ormolu/Printer/SpanStream.hs +1/−1
- src/Ormolu/Processing/Common.hs +8/−8
- src/Ormolu/Processing/Cpp.hs +7/−7
- src/Ormolu/Processing/Preprocess.hs +26/−27
- src/Ormolu/Utils.hs +23/−2
- src/Ormolu/Utils/Cabal.hs +54/−53
- src/Ormolu/Utils/Fixity.hs +20/−23
- src/Ormolu/Utils/IO.hs +4/−4
- tests/Ormolu/CabalInfoSpec.hs +26/−14
- tests/Ormolu/Fixity/ParserSpec.hs +11/−0
- tests/Ormolu/Fixity/PrinterSpec.hs +3/−1
- tests/Ormolu/HackageInfoSpec.hs +9/−7
- tests/Ormolu/OpTreeSpec.hs +10/−6
- tests/Ormolu/Parser/OptionsSpec.hs +4/−3
- tests/Ormolu/Parser/PragmaSpec.hs +6/−2
- tests/Ormolu/PrinterSpec.hs +2/−1
CHANGELOG.md view
@@ -1,3 +1,28 @@+## Ormolu 0.5.3.0++* Stop making empty `let`s move comments. [Issue+ 917](https://github.com/tweag/ormolu/issues/917).++* Now `.ormolu` fixity override files can use both LF and CRLF line endings.+ [PR 969](https://github.com/tweag/ormolu/pull/969).++* Normalize parentheses around constraints. [Issue+ 264](https://github.com/tweag/ormolu/issues/264).++* The `ormolu` function now consumes `Text` instead of `String` due to an+ internal refactoring.++* Exposed a more complete public API in the `Ormolu` module. The API is+ supposed to be stable and change according to+ [PVP](https://pvp.haskell.org/).++* Now warnings regarding Ormolu not being able to find `.cabal` files or+ finding such files but them not mentioning the source file in question are+ only displayed when `--debug` is used. Printing the warnings by default+ seems to have been confusing, see e.g. [Issue+ 971](https://github.com/tweag/ormolu/issues/971) and [issue+ 924](https://github.com/tweag/ormolu/issues/924).+ ## Ormolu 0.5.2.0 * Eliminated the `fixity-th` Cabal flag because it caused issues on GHC 9.4 as
CONTRIBUTING.md view
@@ -40,7 +40,7 @@ ## Formatting -Use `format.sh` script to format Ormolu with the current version of Ormolu.-If Ormolu is not formatted like this, the CI will fail.+Use `nix run .#format` script to format Ormolu with the current version of+Ormolu. If Ormolu is not formatted like this, the CI will fail. [issues]: https://github.com/tweag/ormolu/issues
README.md view
@@ -4,7 +4,7 @@ [](https://hackage.haskell.org/package/ormolu) [](http://stackage.org/nightly/package/ormolu) [](http://stackage.org/lts/package/ormolu)-[](https://buildkite.com/tweag-1/ormolu)+[](https://github.com/tweag/ormolu/actions/workflows/ci.yml) * [Installation](#installation) * [Building from source](#building-from-source)@@ -17,6 +17,7 @@ * [Magic comments](#magic-comments) * [Regions](#regions) * [Exit codes](#exit-codes)+ * [Using as a library](#using-as-a-library) * [Limitations](#limitations) * [Running on Hackage](#running-on-hackage) * [Forks and modifications](#forks-and-modifications)@@ -69,12 +70,11 @@ The easiest way to build the project is with Nix: ```console-$ nix-build -A ormolu+$ nix build ``` -Note that you will need to add [IOHK Hydra binary-cache][iohk-hydra-binary-cache], otherwise building may take a very long-time.+Make sure to accept the offered Nix caches (in particular the IOG cache),+otherwise building may take a very long time. Alternatively, `stack` could be used as follows: @@ -83,19 +83,15 @@ $ stack install # to install ``` -To use Ormolu directly from GitHub with Nix, this snippet may come in handy:+To use Ormolu directly from GitHub with Nix flakes, this snippet may come in handy: ```nix-let- pkgs = import <nixpkgs> { };- source = pkgs.fetchFromGitHub {- owner = "tweag";- repo = "ormolu";- rev = "c1d8a8083cf1492545b8deed342c6399fe9873ea"; # update as necessary- # do not forget to update the hash:- sha256 = "sha256-3XxKuWqZnFa9s3mY7OBD+uEn/fGxPmC8jdevx7exy9o=";- };-in (import source { }).ormoluExe # this is e.g. the executable derivation+{+ inputs.ormolu.url = "github:tweag/ormolu";+ outputs = { ormolu, ... }: {+ # use ormolu.packages.${system}.default here+ };+} ``` ## Usage@@ -248,6 +244,13 @@ 101 | Inplace mode does not work with stdin 102 | Other issue (with multiple input files) +### Using as a library++The `ormolu` package can also be depended upon from other Haskell programs.+For these purposes only the top `Ormolu` module should be considered stable.+It follows [PVP](https://pvp.haskell.org/) starting from the version+0.5.3.0. Rely on other modules at your own risk.+ ## Limitations * CPP support is experimental. CPP is virtually impossible to handle@@ -264,7 +267,7 @@ execute (from the root of the cloned repo): ```console-$ nix-build -A hackage.<package>+$ nix build .#hackage.<package> ``` Then inspect `result/log.txt` for possible problems. The derivation will@@ -293,7 +296,6 @@ [design-cpp]: https://github.com/tweag/ormolu/blob/master/DESIGN.md#cpp [emacs-package]: https://github.com/vyorkin/ormolu.el [haskell-src-exts]: https://hackage.haskell.org/package/haskell-src-exts-[iohk-hydra-binary-cache]: https://input-output-hk.github.io/haskell.nix/tutorials/getting-started.html#setting-up-the-binary-cache [neoformat]: https://github.com/sbdchd/neoformat [releases]: https://github.com/tweag/ormolu/releases [ormolu-action]: https://github.com/marketplace/actions/ormolu-action
app/Main.hs view
@@ -14,27 +14,23 @@ import Control.Monad import Data.Bool (bool) import Data.List (intercalate, sort)-import qualified Data.Map as Map-import Data.Maybe (fromMaybe, mapMaybe)+import qualified Data.Map.Strict as Map+import Data.Maybe (fromMaybe, mapMaybe, maybeToList) import qualified Data.Set as Set-import qualified Data.Text as T import qualified Data.Text.IO as TIO import Data.Version (showVersion)-import Development.GitRev+import Language.Haskell.TH.Env (envQ) import Options.Applicative import Ormolu import Ormolu.Diff.Text (diffText, printTextDiff)-import Ormolu.Fixity (FixityInfo)+import Ormolu.Fixity (FixityInfo, OpName) import Ormolu.Parser (manualExts) import Ormolu.Terminal import Ormolu.Utils (showOutputable)-import Ormolu.Utils.Cabal-import Ormolu.Utils.Fixity- ( getFixityOverridesForSourceFile,- parseFixityDeclarationStr,- )+import Ormolu.Utils.Fixity (parseFixityDeclarationStr) import Ormolu.Utils.IO import Paths_ormolu (version)+import System.Directory import System.Exit (ExitCode (..), exitWith) import qualified System.FilePath as FP import System.IO (hPutStrLn, stderr)@@ -84,15 +80,35 @@ IO ExitCode formatOne CabalOpts {..} mode reqSourceType rawConfig mpath = withPrettyOrmoluExceptions (cfgColorMode rawConfig) $ do+ let getCabalInfoForSourceFile' sourceFile = do+ cabalSearchResult <- getCabalInfoForSourceFile sourceFile+ let debugEnabled = cfgDebug rawConfig+ case cabalSearchResult of+ CabalNotFound -> do+ when debugEnabled $+ hPutStrLn stderr $+ "Could not find a .cabal file for " <> sourceFile+ return Nothing+ CabalDidNotMention cabalInfo -> do+ when debugEnabled $ do+ relativeCabalFile <-+ makeRelativeToCurrentDirectory (ciCabalFilePath cabalInfo)+ hPutStrLn stderr $+ "Found .cabal file "+ <> relativeCabalFile+ <> ", but it did not mention "+ <> sourceFile+ return (Just cabalInfo)+ CabalFound cabalInfo -> return (Just cabalInfo) case FP.normalise <$> mpath of -- input source = STDIN Nothing -> do resultConfig <- ( if optDoNotUseCabal- then pure defaultCabalInfo+ then pure Nothing else case optStdinInputFile of Just stdinInputFile ->- getCabalInfoForSourceFile stdinInputFile+ getCabalInfoForSourceFile' stdinInputFile Nothing -> throwIO OrmoluMissingStdinInputFile ) >>= patchConfig Nothing@@ -111,14 +127,14 @@ originalInput <- getContentsUtf8 let stdinRepr = "<stdin>" formattedInput <-- ormolu resultConfig stdinRepr (T.unpack originalInput)+ ormolu resultConfig stdinRepr originalInput handleDiff originalInput formattedInput stdinRepr -- input source = a file Just inputFile -> do resultConfig <- ( if optDoNotUseCabal- then pure defaultCabalInfo- else getCabalInfoForSourceFile inputFile+ then pure Nothing+ else getCabalInfoForSourceFile' inputFile ) >>= patchConfig (Just (detectSourceType inputFile)) case mode of@@ -129,7 +145,7 @@ -- ormoluFile is not used because we need originalInput originalInput <- readFileUtf8 inputFile formattedInput <-- ormolu resultConfig inputFile (T.unpack originalInput)+ ormolu resultConfig inputFile originalInput when (formattedInput /= originalInput) $ writeFileUtf8 inputFile formattedInput return ExitSuccess@@ -137,30 +153,16 @@ -- ormoluFile is not used because we need originalInput originalInput <- readFileUtf8 inputFile formattedInput <-- ormolu resultConfig inputFile (T.unpack originalInput)+ ormolu resultConfig inputFile originalInput handleDiff originalInput formattedInput inputFile where- patchConfig mdetectedSourceType cabalInfo@CabalInfo {..} = do- let depsFromCabal =- -- It makes sense to take into account the operator info for the- -- package itself if we know it, as if it were its own- -- dependency.- case ciPackageName of- Nothing -> ciDependencies- Just p -> Set.insert p ciDependencies- fixityOverrides <- getFixityOverridesForSourceFile cabalInfo- return- rawConfig- { cfgDynOptions = cfgDynOptions rawConfig ++ ciDynOpts,- cfgFixityOverrides =- Map.unionWith (<>) (cfgFixityOverrides rawConfig) fixityOverrides,- cfgDependencies =- Set.union (cfgDependencies rawConfig) depsFromCabal,- cfgSourceType =- fromMaybe- ModuleSource- (reqSourceType <|> mdetectedSourceType)- }+ patchConfig mdetectedSourceType mcabalInfo = do+ let sourceType =+ fromMaybe+ ModuleSource+ (reqSourceType <|> mdetectedSourceType)+ mfixityOverrides <- traverse getFixityOverridesForSourceFile mcabalInfo+ return (refineConfig sourceType mcabalInfo mfixityOverrides rawConfig) handleDiff originalInput formattedInput fileRepr = case diffText originalInput formattedInput fileRepr of Nothing -> return ExitSuccess@@ -224,12 +226,9 @@ verStr = intercalate "\n"- [ unwords- [ "ormolu",- showVersion version,- $gitBranch,- $gitHash- ],+ [ unwords $+ ["ormolu", showVersion version]+ <> maybeToList $$(envQ @String "ORMOLU_REV"), "using ghc-lib-parser " ++ VERSION_ghc_lib_parser ] exts :: Parser (a -> a)@@ -362,7 +361,7 @@ s -> Left $ "unknown mode: " ++ s -- | Parse a fixity declaration.-parseFixityDeclaration :: ReadM [(String, FixityInfo)]+parseFixityDeclaration :: ReadM [(OpName, FixityInfo)] parseFixityDeclaration = eitherReader parseFixityDeclarationStr -- | Parse 'ColorMode'.
data/examples/declaration/class/default-signatures-simple-out.hs view
@@ -4,5 +4,5 @@ class Foo a where -- | Foo foo :: a -> String- default foo :: Show a => a -> String+ default foo :: (Show a) => a -> String foo = show
data/examples/declaration/class/super-classes-out.hs view
@@ -1,6 +1,6 @@ class Foo a -class Foo a => Bar a+class (Foo a) => Bar a class (Foo a, Bar a) =>
data/examples/declaration/data/existential-multiline-out.hs view
@@ -2,7 +2,7 @@ data Foo = forall a. MkFoo a (a -> Bool)- | forall a. Eq a => MkBar a+ | forall a. (Eq a) => MkBar a data Bar = forall x y.
data/examples/declaration/data/existential-out.hs view
@@ -2,4 +2,4 @@ data Foo = forall a. MkFoo a (a -> Bool) -data Bar = forall a b. a + b => Bar a b+data Bar = forall a b. (a + b) => Bar a b
data/examples/declaration/instance/contexts-out.hs view
@@ -1,4 +1,4 @@-instance Eq a => Eq [a] where (==) _ _ = False+instance (Eq a) => Eq [a] where (==) _ _ = False instance ( Ord a,
data/examples/declaration/instance/newlines-between-methods-out.hs view
@@ -1,4 +1,4 @@-instance Num a => Num (Diff a) where+instance (Num a) => Num (Diff a) where D u dudx + D v dvdx = D (u + v) (dudx + dvdx) D u dudx - D v dvdx = D (u - v) (dudx - dvdx) D u dudx * D v dvdx = D (u * v) (u * dvdx + v * dudx)
data/examples/declaration/signature/specialize/specialize-instance-out.hs view
@@ -8,7 +8,7 @@ instance (Num r, V.Vector v r, Factored m r) => Num (VT v m r) where {-# SPECIALIZE instance- ( Factored m Int => Num (VT U.Vector m Int)+ ( (Factored m Int) => Num (VT U.Vector m Int) ) #-} VT x + VT y = VT $ V.zipWith (+) x y
data/examples/declaration/signature/specialize/specialize-out.hs view
@@ -1,13 +1,13 @@-foo :: Num a => a -> a+foo :: (Num a) => a -> a foo = id {-# SPECIALIZE foo :: Int -> Int #-} {-# SPECIALIZE INLINE foo :: Float -> Float #-} {-# SPECIALIZE NOINLINE [2] bar :: Int -> Int #-}-bar :: Num a => a -> a+bar :: (Num a) => a -> a bar = id -baz :: Num a => a -> a+baz :: (Num a) => a -> a baz = id {-# SPECIALIZE [~2] baz :: Int ->@@ -20,5 +20,5 @@ Bool, Integer -> Bool #-}-fits13Bits :: Integral a => a -> Bool+fits13Bits :: (Integral a) => a -> Bool fits13Bits x = x >= -4096 && x < 4096
data/examples/declaration/signature/type/unicode-out.hs view
@@ -1,4 +1,4 @@ {-# LANGUAGE UnicodeSyntax #-} -foo :: forall a. Show a => a -> String+foo :: forall a. (Show a) => a -> String foo = const ()
data/examples/declaration/value/function/fancy-forall-0-out.hs view
@@ -2,9 +2,9 @@ forall outertag innertag t outer inner m a. ( forall x. Coercible (t m x) (m x), forall m'.- HasCatch outertag outer m' =>+ (HasCatch outertag outer m') => HasCatch innertag inner (t m'), HasCatch outertag outer m ) =>- (forall m'. HasCatch innertag inner m' => m' a) ->+ (forall m'. (HasCatch innertag inner m') => m' a) -> m a
data/examples/declaration/value/function/fancy-forall-1-out.hs view
@@ -2,9 +2,9 @@ forall outertag innertag t outer inner m a. ( forall x. Coercible (t m x) (m x), forall m'.- HasReader outertag outer m' =>+ (HasReader outertag outer m') => HasReader innertag inner (t m'), HasReader outertag outer m ) =>- (forall m'. HasReader innertag inner m' => m' a) ->+ (forall m'. (HasReader innertag inner m') => m' a) -> m a
data/examples/declaration/value/function/let-multi-line-out.hs view
@@ -17,7 +17,7 @@ () -> undefined in go -implicitParams :: HasCallStack => Int+implicitParams :: (HasCallStack) => Int implicitParams = let ?cs = ?callstack in foo cs
data/examples/other/argument-comment-out.hs view
@@ -5,12 +5,12 @@ foo _ = True foo ::- Foo a =>+ (Foo a) => -- | Foo Int -> Int foo ::- Foo a =>+ (Foo a) => -- | Foo Int -> Int
+ data/examples/other/comment-empty-let-out.hs view
@@ -0,0 +1,6 @@+foo =+ let+ in 10++-- a comment+bar = 20
+ data/examples/other/comment-empty-let.hs view
@@ -0,0 +1,6 @@+foo =+ let+ in 10++-- a comment+bar = 20
data/examples/other/cpp/separation-0a-out.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE CPP #-} -instance Stream s => Monad (ParsecT e s m) where+instance (Stream s) => Monad (ParsecT e s m) where return = pure (>>=) = pBind #if !(MIN_VERSION_base(4,13,0))
data/examples/other/cpp/separation-0b-out.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE CPP #-} -instance Stream s => Monad (ParsecT e s m) where+instance (Stream s) => Monad (ParsecT e s m) where return = pure (>>=) = pBind #if !(MIN_VERSION_base(4,13,0))
extract-hackage-info/hackage-info.bin view
binary file changed (1292114 → 1292137 bytes)
ormolu.cabal view
@@ -1,10 +1,10 @@ cabal-version: 2.4 name: ormolu-version: 0.5.2.0+version: 0.5.3.0 license: BSD-3-Clause license-file: LICENSE.md maintainer: Mark Karpov <mark.karpov@tweag.io>-tested-with: ghc ==9.0.2 ghc ==9.2.4+tested-with: ghc ==9.0.2 ghc ==9.2.5 homepage: https://github.com/tweag/ormolu bug-reports: https://github.com/tweag/ormolu/issues synopsis: A formatter for Haskell source code@@ -32,6 +32,13 @@ default: False manual: True +flag internal-bundle-fixities+ description:+ An internal ad-hoc flag that is enabled by default, Ormolu Live disables+ it due to missing WASM TH support.++ manual: True+ library exposed-modules: Ormolu@@ -105,7 +112,7 @@ megaparsec >=9.0, mtl >=2.0 && <3.0, syb >=0.7 && <0.8,- text >=0.2 && <3.0+ text >=2.0 && <3.0 if flag(dev) ghc-options:@@ -116,6 +123,9 @@ else ghc-options: -O2 -Wall + if flag(internal-bundle-fixities)+ cpp-options: -DBUNDLE_FIXITIES+ executable ormolu main-is: Main.hs hs-source-dirs: app@@ -125,12 +135,13 @@ build-depends: base >=4.12 && <5.0, containers >=0.5 && <0.7,+ directory ^>=1.3, filepath >=1.2 && <1.5, ghc-lib-parser >=9.4 && <9.5,- gitrev >=1.3 && <1.4,+ th-env >=0.1.1 && <0.2, optparse-applicative >=0.14 && <0.18, ormolu,- text >=0.2 && <3.0+ text >=2.0 && <3.0 if flag(dev) ghc-options:@@ -161,6 +172,7 @@ default-language: Haskell2010 build-depends:+ Cabal-syntax >=3.8 && <3.9, QuickCheck >=2.14, base >=4.14 && <5.0, containers >=0.5 && <0.7,@@ -173,7 +185,7 @@ path >=0.6 && <0.10, path-io >=1.4.2 && <2.0, temporary ^>=1.3,- text >=0.2 && <3.0+ text >=2.0 && <3.0 if flag(dev) ghc-options: -Wall -Werror -Wunused-packages
src/Ormolu.hs view
@@ -1,18 +1,35 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RecordWildCards #-} --- | A formatter for Haskell source code.+-- | A formatter for Haskell source code. This module exposes the official+-- stable API, other modules may be not as reliable. module Ormolu- ( ormolu,+ ( -- * Top-level formatting functions+ ormolu, ormoluFile, ormoluStdin,++ -- * Configuration Config (..), ColorMode (..), RegionIndices (..), SourceType (..), defaultConfig, detectSourceType,+ refineConfig, DynOption (..),++ -- * Cabal info+ CabalUtils.CabalSearchResult (..),+ CabalUtils.CabalInfo (..),+ CabalUtils.getCabalInfoForSourceFile,++ -- * Fixity overrides+ FixityMap,+ getFixityOverridesForSourceFile,++ -- * Working with exceptions OrmoluException (..), withPrettyOrmoluExceptions, )@@ -21,6 +38,8 @@ import Control.Exception import Control.Monad import Control.Monad.IO.Class (MonadIO (..))+import qualified Data.Map.Strict as Map+import qualified Data.Set as Set import Data.Text (Text) import qualified Data.Text as T import Debug.Trace@@ -36,14 +55,15 @@ import Ormolu.Parser.Result import Ormolu.Printer import Ormolu.Utils (showOutputable)+import qualified Ormolu.Utils.Cabal as CabalUtils+import Ormolu.Utils.Fixity (getFixityOverridesForSourceFile) import Ormolu.Utils.IO import System.FilePath --- | Format a 'String', return formatted version as 'Text'.+-- | Format a 'Text'. -- -- The function ----- * Takes 'String' because that's what GHC parser accepts. -- * Needs 'IO' because some functions from GHC that are necessary to -- setup parsing context require 'IO'. There should be no visible -- side-effects though.@@ -54,16 +74,16 @@ -- the 'cfgSourceType' field. Autodetection of source type won't happen -- here, see 'detectSourceType'. ormolu ::- MonadIO m =>+ (MonadIO m) => -- | Ormolu configuration Config RegionIndices -> -- | Location of source file FilePath -> -- | Input to format- String ->+ Text -> m Text ormolu cfgWithIndices path originalInput = do- let totalLines = length (lines originalInput)+ let totalLines = length (T.lines originalInput) cfg = regionIndicesToDeltas totalLines <$> cfgWithIndices fixityMap = -- It is important to keep all arguments (but last) of@@ -95,9 +115,9 @@ fixityMap OrmoluOutputParsingFailed path- (T.unpack formattedText)+ formattedText unless (cfgUnsafe cfg) . liftIO $ do- let diff = case diffText (T.pack originalInput) formattedText path of+ let diff = case diffText originalInput formattedText path of Nothing -> error "AST differs, yet no changes have been introduced" Just x -> x when (length result0 /= length result1) $@@ -124,7 +144,7 @@ -- the 'cfgSourceType' field. Autodetection of source type won't happen -- here, see 'detectSourceType'. ormoluFile ::- MonadIO m =>+ (MonadIO m) => -- | Ormolu configuration Config RegionIndices -> -- | Location of source file@@ -132,7 +152,7 @@ -- | Resulting rendition m Text ormoluFile cfg path =- readFileUtf8 path >>= ormolu cfg path . T.unpack+ readFileUtf8 path >>= ormolu cfg path -- | Read input from stdin and format it. --@@ -140,20 +160,61 @@ -- the 'cfgSourceType' field. Autodetection of source type won't happen -- here, see 'detectSourceType'. ormoluStdin ::- MonadIO m =>+ (MonadIO m) => -- | Ormolu configuration Config RegionIndices -> -- | Resulting rendition m Text ormoluStdin cfg =- getContentsUtf8 >>= ormolu cfg "<stdin>" . T.unpack+ getContentsUtf8 >>= ormolu cfg "<stdin>" +-- | Refine a 'Config' by incorporating given 'SourceType', 'CabalInfo', and+-- fixity overrides 'FixityMap'. You can use 'detectSourceType' to deduce+-- 'SourceType' based on the file extension,+-- 'CabalUtils.getCabalInfoForSourceFile' to obtain 'CabalInfo' and+-- 'getFixityOverridesForSourceFile' for 'FixityMap'.+--+-- @since 0.5.3.0+refineConfig ::+ -- | Source type to use+ SourceType ->+ -- | Cabal info for the file, if available+ Maybe CabalUtils.CabalInfo ->+ -- | Fixity overrides, if available+ Maybe FixityMap ->+ -- | 'Config' to refine+ Config region ->+ -- | Refined 'Config'+ Config region+refineConfig sourceType mcabalInfo mfixityOverrides rawConfig =+ rawConfig+ { cfgDynOptions = cfgDynOptions rawConfig ++ dynOptsFromCabal,+ cfgFixityOverrides =+ Map.unionWith (<>) (cfgFixityOverrides rawConfig) fixityOverrides,+ cfgDependencies =+ Set.union (cfgDependencies rawConfig) depsFromCabal,+ cfgSourceType = sourceType+ }+ where+ fixityOverrides =+ case mfixityOverrides of+ Nothing -> Map.empty+ Just x -> x+ (dynOptsFromCabal, depsFromCabal) =+ case mcabalInfo of+ Nothing -> ([], Set.empty)+ Just CabalUtils.CabalInfo {..} ->+ -- It makes sense to take into account the operator info for the+ -- package itself if we know it, as if it were its own+ -- dependency.+ (ciDynOpts, Set.insert ciPackageName ciDependencies)+ ---------------------------------------------------------------------------- -- Helpers -- | A wrapper around 'parseModule'. parseModule' ::- MonadIO m =>+ (MonadIO m) => -- | Ormolu configuration Config RegionDeltas -> -- | Fixity Map for operators@@ -163,7 +224,7 @@ -- | File name to use in errors FilePath -> -- | Actual input for the parser- String ->+ Text -> m ([GHC.Warn], [SourceSnippet]) parseModule' cfg fixityMap mkException path str = do (warnings, r) <- parseModule cfg fixityMap path str
src/Ormolu/Config.hs view
@@ -19,6 +19,7 @@ import qualified Data.Map.Strict as Map import Data.Set (Set) import qualified Data.Set as Set+import Distribution.Types.PackageName (PackageName) import GHC.Generics (Generic) import qualified GHC.Types.SrcLoc as GHC import Ormolu.Fixity (FixityMap)@@ -39,7 +40,7 @@ -- | Fixity overrides cfgFixityOverrides :: FixityMap, -- | Known dependencies, if any- cfgDependencies :: !(Set String),+ cfgDependencies :: !(Set PackageName), -- | Do formatting faster but without automatic detection of defects cfgUnsafe :: !Bool, -- | Output information useful for debugging
src/Ormolu/Diff/ParseResult.hs view
@@ -74,7 +74,7 @@ -- * LayoutInfo (brace style) in extension fields -- * Empty contexts in type classes -- * Parens around derived type classes-matchIgnoringSrcSpans :: Data a => a -> a -> ParseResultDiff+matchIgnoringSrcSpans :: (Data a) => a -> a -> ParseResultDiff matchIgnoringSrcSpans a = genericQuery a where genericQuery :: GenericQ (GenericQ ParseResultDiff)@@ -150,7 +150,7 @@ unicodeArrowStyleEq (HsLinearArrow _) (castArrow -> Just (HsLinearArrow _)) = Same unicodeArrowStyleEq (HsExplicitMult _ _ t) (castArrow -> Just (HsExplicitMult _ _ t')) = genericQuery t t' unicodeArrowStyleEq _ _ = Different []- castArrow :: Typeable a => a -> Maybe (HsArrow GhcPs)+ castArrow :: (Typeable a) => a -> Maybe (HsArrow GhcPs) castArrow = cast -- LayoutInfo ~ XClassDecl GhcPs tracks brace information layoutInfoEq :: LayoutInfo -> GenericQ ParseResultDiff
src/Ormolu/Exception.hs view
@@ -4,6 +4,7 @@ -- | 'OrmoluException' type and surrounding definitions. module Ormolu.Exception ( OrmoluException (..),+ printOrmoluException, withPrettyOrmoluExceptions, ) where
src/Ormolu/Fixity.hs view
@@ -1,10 +1,17 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE TemplateHaskell #-} -- | Definitions for fixity analysis. module Ormolu.Fixity- ( FixityDirection (..),+ ( OpName,+ pattern OpName,+ unOpName,+ occOpName,+ FixityDirection (..), FixityInfo (..), FixityMap, LazyFixityMap,@@ -23,31 +30,51 @@ import qualified Data.Binary as Binary import qualified Data.Binary.Get as Binary import qualified Data.ByteString.Lazy as BL-import Data.FileEmbed (embedFile) import Data.Foldable (foldl') import Data.List.NonEmpty (NonEmpty ((:|))) import qualified Data.List.NonEmpty as NE import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import Data.Maybe (fromMaybe)-import Data.MemoTrie (HasTrie, memo)+import Data.MemoTrie (memo) import Data.Semigroup (sconcat) import Data.Set (Set) import qualified Data.Set as Set+import Distribution.Types.PackageName (PackageName, mkPackageName, unPackageName) import Ormolu.Fixity.Internal+#if BUNDLE_FIXITIES+import Data.FileEmbed (embedFile)+#else+import qualified Data.ByteString.Unsafe as BU+import Foreign.Ptr+import System.Environment (getEnv)+import System.IO.Unsafe (unsafePerformIO)+#endif -packageToOps :: Map String FixityMap-packageToPopularity :: Map String Int+packageToOps :: Map PackageName FixityMap+packageToPopularity :: Map PackageName Int+#if BUNDLE_FIXITIES HackageInfo packageToOps packageToPopularity = Binary.runGet Binary.get $ BL.fromStrict $(embedFile "extract-hackage-info/hackage-info.bin")+#else+-- The GHC WASM backend does not yet support Template Haskell, so we instead+-- pass in the encoded fixity DB at runtime by storing the pointer and length of+-- the bytes in an environment variable.+HackageInfo packageToOps packageToPopularity = unsafePerformIO $ do+ (ptr, len) <- read <$> getEnv "ORMOLU_HACKAGE_INFO"+ Binary.runGet Binary.get . BL.fromStrict+ <$> BU.unsafePackMallocCStringLen (intPtrToPtr $ IntPtr ptr, len)+{-# NOINLINE packageToOps #-}+{-# NOINLINE packageToPopularity #-}+#endif -- | List of packages shipped with GHC, for which the download count from -- Hackage does not reflect their high popularity. -- See https://github.com/tweag/ormolu/pull/830#issuecomment-986609572. -- "base" is not is this list, because it is already whitelisted -- by buildFixityMap'.-bootPackages :: Set String+bootPackages :: Set PackageName bootPackages = Set.fromList [ "array",@@ -87,7 +114,7 @@ -- instead of being merged with them Float -> -- | Explicitly known dependencies- Set String ->+ Set PackageName -> -- | Resulting map LazyFixityMap buildFixityMap = buildFixityMap' packageToOps packageToPopularity bootPackages@@ -98,17 +125,17 @@ -- specify the package databases used to build the final fixity map. buildFixityMap' :: -- | Map from package to fixity map for operators defined in this package- Map String FixityMap ->+ Map PackageName FixityMap -> -- | Map from package to popularity- Map String Int ->+ Map PackageName Int -> -- | Higher priority packages- Set String ->+ Set PackageName -> -- | Popularity ratio threshold, after which a very popular package will -- completely rule out conflicting definitions coming from other packages -- instead of being merged with them Float -> -- | Explicitly known dependencies- Set String ->+ Set PackageName -> -- | Resulting map LazyFixityMap buildFixityMap'@@ -147,8 +174,8 @@ remainingFixityMap ] -memoSet :: (HasTrie a, Eq a) => (Set a -> v) -> Set a -> v-memoSet f = memo (f . Set.fromAscList) . Set.toAscList+memoSet :: (Set PackageName -> v) -> Set PackageName -> v+memoSet f = memo (f . Set.fromAscList . fmap mkPackageName) . fmap unPackageName . Set.toAscList -- | Merge a list of individual fixity maps, coming from different packages. -- Package popularities and the given threshold are used to choose between@@ -156,11 +183,11 @@ -- strategies when conflicting definitions are encountered for an operator. mergeFixityMaps :: -- | Map from package name to 30-days download count- Map String Int ->+ Map PackageName Int -> -- | Popularity ratio threshold Float -> -- | List of (package name, package fixity map) to merge- [(String, FixityMap)] ->+ [(PackageName, FixityMap)] -> -- | Resulting fixity map FixityMap mergeFixityMaps popularityMap threshold packageMaps =@@ -174,7 +201,7 @@ -- op1 -map-> {definitions1 -map-> originPackages} -- op1 -map-> {definitions2 -map-> originPackages} -- so we merge the keys (which have the type:- -- Map FixityInfo (NonEmpty String))+ -- Map FixityInfo (NonEmpty PackageName)) -- using 'Map.unionWith (<>)', to "concatenate" the list of -- definitions for this operator, and to also "concatenate" origin -- packages if a same definition is found in both maps@@ -202,7 +229,7 @@ getScores :: -- Map for a given operator associating each of its conflicting -- definitions with the packages that define it- Map FixityInfo (NonEmpty String) ->+ Map FixityInfo (NonEmpty PackageName) -> -- Map for a given operator associating each of its conflicting -- definitions with their score (= sum of the popularity of the -- packages that define it)@@ -212,18 +239,18 @@ (sum . fmap (fromMaybe 0 . flip Map.lookup popularityMap)) opFixityMapFrom :: -- (packageName, package fixity map)- (String, FixityMap) ->+ (PackageName, FixityMap) -> -- Map associating each operator of the package with a -- {map for a given operator associating each of its definitions with -- the list of packages that define it} -- (this list can only be == [packageName] in the context of this -- function)- Map String (Map FixityInfo (NonEmpty String))+ Map OpName (Map FixityInfo (NonEmpty PackageName)) opFixityMapFrom (packageName, opsMap) = Map.map (flip Map.singleton (packageName :| [])) opsMap- maxWith :: Ord b => (a -> b) -> NonEmpty a -> NonEmpty a+ maxWith :: (Ord b) => (a -> b) -> NonEmpty a -> NonEmpty a maxWith f xs = snd $ foldl' comp (f h, h :| []) t where h :| t = xs
src/Ormolu/Fixity/Internal.hs view
@@ -1,12 +1,19 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ViewPatterns #-} module Ormolu.Fixity.Internal- ( FixityDirection (..),+ ( OpName,+ pattern OpName,+ unOpName,+ occOpName,+ FixityDirection (..), FixityInfo (..), defaultFixityInfo, colonFixityInfo,@@ -18,10 +25,19 @@ where import Data.Binary (Binary)+import Data.ByteString.Short (ShortByteString)+import qualified Data.ByteString.Short as SBS import Data.Foldable (asum) import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map+import Data.String (IsString (..))+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import Distribution.Types.PackageName (PackageName)+import GHC.Data.FastString (fs_sbs) import GHC.Generics (Generic)+import GHC.Types.Name (OccName (occNameFS)) -- | Fixity direction. data FixityDirection@@ -79,8 +95,36 @@ (Just a, Just b) | a == b -> Just a _ -> Nothing +-- | An operator name.+newtype OpName = MkOpName+ { -- | Invariant: UTF-8 encoded+ getOpName :: ShortByteString+ }+ deriving newtype (Eq, Ord, Binary)++-- | Convert an 'OpName' to 'Text'.+unOpName :: OpName -> Text+unOpName = T.decodeUtf8 . SBS.fromShort . getOpName++pattern OpName :: Text -> OpName+pattern OpName opName <- (unOpName -> opName)+ where+ OpName = MkOpName . SBS.toShort . T.encodeUtf8++{-# COMPLETE OpName #-}++-- | Convert an 'OccName to an 'OpName'.+occOpName :: OccName -> OpName+occOpName = MkOpName . fs_sbs . occNameFS++instance Show OpName where+ show = T.unpack . unOpName++instance IsString OpName where+ fromString = OpName . T.pack+ -- | Map from the operator name to its 'FixityInfo'.-type FixityMap = Map String FixityInfo+type FixityMap = Map OpName FixityInfo -- | A variant of 'FixityMap', represented as a lazy union of several -- 'FixityMap's.@@ -89,16 +133,16 @@ -- | Lookup a 'FixityInfo' of an operator. This might have drastically -- different performance depending on whether this is an "unusual" operator.-lookupFixity :: String -> LazyFixityMap -> Maybe FixityInfo+lookupFixity :: OpName -> LazyFixityMap -> Maybe FixityInfo lookupFixity op (LazyFixityMap maps) = asum (Map.lookup op <$> maps) -- | The map of operators declared by each package and the popularity of -- each package, if available. data HackageInfo = HackageInfo- (Map String FixityMap)+ (Map PackageName FixityMap) -- ^ Map from package name to a map from operator name to its fixity- (Map String Int)+ (Map PackageName Int) -- ^ Map from package name to its 30-days download count from Hackage deriving stock (Generic) deriving anyclass (Binary)
src/Ormolu/Fixity/Parser.hs view
@@ -16,8 +16,9 @@ import qualified Data.Char as Char import qualified Data.Map.Strict as Map import Data.Text (Text)+import qualified Data.Text as T import Data.Void (Void)-import Ormolu.Fixity.Internal+import Ormolu.Fixity import Text.Megaparsec import Text.Megaparsec.Char import qualified Text.Megaparsec.Char.Lexer as L@@ -39,19 +40,19 @@ -- | Expression to parse Text -> -- | Parse result- Either (ParseErrorBundle Text Void) [(String, FixityInfo)]+ Either (ParseErrorBundle Text Void) [(OpName, FixityInfo)] parseFixityDeclaration = runParser (pFixity <* eof) "" pFixityMap :: Parser FixityMap pFixityMap = Map.fromListWith (<>) . mconcat- <$> many (pFixity <* newline <* hidden space)+ <$> many (pFixity <* eol <* hidden space) <* eof -- | Parse a single fixity declaration, such as -- -- > infixr 4 +++, >>>-pFixity :: Parser [(String, FixityInfo)]+pFixity :: Parser [(OpName, FixityInfo)] pFixity = do fiDirection <- Just <$> pFixityDirection hidden hspace1@@ -72,19 +73,16 @@ ] -- | See <https://www.haskell.org/onlinereport/haskell2010/haskellch2.html>-pOperator :: Parser String-pOperator = tickedOperator <|> normalOperator+pOperator :: Parser OpName+pOperator = OpName <$> (tickedOperator <|> normalOperator) where tickedOperator = between tick tick haskellIdentifier tick = char '`'- haskellIdentifier = do- x <- letterChar- xs <- many (alphaNumChar <|> char '_' <|> char '\'')- return (x : xs)- normalOperator = some operatorChar- operatorChar =- satisfy- (\x -> (Char.isSymbol x || Char.isPunctuation x) && isNotExcluded x)- <?> "operator character"- where- isNotExcluded x = x /= ',' && x /= '`' && x /= '(' && x /= ')'+ haskellIdentifier =+ T.cons+ <$> letterChar+ <*> takeWhileP Nothing (\x -> Char.isAlphaNum x || x == '_' || x == '\'')+ normalOperator =+ takeWhile1P (Just "operator character") $ \x ->+ (Char.isSymbol x || Char.isPunctuation x)+ && (x /= ',' && x /= '`' && x /= '(' && x /= ')')
src/Ormolu/Fixity/Printer.hs view
@@ -10,11 +10,12 @@ import qualified Data.Char as Char import qualified Data.Map.Strict as Map import Data.Text (Text)+import qualified Data.Text as T import qualified Data.Text.Lazy as TL import Data.Text.Lazy.Builder (Builder) import qualified Data.Text.Lazy.Builder as B import qualified Data.Text.Lazy.Builder.Int as B-import Ormolu.Fixity.Internal+import Ormolu.Fixity -- | Print out a textual representation of a 'FixityMap'. printFixityMap :: FixityMap -> Text@@ -26,7 +27,7 @@ . concatMap decompose . Map.toList where- decompose :: (String, FixityInfo) -> [(FixityDirection, Int, String)]+ decompose :: (OpName, FixityInfo) -> [(FixityDirection, Int, OpName)] decompose (operator, FixityInfo {..}) = let forDirection dir = (dir, fiMinPrecedence, operator)@@ -36,8 +37,8 @@ in case fiDirection of Nothing -> concatMap forDirection [InfixL, InfixR] Just dir -> forDirection dir- renderOne :: (FixityDirection, Int, String) -> Builder- renderOne (fixityDirection, n, operator) =+ renderOne :: (FixityDirection, Int, OpName) -> Builder+ renderOne (fixityDirection, n, OpName operator) = mconcat [ case fixityDirection of InfixL -> "infixl"@@ -47,9 +48,8 @@ B.decimal n, " ", if isTickedOperator operator- then "`" <> B.fromString operator <> "`"- else B.fromString operator,+ then "`" <> B.fromText operator <> "`"+ else B.fromText operator, "\n" ]- isTickedOperator [] = True- isTickedOperator (x : _) = Char.isLetter x+ isTickedOperator = maybe True (Char.isLetter . fst) . T.uncons
src/Ormolu/Parser.hs view
@@ -13,16 +13,18 @@ where import Control.Exception-import Control.Monad.Except+import Control.Monad+import Control.Monad.Except (ExceptT (..), runExceptT)+import Control.Monad.IO.Class import Data.Char (isSpace) import Data.Functor import Data.Generics import qualified Data.List as L import qualified Data.List.NonEmpty as NE+import Data.Text (Text) import GHC.Data.Bag (bagToList) import qualified GHC.Data.EnumSet as EnumSet import qualified GHC.Data.FastString as GHC-import qualified GHC.Data.StringBuffer as GHC import qualified GHC.Driver.CmdLine as GHC import GHC.Driver.Config.Parser (initParserOpts) import GHC.Driver.Session as GHC@@ -46,11 +48,11 @@ import Ormolu.Parser.Result import Ormolu.Processing.Common import Ormolu.Processing.Preprocess-import Ormolu.Utils (incSpanLine, showOutputable)+import Ormolu.Utils (incSpanLine, showOutputable, textToStringBuffer) -- | Parse a complete module from string. parseModule ::- MonadIO m =>+ (MonadIO m) => -- | Ormolu configuration Config RegionDeltas -> -- | Fixity map to include in the resulting 'ParseResult's@@ -58,7 +60,7 @@ -- | File name (only for source location annotations) FilePath -> -- | Input for parser- String ->+ Text -> m ( [GHC.Warn], Either (SrcSpan, String) [SourceSnippet]@@ -90,12 +92,12 @@ pure (warnings, snippets) parseModuleSnippet ::- MonadIO m =>+ (MonadIO m) => Config RegionDeltas -> LazyFixityMap -> DynFlags -> FilePath ->- String ->+ Text -> m (Either (SrcSpan, String) ParseResult) parseModuleSnippet Config {..} fixityMap dynFlags path rawInput = liftIO $ do let (input, indent) = removeIndentation . linesInRegion cfgRegion $ rawInput@@ -153,7 +155,7 @@ normalizeModule :: HsModule -> HsModule normalizeModule hsmod = everywhere- (mkT dropBlankTypeHaddocks)+ (extT (mkT dropBlankTypeHaddocks) patchContext) hsmod { hsmodImports = normalizeImports (hsmodImports hsmod),@@ -173,11 +175,15 @@ IEGroup _ _ s -> isBlankDocString s IEDoc _ s -> isBlankDocString s _ -> False- dropBlankTypeHaddocks = \case L _ (HsDocTy _ ty s) :: LHsType GhcPs | isBlankDocString s -> ty a -> a+ patchContext :: LHsContext GhcPs -> LHsContext GhcPs+ patchContext = mapLoc $ \case+ [x@(L _ (HsParTy _ _))] -> [x]+ [x@(L lx _)] -> [L lx (HsParTy EpAnnNotUsed x)]+ xs -> xs -- | Enable all language extensions that we think should be enabled by -- default for ease of use.@@ -227,13 +233,13 @@ -- | Module path FilePath -> -- | Module contents- String ->+ Text -> -- | Parse result GHC.ParseResult a runParser parser flags filename input = GHC.unP parser parseState where location = mkRealSrcLoc (GHC.mkFastString filename) 1 1- buffer = GHC.stringToStringBuffer input+ buffer = textToStringBuffer input parseState = GHC.initParserState (initParserOpts flags) buffer location ----------------------------------------------------------------------------@@ -247,14 +253,14 @@ -- | File name (only for source location annotations) FilePath -> -- | Input for parser- String ->+ Text -> IO (Either String ([GHC.Warn], DynFlags)) parsePragmasIntoDynFlags flags extraOpts filepath str = catchErrors $ do let (_warnings, fileOpts) = GHC.getOptions (initParserOpts flags)- (GHC.stringToStringBuffer str)+ (textToStringBuffer str) filepath (flags', leftovers, warnings) <- parseDynamicFilePragma flags (extraOpts <> fileOpts)
src/Ormolu/Parser/CommentStream.hs view
@@ -1,8 +1,10 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ViewPatterns #-} -- | Functions for working with comment stream. module Ormolu.Parser.CommentStream@@ -23,12 +25,13 @@ import Data.Char (isSpace) import Data.Data (Data) import Data.Generics.Schemes-import qualified Data.List as L import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.List.NonEmpty as NE import qualified Data.Map.Lazy as M import Data.Maybe import qualified Data.Set as S+import Data.Text (Text)+import qualified Data.Text as T import qualified GHC.Data.Strict as Strict import GHC.Hs (HsModule) import GHC.Hs.Doc@@ -52,7 +55,7 @@ -- removed from the 'CommentStream'. mkCommentStream :: -- | Original input- String ->+ Text -> -- | Module to use for comment extraction HsModule -> -- | Stack header, pragmas, and comment stream@@ -120,7 +123,7 @@ -- atoms before beginning of the comment in the original input. The -- 'NonEmpty' list inside contains lines of multiline comment @{- … -}@ or -- just single item\/line otherwise.-data Comment = Comment Bool (NonEmpty String)+data Comment = Comment Bool (NonEmpty Text) deriving (Eq, Show, Data) -- | Normalize comment string. Sometimes one multi-line comment is turned@@ -128,37 +131,36 @@ -- each line. mkComment :: -- | Lines of original input with their indices- [(Int, String)] ->+ [(Int, Text)] -> -- | Raw comment string- RealLocated String ->+ RealLocated Text -> -- | Remaining lines of original input and the constructed 'Comment'- ([(Int, String)], RealLocated Comment)+ ([(Int, Text)], RealLocated Comment) mkComment ls (L l s) = (ls', comment) where comment =- L l . Comment atomsBefore . removeConseqBlanks . fmap dropTrailing $- case NE.nonEmpty (lines s) of+ L l . Comment atomsBefore . removeConseqBlanks . fmap T.stripEnd $+ case NE.nonEmpty (T.lines s) of Nothing -> s :| [] Just (x :| xs) -> let getIndent y =- if all isSpace y+ if T.all isSpace y then startIndent- else length (takeWhile isSpace y)+ else T.length (T.takeWhile isSpace y) n = minimum (startIndent : fmap getIndent xs)- commentPrefix = if "{-" `L.isPrefixOf` s then "" else "-- "- in x :| ((commentPrefix <>) . escapeHaddockTriggers . drop n <$> xs)+ commentPrefix = if "{-" `T.isPrefixOf` s then "" else "-- "+ in x :| ((commentPrefix <>) . escapeHaddockTriggers . T.drop n <$> xs) (atomsBefore, ls') = case dropWhile ((< commentLine) . fst) ls of [] -> (False, []) ((_, i) : ls'') ->- case take 2 (dropWhile isSpace i) of+ case T.take 2 (T.stripStart i) of "--" -> (False, ls'') "{-" -> (False, ls'') _ -> (True, ls'')- dropTrailing = L.dropWhileEnd isSpace startIndent -- srcSpanStartCol counts columns starting from 1, so we subtract 1- | "{-" `L.isPrefixOf` s = srcSpanStartCol l - 1+ | "{-" `T.isPrefixOf` s = srcSpanStartCol l - 1 -- For single-line comments, the only case where xs != [] is when an -- invalid haddock comment composed of several single-line comments is -- encountered. In that case, each line of xs is prefixed with an@@ -168,7 +170,7 @@ commentLine = srcSpanStartLine l -- | Get a collection of lines from a 'Comment'.-unComment :: Comment -> NonEmpty String+unComment :: Comment -> NonEmpty Text unComment (Comment _ xs) = xs -- | Check whether the 'Comment' had some non-whitespace atoms in front of@@ -178,7 +180,7 @@ -- | Is this comment multiline-style? isMultilineComment :: Comment -> Bool-isMultilineComment (Comment _ (x :| _)) = "{-" `L.isPrefixOf` x+isMultilineComment (Comment _ (x :| _)) = "{-" `T.isPrefixOf` x ---------------------------------------------------------------------------- -- Helpers@@ -186,8 +188,8 @@ -- | Detect and extract stack header if it is present. extractStackHeader :: -- | Comment stream to analyze- [RealLocated String] ->- ([RealLocated String], Maybe (RealLocated Comment))+ [RealLocated Text] ->+ ([RealLocated Text], Maybe (RealLocated Comment)) extractStackHeader = \case [] -> ([], Nothing) (x : xs) ->@@ -197,18 +199,18 @@ else (x : xs, Nothing) where isStackHeader (Comment _ (x :| _)) =- "stack" `L.isPrefixOf` dropWhile isSpace (drop 2 x)+ "stack" `T.isPrefixOf` T.stripStart (T.drop 2 x) -- | Extract pragmas and their associated comments. extractPragmas :: -- | Input- String ->+ Text -> -- | Comment stream to analyze- [RealLocated String] ->+ [RealLocated Text] -> ([RealLocated Comment], [([RealLocated Comment], Pragma)]) extractPragmas input = go initialLs id id where- initialLs = zip [1 ..] (lines input)+ initialLs = zip [1 ..] (T.lines input) go ls csSoFar pragmasSoFar = \case [] -> (csSoFar [], pragmasSoFar []) (x : xs) ->@@ -229,8 +231,8 @@ then go' ls' [y'] ys else go' ls [] xs --- | Extract @'RealLocated' 'String'@ from 'GHC.LEpaComment'.-unAnnotationComment :: GHC.LEpaComment -> Maybe (RealLocated String)+-- | Extract @'RealLocated' 'Text'@ from 'GHC.LEpaComment'.+unAnnotationComment :: GHC.LEpaComment -> Maybe (RealLocated Text) unAnnotationComment (L (GHC.Anchor anchor _) (GHC.EpaComment eck _)) = case eck of GHC.EpaDocComment s ->@@ -239,48 +241,48 @@ NestedDocString t _ -> Just t -- should not occur GeneratedDocString _ -> Nothing- in haddock trigger (renderHsDocString s)- GHC.EpaDocOptions s -> mkL s- GHC.EpaLineComment s -> mkL $- case take 3 s of+ in haddock trigger (T.pack $ renderHsDocString s)+ GHC.EpaDocOptions s -> mkL (T.pack s)+ GHC.EpaLineComment (T.pack -> s) -> mkL $+ case T.take 3 s of "-- " -> s "---" -> s- _ -> let s' = insertAt " " s 3 in s'- GHC.EpaBlockComment s -> mkL s+ _ -> insertAt " " s 3+ GHC.EpaBlockComment s -> mkL (T.pack s) GHC.EpaEofComment -> Nothing where mkL = Just . L anchor- insertAt x xs n = take (n - 1) xs ++ x ++ drop (n - 1) xs+ insertAt x xs n = T.take (n - 1) xs <> x <> T.drop (n - 1) xs haddock mtrigger = mkL . dashPrefix . escapeHaddockTriggers . (trigger <>) <=< dropBlank where trigger = case mtrigger of Just HsDocStringNext -> "|" Just HsDocStringPrevious -> "^"- Just (HsDocStringNamed n) -> "$" <> n- Just (HsDocStringGroup k) -> replicate k '*'+ Just (HsDocStringNamed n) -> "$" <> T.pack n+ Just (HsDocStringGroup k) -> T.replicate k "*" Nothing -> "" dashPrefix s = "--" <> spaceIfNecessary <> s where- spaceIfNecessary = case s of- c : _ | c /= ' ' -> " "+ spaceIfNecessary = case T.uncons s of+ Just (c, _) | c /= ' ' -> " " _ -> ""- dropBlank :: String -> Maybe String- dropBlank s = if all isSpace s then Nothing else Just s+ dropBlank :: Text -> Maybe Text+ dropBlank s = if T.all isSpace s then Nothing else Just s -- | Remove consecutive blank lines.-removeConseqBlanks :: NonEmpty String -> NonEmpty String-removeConseqBlanks (x :| xs) = x :| go (null x) id xs+removeConseqBlanks :: NonEmpty Text -> NonEmpty Text+removeConseqBlanks (x :| xs) = x :| go (T.null x) id xs where go seenBlank acc = \case [] -> acc [] (y : ys) ->- if seenBlank && null y+ if seenBlank && T.null y then go True acc ys- else go (null y) (acc . (y :)) ys+ else go (T.null y) (acc . (y :)) ys -- | Escape characters that can turn a line into a Haddock.-escapeHaddockTriggers :: String -> String+escapeHaddockTriggers :: Text -> Text escapeHaddockTriggers string- | h : _ <- string, h `elem` "|^*$" = '\\' : string+ | Just (h, _) <- T.uncons string, h `elem` ("|^*$" :: [Char]) = T.cons '\\' string | otherwise = string
src/Ormolu/Parser/Pragma.hs view
@@ -8,65 +8,62 @@ ) where -import Control.Monad-import Data.Char (isSpace, toLower)-import qualified Data.List as L-import GHC.Data.FastString (mkFastString, unpackFS)-import GHC.Data.StringBuffer+import Data.Char (isSpace)+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import GHC.Data.FastString (bytesFS, mkFastString) import GHC.Driver.Config.Parser (initParserOpts) import GHC.DynFlags (baseDynFlags) import qualified GHC.Parser.Lexer as L import GHC.Types.SrcLoc+import Ormolu.Utils (textToStringBuffer) -- | Ormolu's representation of pragmas. data Pragma = -- | Language pragma- PragmaLanguage [String]+ PragmaLanguage [Text] | -- | GHC options pragma- PragmaOptionsGHC String+ PragmaOptionsGHC Text | -- | Haddock options pragma- PragmaOptionsHaddock String+ PragmaOptionsHaddock Text deriving (Show, Eq) -- | Extract a pragma from a comment if possible, or return 'Nothing' -- otherwise. parsePragma :: -- | Comment to try to parse- String ->+ Text -> Maybe Pragma parsePragma input = do- inputNoPrefix <- L.stripPrefix "{-#" input- guard ("#-}" `L.isSuffixOf` input)- let contents = take (length inputNoPrefix - 3) inputNoPrefix- (pragmaName, cs) = (break isSpace . dropWhile isSpace) contents- case toLower <$> pragmaName of+ contents <- T.stripSuffix "#-}" =<< T.stripPrefix "{-#" input+ let (pragmaName, cs) = (T.break isSpace . T.dropWhile isSpace) contents+ case T.toLower pragmaName of "language" -> PragmaLanguage <$> parseExtensions cs- "options_ghc" -> Just $ PragmaOptionsGHC (trimSpaces cs)- "options_haddock" -> Just $ PragmaOptionsHaddock (trimSpaces cs)+ "options_ghc" -> Just $ PragmaOptionsGHC (T.strip cs)+ "options_haddock" -> Just $ PragmaOptionsHaddock (T.strip cs) _ -> Nothing- where- trimSpaces :: String -> String- trimSpaces = L.dropWhileEnd isSpace . dropWhile isSpace -- | Assuming the input consists of a series of tokens from a language -- pragma, return the set of enabled extensions.-parseExtensions :: String -> Maybe [String]+parseExtensions :: Text -> Maybe [Text] parseExtensions str = tokenize str >>= go where go = \case- [L.ITconid ext] -> return [unpackFS ext]- (L.ITconid ext : L.ITcomma : xs) -> (unpackFS ext :) <$> go xs+ [L.ITconid ext] -> return [fsToText ext]+ (L.ITconid ext : L.ITcomma : xs) -> (fsToText ext :) <$> go xs _ -> Nothing+ fsToText = T.decodeUtf8 . bytesFS -- | Tokenize a given input using GHC's lexer.-tokenize :: String -> Maybe [L.Token]+tokenize :: Text -> Maybe [L.Token] tokenize input = case L.unP pLexer parseState of L.PFailed {} -> Nothing L.POk _ x -> Just x where location = mkRealSrcLoc (mkFastString "") 1 1- buffer = stringToStringBuffer input+ buffer = textToStringBuffer input parseState = L.initParserState parserOpts buffer location parserOpts = initParserOpts baseDynFlags
src/Ormolu/Printer/Combinators.hs view
@@ -99,7 +99,7 @@ -- 'Located' wrapper, it should be “discharged” with a corresponding -- 'located' invocation. located ::- HasSrcSpan l =>+ (HasSrcSpan l) => -- | Thing to enter GenLocated l a -> -- | How to render inner value@@ -115,7 +115,7 @@ -- | A version of 'located' with arguments flipped. located' ::- HasSrcSpan l =>+ (HasSrcSpan l) => -- | How to render inner value (a -> R ()) -> -- | Thing to enter
src/Ormolu/Printer/Comments.hs view
@@ -15,7 +15,6 @@ import Control.Monad import qualified Data.List.NonEmpty as NE import Data.Maybe (listToMaybe)-import qualified Data.Text as T import GHC.Types.SrcLoc import Ormolu.Parser.CommentStream import Ormolu.Printer.Internal@@ -264,7 +263,7 @@ sitcc . sequence_ . NE.intersperse newline- . fmap (txt . T.pack)+ . fmap txt . unComment $ comment setSpanMark (CommentSpan spn)@@ -280,7 +279,7 @@ wrapper . sequence_ . NE.toList- . fmap (registerPendingCommentLine position . T.pack)+ . fmap (registerPendingCommentLine position) . unComment $ comment setSpanMark (CommentSpan spn)
src/Ormolu/Printer/Internal.hs view
@@ -56,6 +56,7 @@ ) where +import Control.Monad import Control.Monad.Reader import Control.Monad.State.Strict import Data.Bool (bool)@@ -251,7 +252,7 @@ -- literals and similar. Everything that doesn't have inner structure but -- does have an 'Outputable' instance. atom ::- Outputable a =>+ (Outputable a) => a -> R () atom = spit Atom . T.pack . showOutputable
src/Ormolu/Printer/Meat/Declaration.hs view
@@ -209,10 +209,10 @@ ) -> True _ -> False -intersects :: Ord a => [a] -> [a] -> Bool+intersects :: (Ord a) => [a] -> [a] -> Bool intersects a b = go (sort a) (sort b) where- go :: Ord a => [a] -> [a] -> Bool+ go :: (Ord a) => [a] -> [a] -> Bool go _ [] = False go [] _ = False go (x : xs) (y : ys)
src/Ormolu/Printer/Meat/Declaration/OpTree.hs view
@@ -47,7 +47,7 @@ -- | Decide if the operands of an operator chain should be hanging. opBranchPlacement ::- HasSrcSpan l =>+ (HasSrcSpan l) => -- | Placer function for nodes (ty -> Placement) -> -- | first expression of the chain
src/Ormolu/Printer/Meat/Declaration/Value.hs view
@@ -537,8 +537,11 @@ -- of p_hsLocalBinds). Hence, we introduce a manual Located as we -- depend on the layout being correctly set. pseudoLocated = \case- EpAnn {anns = AnnList {al_anchor = Just Anchor {anchor}}} ->- located (L (RealSrcSpan anchor Strict.Nothing) ()) . const+ EpAnn {anns = AnnList {al_anchor = Just Anchor {anchor}}}+ | let sp = RealSrcSpan anchor Strict.Nothing,+ -- excluding cases where there are no bindings+ not $ isZeroWidthSpan sp ->+ located (L sp ()) . const _ -> id p_ldotFieldOcc :: XRec GhcPs (DotFieldOcc GhcPs) -> R ()@@ -1170,7 +1173,7 @@ -- of an (*|) operator. -- The detection is a bit overcautious, as it adds the spaces as soon as -- HsStarTy is anywhere in the type/declaration.- handleStarIsType :: Data a => a -> R () -> R ()+ handleStarIsType :: (Data a) => a -> R () -> R () handleStarIsType a p | containsHsStarTy a = space *> p <* space | otherwise = p@@ -1236,7 +1239,7 @@ -- | Append each element in both lists with semigroups. If one list is shorter -- than the other, return the rest of the longer list unchanged.-liftAppend :: Semigroup a => [a] -> [a] -> [a]+liftAppend :: (Semigroup a) => [a] -> [a] -> [a] liftAppend [] [] = [] liftAppend [] (y : ys) = y : ys liftAppend (x : xs) [] = x : xs
src/Ormolu/Printer/Meat/Pragma.hs view
@@ -10,9 +10,9 @@ import Control.Monad import Data.Char (isUpper) import qualified Data.List as L-import Data.Maybe (listToMaybe) import Data.Set (Set) import qualified Data.Set as Set+import Data.Text (Text) import qualified Data.Text as T import GHC.Driver.Flags (Language) import GHC.Types.SrcLoc@@ -63,7 +63,7 @@ forM_ (prepare ps) $ \(cs, (pragmaTy, x)) -> p_pragma cs pragmaTy x -p_pragma :: [RealLocated Comment] -> PragmaTy -> String -> R ()+p_pragma :: [RealLocated Comment] -> PragmaTy -> Text -> R () p_pragma comments ty x = do forM_ comments $ \(L l comment) -> do spitCommentNow l comment@@ -74,28 +74,28 @@ OptionsGHC -> "OPTIONS_GHC" OptionsHaddock -> "OPTIONS_HADDOCK" space- txt (T.pack x)+ txt x txt " #-}" newline -- | Classify a 'LanguagePragma'.-classifyLanguagePragma :: String -> LanguagePragmaClass+classifyLanguagePragma :: Text -> LanguagePragmaClass classifyLanguagePragma = \case str | str `Set.member` extensionPacks -> ExtensionPack "ImplicitPrelude" -> Final "CUSKs" -> Final str ->- case splitAt 2 str of+ case T.splitAt 2 str of ("No", rest) ->- case listToMaybe rest of+ case T.uncons rest of Nothing -> Normal- Just x ->+ Just (x, _) -> if isUpper x then Disabling else Normal _ -> Normal -- | Extension packs, like @GHC2021@ and @Haskell2010@.-extensionPacks :: Set String+extensionPacks :: Set Text extensionPacks =- Set.fromList $ show <$> [minBound :: Language .. maxBound]+ Set.fromList $ T.pack . show <$> [minBound :: Language .. maxBound]
src/Ormolu/Printer/Meat/Type.hs view
@@ -227,7 +227,7 @@ InferredSpec -> True SpecifiedSpec -> False -p_hsTyVarBndr :: IsInferredTyVarBndr flag => HsTyVarBndr flag GhcPs -> R ()+p_hsTyVarBndr :: (IsInferredTyVarBndr flag) => HsTyVarBndr flag GhcPs -> R () p_hsTyVarBndr = \case UserTyVar _ flag x -> (if isInferred flag then braces N else id) $ p_rdrName x@@ -242,7 +242,7 @@ -- | Render several @forall@-ed variables. p_forallBndrs ::- HasSrcSpan l =>+ (HasSrcSpan l) => ForAllVisibility -> (a -> R ()) -> [GenLocated l a] ->
src/Ormolu/Printer/Operators.hs view
@@ -16,7 +16,6 @@ import qualified Data.List.NonEmpty as NE import qualified Data.Map.Strict as Map import Data.Maybe (fromMaybe)-import GHC.Types.Name.Occurrence (occNameString) import GHC.Types.Name.Reader import GHC.Types.SrcLoc import Ormolu.Fixity@@ -44,10 +43,10 @@ data OpInfo op = OpInfo { -- | The actual operator opiOp :: op,- -- | Its name, if available. We use 'Maybe String' here instead of- -- 'String' because the name-fetching function received by- -- 'reassociateOpTree' returns a 'Maybe'- opiName :: Maybe String,+ -- | Its name, if available. We use 'Maybe OpName' here instead of 'OpName'+ -- because the name-fetching function received by 'reassociateOpTree'+ -- returns a 'Maybe'+ opiName :: Maybe OpName, -- | Information about the fixity direction and precedence level of the -- operator opiFix :: FixityInfo@@ -80,7 +79,7 @@ _ -> False -- | Return combined 'SrcSpan's of all elements in this 'OpTree'.-opTreeLoc :: HasSrcSpan l => OpTree (GenLocated l a) b -> SrcSpan+opTreeLoc :: (HasSrcSpan l) => OpTree (GenLocated l a) b -> SrcSpan opTreeLoc (OpNode n) = getLoc' n opTreeLoc (OpBranches exprs _) = combineSrcSpans' . NE.fromList . fmap opTreeLoc $ exprs@@ -125,7 +124,7 @@ where toOpInfo o = OpInfo o mName fixityInfo where- mName = occNameString . rdrNameOcc <$> getOpName o+ mName = occOpName . rdrNameOcc <$> getOpName o fixityInfo = fromMaybe defaultFixityInfo
src/Ormolu/Printer/SpanStream.hs view
@@ -27,7 +27,7 @@ -- | Create 'SpanStream' from a data structure containing \"located\" -- elements. mkSpanStream ::- Data a =>+ (Data a) => -- | Data structure to inspect (AST) a -> SpanStream
src/Ormolu/Processing/Common.hs view
@@ -18,24 +18,24 @@ import qualified Data.Text as T import Ormolu.Config --- | Remove indentation from a given 'String'. Return the input with--- indentation removed and the detected indentation level.-removeIndentation :: String -> (String, Int)-removeIndentation (lines -> xs) = (unlines (drop n <$> xs), n)+-- | Remove indentation from a given 'Text'. Return the input with indentation+-- removed and the detected indentation level.+removeIndentation :: Text -> (Text, Int)+removeIndentation (T.lines -> xs) = (T.unlines (T.drop n <$> xs), n) where n = minimum (getIndent <$> xs) getIndent y =- if all isSpace y+ if T.all isSpace y then 0- else length (takeWhile isSpace y)+ else T.length (T.takeWhile isSpace y) -- | Add indentation to a 'Text'. reindent :: Int -> Text -> Text reindent i = T.unlines . fmap (T.replicate i " " <>) . T.lines -- | All lines in the region specified by 'RegionDeltas'.-linesInRegion :: RegionDeltas -> String -> String-linesInRegion RegionDeltas {..} (lines -> ls) = unlines middle+linesInRegion :: RegionDeltas -> Text -> Text+linesInRegion RegionDeltas {..} (T.lines -> ls) = T.unlines middle where (_, nonPrefix) = splitAt regionPrefixLength ls middle = take (length nonPrefix - regionSuffixLength) nonPrefix
src/Ormolu/Processing/Cpp.hs view
@@ -6,11 +6,11 @@ ) where -import Data.Char (isSpace) import Data.IntSet (IntSet) import qualified Data.IntSet as IntSet-import qualified Data.List as L import Data.Maybe (isJust)+import Data.Text (Text)+import qualified Data.Text as T -- | State of the CPP processor. data State@@ -23,8 +23,8 @@ deriving (Eq, Show) -- | Return an 'IntSet' containing all lines which are affected by CPP.-cppLines :: String -> IntSet-cppLines input = IntSet.fromAscList $ go Outside (lines input `zip` [1 ..])+cppLines :: Text -> IntSet+cppLines input = IntSet.fromAscList $ go Outside (T.lines input `zip` [1 ..]) where go _ [] = [] go state ((line, i) : ls)@@ -50,10 +50,10 @@ in is <> go state' ls where for directive = isJust $ do- s <- dropWhile isSpace <$> L.stripPrefix "#" line- L.stripPrefix directive s+ s <- T.stripStart <$> T.stripPrefix "#" line+ T.stripPrefix directive s contState =- if "\\" `L.isSuffixOf` line && not inConditional+ if "\\" `T.isSuffixOf` line && not inConditional then InContinuation else Outside where
src/Ormolu/Processing/Preprocess.hs view
@@ -32,7 +32,7 @@ -- | Whether CPP is enabled Bool -> RegionDeltas ->- String ->+ Text -> [Either Text RegionDeltas] preprocess cppEnabled region rawInput = rawSnippetsAndRegionsToFormat where@@ -48,9 +48,9 @@ interleave' = case regionsNotToFormat of r : _ | regionPrefixLength r == 0 -> interleave _ -> flip interleave- rawSnippets = T.pack . flip linesInRegion updatedInput <$> regionsNotToFormat+ rawSnippets = flip linesInRegion updatedInput <$> regionsNotToFormat where- updatedInput = unlines . fmap updateLine . zip [1 ..] . lines $ rawInput+ updatedInput = T.unlines . fmap updateLine . zip [1 ..] . T.lines $ rawInput updateLine (i, line) = IntMap.findWithDefault line i replacementLines rawSnippetsAndRegionsToFormat = interleave' (Left <$> rawSnippets) (Right <$> regionsToFormat)@@ -64,7 +64,7 @@ -- Extraneous raw snippets at the start/end are dropped afterwards. patchSeparatingBlankLines = \case Right r@RegionDeltas {..} ->- if all isSpace (linesInRegion r rawInput)+ if T.all isSpace (linesInRegion r rawInput) then [blankRawSnippet] else [blankRawSnippet | isBlankLine regionPrefixLength]@@ -73,14 +73,14 @@ Left r -> [Left r] where blankRawSnippet = Left "\n"- isBlankLine i = isJust . mfilter (all isSpace) $ rawLines !!? i+ isBlankLine i = isJust . mfilter (T.all isSpace) $ rawLines !!? i isBlankRawSnippet = \case Left r | T.all isSpace r -> True _ -> False rawLines = A.listArray (0, length rawLines' - 1) rawLines' where- rawLines' = lines rawInput+ rawLines' = T.lines rawInput rawLineLength = length rawLines interleave [] bs = bs@@ -94,15 +94,15 @@ -- | Whether CPP is enabled Bool -> RegionDeltas ->- String ->- (IntSet, IntMap String)+ Text ->+ (IntSet, IntMap Text) linesNotToFormat cppEnabled region@RegionDeltas {..} input = (unconsidered <> magicDisabled <> otherDisabled, lineUpdates) where unconsidered = IntSet.fromAscList $ [1 .. regionPrefixLength] <> [totalLines - regionSuffixLength + 1 .. totalLines]- totalLines = length (lines input)+ totalLines = length (T.lines input) regionLines = linesInRegion region input (magicDisabled, lineUpdates) = magicDisabledLines regionLines otherDisabled = (mconcat allLines) regionLines@@ -119,10 +119,10 @@ -- | All lines which are disabled by Ormolu's magic comments, -- as well as normalizing replacements.-magicDisabledLines :: String -> (IntSet, IntMap String)+magicDisabledLines :: Text -> (IntSet, IntMap Text) magicDisabledLines input = bimap IntSet.fromAscList IntMap.fromAscList . mconcat $- go OrmoluEnabled (lines input `zip` [1 ..])+ go OrmoluEnabled (T.lines input `zip` [1 ..]) where go _ [] = [] go state ((line, i) : ls)@@ -139,40 +139,39 @@ OrmoluEnabled -> ([], []) -- | All lines which satisfy a predicate.-linesFiltered :: (String -> Bool) -> String -> IntSet+linesFiltered :: (Text -> Bool) -> Text -> IntSet linesFiltered p =- IntSet.fromAscList . fmap snd . filter (p . fst) . (`zip` [1 ..]) . lines+ IntSet.fromAscList . fmap snd . filter (p . fst) . (`zip` [1 ..]) . T.lines -- | Lines which contain a shebang.-shebangLines :: String -> IntSet-shebangLines = linesFiltered ("#!" `L.isPrefixOf`)+shebangLines :: Text -> IntSet+shebangLines = linesFiltered ("#!" `T.isPrefixOf`) -- | Lines which contain a LINE pragma.-linePragmaLines :: String -> IntSet-linePragmaLines = linesFiltered ("{-# LINE" `L.isPrefixOf`)+linePragmaLines :: Text -> IntSet+linePragmaLines = linesFiltered ("{-# LINE" `T.isPrefixOf`) -- | Inner text of a magic enabling marker.-ormoluEnable :: String+ormoluEnable :: Text ormoluEnable = "ORMOLU_ENABLE" -- | Inner text of a magic disabling marker.-ormoluDisable :: String+ormoluDisable :: Text ormoluDisable = "ORMOLU_DISABLE" -- | Creates a magic comment with the given inner text.-magicComment :: String -> String+magicComment :: Text -> Text magicComment t = "{- " <> t <> " -}" -- | Construct a function for whitespace-insensitive matching of string. isMagicComment :: -- | What to expect- String ->+ Text -> -- | String to test- String ->+ Text -> -- | If the two strings match, we return the rest of the line.- Maybe String+ Maybe Text isMagicComment expected s0 = do- let trim = dropWhile isSpace- s1 <- trim <$> L.stripPrefix "{-" (trim s0)- s2 <- trim <$> L.stripPrefix expected s1- L.stripPrefix "-}" s2+ s1 <- T.stripStart <$> T.stripPrefix "{-" (T.stripStart s0)+ s2 <- T.stripStart <$> T.stripPrefix expected s1+ T.stripPrefix "-}" s2
src/Ormolu/Utils.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ViewPatterns #-} @@ -17,6 +18,7 @@ HasSrcSpan (..), getLoc', matchAddEpAnn,+ textToStringBuffer, ) where @@ -26,10 +28,15 @@ import Data.Maybe (fromMaybe) import Data.Text (Text) import qualified Data.Text as T+import qualified Data.Text.Foreign as TFFI+import Foreign (pokeElemOff, withForeignPtr) import qualified GHC.Data.Strict as Strict+import GHC.Data.StringBuffer (StringBuffer (..)) import GHC.Driver.Ppr import GHC.DynFlags (baseDynFlags)+import GHC.ForeignPtr (mallocPlainForeignPtrBytes) import GHC.Hs+import GHC.IO.Unsafe (unsafePerformIO) import GHC.Types.SrcLoc import GHC.Utils.Outputable @@ -61,7 +68,7 @@ notImplemented msg = error $ "not implemented yet: " ++ msg -- | Pretty-print an 'GHC.Outputable' thing.-showOutputable :: Outputable o => o -> String+showOutputable :: (Outputable o) => o -> String showOutputable = showSDoc baseDynFlags . ppr -- | Split and normalize a doc string. The result is a list of lines that@@ -141,7 +148,7 @@ instance HasSrcSpan (SrcSpanAnn' ann) where loc' = locA -getLoc' :: HasSrcSpan l => GenLocated l a -> SrcSpan+getLoc' :: (HasSrcSpan l) => GenLocated l a -> SrcSpan getLoc' = loc' . getLoc -- | Check whether the given 'AnnKeywordId' or its Unicode variant is in an@@ -150,3 +157,17 @@ matchAddEpAnn annId (AddEpAnn annId' loc) | annId == annId' || unicodeAnn annId == annId' = Just loc | otherwise = Nothing++-- | Convert 'Text' to a 'StringBuffer' by making a copy.+textToStringBuffer :: Text -> StringBuffer+textToStringBuffer txt = unsafePerformIO $ do+ buf <- mallocPlainForeignPtrBytes (len + 3)+ withForeignPtr buf $ \ptr -> do+ TFFI.unsafeCopyToPtr txt ptr+ -- last three bytes have to be zero for easier decoding+ pokeElemOff ptr len 0+ pokeElemOff ptr (len + 1) 0+ pokeElemOff ptr (len + 2) 0+ pure StringBuffer {buf, len, cur = 0}+ where+ len = TFFI.lengthWord8 txt
src/Ormolu/Utils/Cabal.hs view
@@ -4,10 +4,8 @@ {-# LANGUAGE ViewPatterns #-} module Ormolu.Utils.Cabal- ( CabalInfo (..),- defaultCabalInfo,- PackageName,- unPackageName,+ ( CabalSearchResult (..),+ CabalInfo (..), Extension (..), getCabalInfoForSourceFile, findCabalFile,@@ -34,52 +32,58 @@ import Ormolu.Exception import System.Directory import System.FilePath-import System.IO (hPutStrLn, stderr) import System.IO.Error (isDoesNotExistError) import System.IO.Unsafe (unsafePerformIO) +-- | The result of searching for a @.cabal@ file.+--+-- @since 0.5.3.0+data CabalSearchResult+ = -- | Cabal file could not be found+ CabalNotFound+ | -- | Cabal file was found, but it did not mention the source file in+ -- question+ CabalDidNotMention CabalInfo+ | -- | Cabal file was found and it mentions the source file in question+ CabalFound CabalInfo+ deriving (Eq, Show)+ -- | Cabal information of interest to Ormolu. data CabalInfo = CabalInfo { -- | Package name- ciPackageName :: !(Maybe String),+ ciPackageName :: !PackageName, -- | Extension and language settings in the form of 'DynOption's ciDynOpts :: ![DynOption], -- | Direct dependencies- ciDependencies :: !(Set String),- -- | Absolute path to the cabal file, if it was found- ciCabalFilePath :: !(Maybe FilePath)+ ciDependencies :: !(Set PackageName),+ -- | Absolute path to the cabal file+ ciCabalFilePath :: !FilePath } deriving (Eq, Show) --- | Cabal info that is used by default when no .cabal file can be found.-defaultCabalInfo :: CabalInfo-defaultCabalInfo =- CabalInfo- { ciPackageName = Nothing,- ciDynOpts = [],- ciDependencies = Set.empty,- ciCabalFilePath = Nothing- }---- | Locate .cabal file corresponding to the given Haskell source file and--- obtain 'CabalInfo' from it.+-- | Locate a @.cabal@ file corresponding to the given Haskell source file+-- and obtain 'CabalInfo' from it. getCabalInfoForSourceFile ::- MonadIO m =>+ (MonadIO m) => -- | Haskell source file FilePath ->- -- | Extracted cabal info- m CabalInfo+ -- | Extracted cabal info, if any+ m CabalSearchResult getCabalInfoForSourceFile sourceFile = liftIO $ do findCabalFile sourceFile >>= \case- Just cabalFile -> parseCabalInfo cabalFile sourceFile- Nothing -> do- hPutStrLn stderr $ "Could not find a .cabal file for " <> sourceFile- return defaultCabalInfo+ Just cabalFile -> do+ (mentioned, cabalInfo) <- parseCabalInfo cabalFile sourceFile+ return+ ( if mentioned+ then CabalFound cabalInfo+ else CabalDidNotMention cabalInfo+ )+ Nothing -> return CabalNotFound -- | Find the path to an appropriate .cabal file for a Haskell source file, -- if available. findCabalFile ::- MonadIO m =>+ (MonadIO m) => -- | Path to a Haskell source file in a project with a .cabal file FilePath -> -- | Absolute path to the .cabal file if available@@ -111,7 +115,7 @@ genericPackageDescription :: GenericPackageDescription, -- | Map from Haskell source file paths (without any extensions) to the -- corresponding 'DynOption's and dependencies.- extensionsAndDeps :: Map FilePath ([DynOption], [String])+ extensionsAndDeps :: Map FilePath ([DynOption], [PackageName]) } deriving (Show) @@ -122,13 +126,14 @@ -- | Parse 'CabalInfo' from a .cabal file at the given 'FilePath'. parseCabalInfo ::- MonadIO m =>+ (MonadIO m) => -- | Location of the .cabal file FilePath -> -- | Location of the source file we are formatting FilePath ->- -- | Extracted cabal info- m CabalInfo+ -- | Indication if the source file was mentioned in the Cabal file and the+ -- extracted 'CabalInfo'+ m (Bool, CabalInfo) parseCabalInfo cabalFileAsGiven sourceFileAsGiven = liftIO $ do cabalFile <- makeAbsolute cabalFileAsGiven sourceFileAbs <- makeAbsolute sourceFileAsGiven@@ -143,26 +148,22 @@ cachedCabalFile = CachedCabalFile {..} atomicModifyIORef cabalCacheRef $ (,cachedCabalFile) . M.insert cabalFile cachedCabalFile- (dynOpts, dependencies) <-- whenNothing (M.lookup (dropExtensions sourceFileAbs) extensionsAndDeps) $ do- relativeCabalFile <- makeRelativeToCurrentDirectory cabalFile- hPutStrLn stderr $- "Found .cabal file "- <> relativeCabalFile- <> ", but it did not mention "- <> sourceFileAsGiven- return ([], [])- let pdesc = packageDescription genericPackageDescription- packageName = (unPackageName . pkgName . package) pdesc+ let (dynOpts, dependencies, mentioned) =+ case M.lookup (dropExtensions sourceFileAbs) extensionsAndDeps of+ Nothing -> ([], [], False)+ Just (dynOpts', dependencies') -> (dynOpts', dependencies', True)+ pdesc = packageDescription genericPackageDescription return- CabalInfo- { ciPackageName = Just packageName,- ciDynOpts = dynOpts,- ciDependencies = Set.fromList dependencies,- ciCabalFilePath = Just cabalFile- }+ ( mentioned,+ CabalInfo+ { ciPackageName = pkgName (package pdesc),+ ciDynOpts = dynOpts,+ ciDependencies = Set.fromList dependencies,+ ciCabalFilePath = cabalFile+ }+ ) where- whenNothing :: Monad m => Maybe a -> m a -> m a+ whenNothing :: (Monad m) => Maybe a -> m a -> m a whenNothing maya ma = maybe ma pure maya -- | Get a map from Haskell source file paths (without any extensions) to@@ -172,7 +173,7 @@ FilePath -> -- | Parsed generic package description GenericPackageDescription ->- Map FilePath ([DynOption], [String])+ Map FilePath ([DynOption], [PackageName]) getExtensionAndDepsMap cabalFile GenericPackageDescription {..} = M.unions . concat $ [ buildMap extractFromLibrary <$> lib ++ sublibs,@@ -196,7 +197,7 @@ prependSrcDirs f | null hsSourceDirs = [f] | otherwise = (</> f) . getSymbolicPath <$> hsSourceDirs- deps = unPackageName . depPkgName <$> targetBuildDepends+ deps = depPkgName <$> targetBuildDepends exts = maybe [] langExt defaultLanguage ++ fmap extToDynOption defaultExtensions langExt = pure . DynOption . ("-X" <>) . \case
src/Ormolu/Utils/Fixity.hs view
@@ -28,35 +28,32 @@ cacheRef = unsafePerformIO (newIORef Map.empty) {-# NOINLINE cacheRef #-} --- | Attempt to locate and parse a @.ormolu@ file. If it does not exist,+-- | Attempt to locate and parse an @.ormolu@ file. If it does not exist, -- empty fixity map is returned. This function maintains a cache of fixity -- overrides where cabal file paths act as keys. getFixityOverridesForSourceFile ::- MonadIO m =>+ (MonadIO m) => -- | 'CabalInfo' already obtained for this source file CabalInfo -> m FixityMap getFixityOverridesForSourceFile CabalInfo {..} = liftIO $ do- case ciCabalFilePath of- Nothing -> return Map.empty- Just cabalPath -> do- cache <- readIORef cacheRef- case Map.lookup cabalPath cache of- Nothing -> do- let dotOrmolu = replaceFileName cabalPath ".ormolu"- exists <- doesFileExist dotOrmolu- if exists- then do- dotOrmoluRelative <- makeRelativeToCurrentDirectory dotOrmolu- contents <- readFileUtf8 dotOrmolu- case parseFixityMap dotOrmoluRelative contents of- Left errorBundle ->- throwIO (OrmoluFixityOverridesParseError errorBundle)- Right x -> do- modifyIORef' cacheRef (Map.insert cabalPath x)- return x- else return Map.empty- Just x -> return x+ cache <- readIORef cacheRef+ case Map.lookup ciCabalFilePath cache of+ Nothing -> do+ let dotOrmolu = replaceFileName ciCabalFilePath ".ormolu"+ exists <- doesFileExist dotOrmolu+ if exists+ then do+ dotOrmoluRelative <- makeRelativeToCurrentDirectory dotOrmolu+ contents <- readFileUtf8 dotOrmolu+ case parseFixityMap dotOrmoluRelative contents of+ Left errorBundle ->+ throwIO (OrmoluFixityOverridesParseError errorBundle)+ Right x -> do+ modifyIORef' cacheRef (Map.insert ciCabalFilePath x)+ return x+ else return Map.empty+ Just x -> return x -- | A wrapper around 'parseFixityDeclaration' for parsing individual fixity -- definitions.@@ -64,6 +61,6 @@ -- | Input to parse String -> -- | Parse result- Either String [(String, FixityInfo)]+ Either String [(OpName, FixityInfo)] parseFixityDeclarationStr = first errorBundlePretty . parseFixityDeclaration . T.pack
src/Ormolu/Utils/IO.hs view
@@ -16,19 +16,19 @@ -- | Write a 'Text' to a file using UTF8 and ignoring native -- line ending conventions.-writeFileUtf8 :: MonadIO m => FilePath -> Text -> m ()+writeFileUtf8 :: (MonadIO m) => FilePath -> Text -> m () writeFileUtf8 p = liftIO . B.writeFile p . TE.encodeUtf8 -- | Read an entire file strictly into a 'Text' using UTF8 and -- ignoring native line ending conventions.-readFileUtf8 :: MonadIO m => FilePath -> m Text+readFileUtf8 :: (MonadIO m) => FilePath -> m Text readFileUtf8 p = liftIO (B.readFile p) >>= decodeUtf8 -- | Read stdin as UTF8-encoded 'Text' value.-getContentsUtf8 :: MonadIO m => m Text+getContentsUtf8 :: (MonadIO m) => m Text getContentsUtf8 = liftIO B.getContents >>= decodeUtf8 -- | A helper function for decoding a strict 'ByteString' into 'Text'. It is -- strict and fails immediately if decoding encounters a problem.-decodeUtf8 :: MonadIO m => ByteString -> m Text+decodeUtf8 :: (MonadIO m) => ByteString -> m Text decodeUtf8 = liftIO . either throwIO pure . TE.decodeUtf8'
tests/Ormolu/CabalInfoSpec.hs view
@@ -3,6 +3,7 @@ module Ormolu.CabalInfoSpec (spec) where import qualified Data.Set as Set+import Distribution.Types.PackageName (unPackageName) import Ormolu.Config (DynOption (..)) import Ormolu.Utils.Cabal import System.Directory@@ -30,24 +31,35 @@ cabalFile <- findCabalFile (dir </> "foo/bar.hs") cabalFile `shouldBe` Nothing describe "parseCabalInfo" $ do- it "extracts correct package name from ormolu.cabal" $ do- CabalInfo {..} <- parseCabalInfo "ormolu.cabal" "src/Ormolu/Config.hs"- ciPackageName `shouldBe` Just "ormolu"- it "extracts correct dyn opts from ormolu.cabal" $ do- CabalInfo {..} <- parseCabalInfo "ormolu.cabal" "src/Ormolu/Config.hs"+ it "extracts correct cabal info from ormolu.cabal for src/Ormolu/Config.hs" $ do+ (mentioned, CabalInfo {..}) <- parseCabalInfo "ormolu.cabal" "src/Ormolu/Config.hs"+ mentioned `shouldBe` True+ unPackageName ciPackageName `shouldBe` "ormolu" ciDynOpts `shouldBe` [DynOption "-XHaskell2010"]- it "extracts correct dependencies from ormolu.cabal (src/Ormolu/Config.hs)" $ do- CabalInfo {..} <- parseCabalInfo "ormolu.cabal" "src/Ormolu/Config.hs"- ciDependencies `shouldBe` Set.fromList ["Cabal-syntax", "Diff", "MemoTrie", "ansi-terminal", "array", "base", "binary", "bytestring", "containers", "directory", "dlist", "file-embed", "filepath", "ghc-lib-parser", "megaparsec", "mtl", "syb", "text"]- it "extracts correct dependencies from ormolu.cabal (tests/Ormolu/PrinterSpec.hs)" $ do- CabalInfo {..} <- parseCabalInfo "ormolu.cabal" "tests/Ormolu/PrinterSpec.hs"- ciDependencies `shouldBe` Set.fromList ["QuickCheck", "base", "containers", "directory", "filepath", "ghc-lib-parser", "hspec", "hspec-megaparsec", "ormolu", "path", "path-io", "temporary", "text"]-+ Set.map unPackageName ciDependencies `shouldBe` Set.fromList ["Cabal-syntax", "Diff", "MemoTrie", "ansi-terminal", "array", "base", "binary", "bytestring", "containers", "directory", "dlist", "file-embed", "filepath", "ghc-lib-parser", "megaparsec", "mtl", "syb", "text"]+ ciCabalFilePath `shouldSatisfy` isAbsolute+ makeRelativeToCurrentDirectory ciCabalFilePath `shouldReturn` "ormolu.cabal"+ it "extracts correct cabal info from ormolu.cabal for tests/Ormolu/PrinterSpec.hs" $ do+ (mentioned, CabalInfo {..}) <- parseCabalInfo "ormolu.cabal" "tests/Ormolu/PrinterSpec.hs"+ mentioned `shouldBe` True+ unPackageName ciPackageName `shouldBe` "ormolu"+ ciDynOpts `shouldBe` [DynOption "-XHaskell2010"]+ Set.map unPackageName ciDependencies `shouldBe` Set.fromList ["Cabal-syntax", "QuickCheck", "base", "containers", "directory", "filepath", "ghc-lib-parser", "hspec", "hspec-megaparsec", "ormolu", "path", "path-io", "temporary", "text"]+ ciCabalFilePath `shouldSatisfy` isAbsolute+ makeRelativeToCurrentDirectory ciCabalFilePath `shouldReturn` "ormolu.cabal"+ it "handles correctly files that are not mentioned in ormolu.cabal" $ do+ (mentioned, CabalInfo {..}) <- parseCabalInfo "ormolu.cabal" "src/FooBob.hs"+ mentioned `shouldBe` False+ unPackageName ciPackageName `shouldBe` "ormolu"+ ciDynOpts `shouldBe` []+ Set.map unPackageName ciDependencies `shouldBe` Set.empty+ ciCabalFilePath `shouldSatisfy` isAbsolute+ makeRelativeToCurrentDirectory ciCabalFilePath `shouldReturn` "ormolu.cabal" it "handles `hs-source-dirs: .`" $ do- CabalInfo {..} <- parseTestCabalInfo "Foo.hs"+ (_, CabalInfo {..}) <- parseTestCabalInfo "Foo.hs" ciDynOpts `shouldContain` [DynOption "-XImportQualifiedPost"] it "handles empty hs-source-dirs" $ do- CabalInfo {..} <- parseTestCabalInfo "Bar.hs"+ (_, CabalInfo {..}) <- parseTestCabalInfo "Bar.hs" ciDynOpts `shouldContain` [DynOption "-XImportQualifiedPost"] where parseTestCabalInfo f =
tests/Ormolu/Fixity/ParserSpec.hs view
@@ -3,6 +3,7 @@ module Ormolu.Fixity.ParserSpec (spec) where import qualified Data.Map.Strict as Map+import Data.Text (Text) import qualified Data.Text as T import Ormolu.Fixity import Ormolu.Fixity.Parser@@ -115,6 +116,13 @@ (".", FixityInfo (Just InfixR) 7 9), ("^", FixityInfo (Just InfixR) 9 9) ]+ it "handles CRLF line endings correctly" $+ parseFixityMap ""+ `shouldSucceedOn` ( unlinesCrlf+ [ "infixr 9 .",+ "infixr 5 ++"+ ]+ ) it "fails with correct parse error (keyword wrong second line)" $ parseFixityMap "" "infixr 5 .\nfoobar 5 $" `shouldFailWith` err@@ -127,3 +135,6 @@ eeof ] )++unlinesCrlf :: [Text] -> Text+unlinesCrlf = T.concat . fmap (<> "\r\n")
tests/Ormolu/Fixity/PrinterSpec.hs view
@@ -4,6 +4,7 @@ import qualified Data.Char as Char import qualified Data.Map.Strict as Map+import qualified Data.Text as T import Ormolu.Fixity import Ormolu.Fixity.Parser import Ormolu.Fixity.Printer@@ -20,7 +21,8 @@ <$> listOf ((,) <$> genOperator <*> genFixityInfo) where scaleDown = scale (`div` 4)- genOperator = oneof [genNormalOperator, genIdentifier]+ genOperator =+ OpName . T.pack <$> oneof [genNormalOperator, genIdentifier] genNormalOperator = listOf1 (scaleDown arbitrary `suchThat` isOperatorConstituent) isOperatorConstituent x =
tests/Ormolu/HackageInfoSpec.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TupleSections #-} module Ormolu.HackageInfoSpec (spec) where@@ -5,6 +6,7 @@ import qualified Data.Map.Strict as Map import Data.Maybe (mapMaybe) import qualified Data.Set as Set+import Distribution.Types.PackageName (PackageName) import Ormolu.Fixity import Test.Hspec @@ -13,12 +15,12 @@ -- operators. checkFixityMap :: -- | List of dependencies- [String] ->+ [PackageName] -> -- | Threshold to choose the conflict resolution strategy Float -> -- | Associative list representing a subset of the resulting fixity map -- that should be checked.- [(String, FixityInfo)] ->+ [(OpName, FixityInfo)] -> Expectation checkFixityMap dependencies@@ -43,20 +45,20 @@ checkFixityMap' :: -- | Associative list for packageToOps: -- package name -map-> (operator -map-> fixity)- [(String, [(String, FixityInfo)])] ->+ [(PackageName, [(OpName, FixityInfo)])] -> -- | Associative list for packageToPopularity: -- package name -map-> download count- [(String, Int)] ->+ [(PackageName, Int)] -> -- | List of packages that should have a higher priority than -- unspecified packages (boot packages)- [String] ->+ [PackageName] -> -- | List of dependencies- [String] ->+ [PackageName] -> -- | Threshold to choose the conflict resolution strategy Float -> -- | Associative list representing a subset of the resulting fixity map -- that should be checked.- [(String, FixityInfo)] ->+ [(OpName, FixityInfo)] -> Expectation checkFixityMap' lPackageToOps
tests/Ormolu/OpTreeSpec.hs view
@@ -1,7 +1,11 @@+{-# LANGUAGE OverloadedStrings #-}+ module Ormolu.OpTreeSpec (spec) where import qualified Data.Map.Strict as Map import Data.Maybe (fromJust)+import Data.Text (Text)+import qualified Data.Text as T import GHC.Types.Name (mkOccName, varName) import GHC.Types.Name.Reader (mkRdrUnqual) import Ormolu.Fixity@@ -9,17 +13,17 @@ import Ormolu.Printer.Operators import Test.Hspec -n :: String -> OpTree String String+n :: Text -> OpTree Text OpName n = OpNode -- | Check that the input tree is actually reassociated as expected. checkReassociate :: -- | Fixity map used for the reassociation- [(String, FixityInfo)] ->+ [(OpName, FixityInfo)] -> -- | Input tree- OpTree String String ->+ OpTree Text OpName -> -- | Expected output tree- OpTree String String ->+ OpTree Text OpName -> Expectation checkReassociate lFixities inputTree expectedOutputTree = removeOpInfo actualOutputTree `shouldBe` expectedOutputTree@@ -29,10 +33,10 @@ OpBranches (removeOpInfo <$> exprs) (opiOp <$> ops) actualOutputTree = reassociateOpTree convertName Map.empty fixityMap inputTree fixityMap = LazyFixityMap [Map.fromList lFixities]- convertName = Just . mkRdrUnqual . mkOccName varName+ convertName = Just . mkRdrUnqual . mkOccName varName . T.unpack . unOpName -- | Associative list of fixities for operators from "base"-baseFixities :: [(String, FixityInfo)]+baseFixities :: [(OpName, FixityInfo)] baseFixities = Map.toList . fromJust $ Map.lookup "base" packageToOps spec :: Spec
tests/Ormolu/Parser/OptionsSpec.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-} module Ormolu.Parser.OptionsSpec (spec) where @@ -10,7 +11,7 @@ spec = describe "GHC options in source files take priority" $ do it "default extensions can be disabled locally" $ do let src =- unlines+ T.unlines [ "{-# LANGUAGE NoBlockArguments #-}", "", "test = test do test"@@ -20,7 +21,7 @@ _ -> False it "extensions disabled via CLI can be enabled locally" $ do let src =- unlines+ T.unlines [ "{-# LANGUAGE BlockArguments #-}", "", "test = test do test"@@ -29,4 +30,4 @@ where fixedPoint opts input = do output <- ormolu defaultConfig {cfgDynOptions = DynOption <$> opts} "<input>" input- T.unpack output `shouldBe` input+ output `shouldBe` input
tests/Ormolu/Parser/PragmaSpec.hs view
@@ -1,5 +1,9 @@+{-# LANGUAGE OverloadedStrings #-}+ module Ormolu.Parser.PragmaSpec (spec) where +import Data.Text (Text)+import qualified Data.Text as T import Ormolu.Parser.Pragma import Test.Hspec @@ -20,7 +24,7 @@ stdTest "{-# OPTIONS_GHC foo bar baz #-}" (Just $ PragmaOptionsGHC "foo bar baz") stdTest "{-#OPTIONS_HADDOCK foo, bar, baz #-}" (Just $ PragmaOptionsHaddock "foo, bar, baz") -stdTest :: String -> Maybe Pragma -> Spec+stdTest :: Text -> Maybe Pragma -> Spec stdTest input result =- it input $+ it (T.unpack input) $ parsePragma input `shouldBe` result
tests/Ormolu/PrinterSpec.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} module Ormolu.PrinterSpec (spec) where@@ -56,7 +57,7 @@ shouldMatch False formatted0 expected -- 4. Check that running the formatter on the output produces the same -- output again (the transformation is idempotent).- formatted1 <- ormolu config "<formatted>" (T.unpack formatted0)+ formatted1 <- ormolu config "<formatted>" formatted0 shouldMatch True formatted1 formatted0 -- | Build list of examples for testing.