packages feed

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 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 @@ [![Hackage](https://img.shields.io/hackage/v/ormolu.svg?style=flat)](https://hackage.haskell.org/package/ormolu) [![Stackage Nightly](http://stackage.org/package/ormolu/badge/nightly)](http://stackage.org/nightly/package/ormolu) [![Stackage LTS](http://stackage.org/package/ormolu/badge/lts)](http://stackage.org/lts/package/ormolu)-[![Build status](https://badge.buildkite.com/8e3b0951f3652b77e1c422b361904136a539b0522029156354.svg?branch=master)](https://buildkite.com/tweag-1/ormolu)+[![CI](https://github.com/tweag/ormolu/actions/workflows/ci.yml/badge.svg)](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.