packages feed

ormolu 0.7.0.0 → 0.7.1.0

raw patch · 25 files changed

+174/−54 lines, 25 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Ormolu.Config: overapproximatedDependencies :: Config region -> Set PackageName
+ Ormolu.Processing.Cpp: eraseCppLines :: Text -> Text
+ Ormolu.Utils.IO: withIORefCache :: Ord k => IORef (Map k v) -> k -> IO v -> IO v
- Ormolu.Fixity: ModuleReexports :: Map ModuleName (NonEmpty ModuleName) -> ModuleReexports
+ Ormolu.Fixity: ModuleReexports :: Map ModuleName (NonEmpty (Maybe PackageName, ModuleName)) -> ModuleReexports
- Ormolu.Fixity: [unModuleReexports] :: ModuleReexports -> Map ModuleName (NonEmpty ModuleName)
+ Ormolu.Fixity: [unModuleReexports] :: ModuleReexports -> Map ModuleName (NonEmpty (Maybe PackageName, ModuleName))
- Ormolu.Fixity.Internal: ModuleReexports :: Map ModuleName (NonEmpty ModuleName) -> ModuleReexports
+ Ormolu.Fixity.Internal: ModuleReexports :: Map ModuleName (NonEmpty (Maybe PackageName, ModuleName)) -> ModuleReexports
- Ormolu.Fixity.Internal: [unModuleReexports] :: ModuleReexports -> Map ModuleName (NonEmpty ModuleName)
+ Ormolu.Fixity.Internal: [unModuleReexports] :: ModuleReexports -> Map ModuleName (NonEmpty (Maybe PackageName, ModuleName))
- Ormolu.Fixity.Parser: parseModuleReexportDeclaration :: Text -> Either (ParseErrorBundle Text Void) (ModuleName, NonEmpty ModuleName)
+ Ormolu.Fixity.Parser: parseModuleReexportDeclaration :: Text -> Either (ParseErrorBundle Text Void) (ModuleName, NonEmpty (Maybe PackageName, ModuleName))
- Ormolu.Utils.Fixity: parseModuleReexportDeclarationStr :: String -> Either String (ModuleName, NonEmpty ModuleName)
+ Ormolu.Utils.Fixity: parseModuleReexportDeclarationStr :: String -> Either String (ModuleName, NonEmpty (Maybe PackageName, ModuleName))

Files

CHANGELOG.md view
@@ -1,3 +1,23 @@+## Ormolu 0.7.1.0++* Include `base` fixity information when formatting a Haskell file that's+  not mentioned in an existing cabal file. [Issue+  1032](https://github.com/tweag/ormolu/issues/1032)++* Update `displayException` for `OrmoluException` to pretty print the+  exception. [PR 1031](https://github.com/tweag/ormolu/pull/1031).++* Ormolu is now aware of more common module re-exports by default.++* Support explicit mention of target package name in module re-exports. Even+  if the exported package is not specified as a direct dependency of the+  component being formatted it will still be taken into account correctly.+  [Issue 1037](https://github.com/tweag/ormolu/issues/1037).++* Ormolu no longer fails when CPP directly follows the import section (a+  regression introduced in 0.7.0.0). [Issue+  1040](https://github.com/tweag/ormolu/issues/1040).+ ## Ormolu 0.7.0.0  * Inference of operator fixity information is now more precise and takes
README.md view
@@ -156,8 +156,8 @@  ### GitHub actions -[`ormolu-action`][ormolu-action] is the recommended way to ensure that a-project is formatted with Ormolu.+[`run-ormolu`][run-ormolu] is the recommended way to ensure that a project+is formatted with Ormolu.  ### Language extensions, dependencies, and fixities @@ -200,11 +200,12 @@  ```haskell module Control.Lens exports Control.Lens.At-module Control.Lens exports Control.Lens.Lens+module Control.Lens exports "lens" Control.Lens.Lens ```  Module re-export declarations can be mixed freely with fixity overrides, as-long as each declaration is on its own line.+long as each declaration is on its own line. As of Ormolu 0.7.1.0 explicit+package names are allowed in re-export declarations (see the example above).  Finally, all of the above-mentioned parameters can be controlled from the command line:@@ -318,7 +319,7 @@ [haskell-src-exts]: https://hackage.haskell.org/package/haskell-src-exts [neoformat]: https://github.com/sbdchd/neoformat [releases]: https://github.com/tweag/ormolu/releases-[ormolu-action]: https://github.com/marketplace/actions/ormolu-action+[run-ormolu]: https://github.com/haskell-actions/run-ormolu [vim-ormolu]: https://github.com/sdiehl/vim-ormolu [vs-code-plugin]: https://marketplace.visualstudio.com/items?itemName=sjurmillidahl.ormolu-vscode [fourmolu]: https://github.com/fourmolu/fourmolu
app/Main.hs view
@@ -18,6 +18,7 @@ import Data.Text.IO qualified as TIO import Data.Version (showVersion) import Distribution.ModuleName (ModuleName)+import Distribution.Types.PackageName (PackageName) import Language.Haskell.TH.Env (envQ) import Options.Applicative import Ormolu@@ -392,7 +393,8 @@ parseFixityDeclaration = eitherReader parseFixityDeclarationStr  -- | Parse a module reexport declaration.-parseModuleReexportDeclaration :: ReadM (ModuleName, NonEmpty ModuleName)+parseModuleReexportDeclaration ::+  ReadM (ModuleName, NonEmpty (Maybe PackageName, ModuleName)) parseModuleReexportDeclaration = eitherReader parseModuleReexportDeclarationStr  -- | Parse 'ColorMode'.
+ data/examples/declaration/value/function/infix/hspec-expectation-out.hs view
@@ -0,0 +1,8 @@+import Test.Hspec++my_tests = do+  context "my context" $+    it "does something" $+      property $ \pos xs0 xs1 ->+        FancyError pos xs0 <> FancyError pos xs1+          `shouldBe` (FancyError pos (E.union xs0 xs1) :: PE)
+ data/examples/declaration/value/function/infix/hspec-expectation.hs view
@@ -0,0 +1,8 @@+import Test.Hspec++my_tests = do+  context "my context" $+    it "does something" $+      property $ \pos xs0 xs1 ->+        FancyError pos xs0 <> FancyError pos xs1+          `shouldBe` (FancyError pos (E.union xs0 xs1) :: PE)
+ data/examples/other/cpp/cpp-and-imports-out.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE CPP #-}++module Bug where++#ifdef flag+constant :: Int+constant = 1312+#endif
+ data/examples/other/cpp/cpp-and-imports.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE CPP #-}++module Bug where++#ifdef flag+constant :: Int+constant = 1312+#endif
ormolu.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.4 name:               ormolu-version:            0.7.0.0+version:            0.7.1.0 license:            BSD-3-Clause license-file:       LICENSE.md maintainer:         Mark Karpov <mark.karpov@tweag.io>@@ -140,7 +140,7 @@         directory ^>=1.3,         filepath >=1.2 && <1.5,         ghc-lib-parser >=9.6 && <9.7,-        optparse-applicative >=0.14 && <0.18,+        optparse-applicative >=0.14 && <0.19,         ormolu,         text >=2.0 && <3.0,         th-env >=0.1.1 && <0.2
src/Ormolu.hs view
@@ -90,7 +90,7 @@       cfg = regionIndicesToDeltas totalLines <$> cfgWithIndices       fixityMap =         packageFixityMap-          (cfgDependencies cfg) -- memoized on the set of dependencies+          (overapproximatedDependencies cfg) -- memoized on the set of dependencies   (warnings, result0) <-     parseModule' cfg fixityMap OrmoluParsingFailed path originalInput   when (cfgDebug cfg) $ do
src/Ormolu/Config.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RecordWildCards #-}  -- | Configuration options used by the tool.@@ -8,12 +9,14 @@     RegionDeltas (..),     SourceType (..),     defaultConfig,+    overapproximatedDependencies,     regionIndicesToDeltas,     DynOption (..),     dynOptionToLocatedStr,   ) where +import Data.Map.Strict qualified as Map import Data.Set (Set) import Data.Set qualified as Set import Distribution.Types.PackageName (PackageName)@@ -93,6 +96,21 @@             regionEndLine = Nothing           }     }++-- | Return all dependencies of the module. This includes both the declared+-- dependencies of the component we are working with and all potential+-- module re-export targets.+overapproximatedDependencies :: Config region -> Set PackageName+overapproximatedDependencies Config {..} =+  Set.union cfgDependencies potentialReexportTargets+  where+    potentialReexportTargets =+      Set.fromList+        . concatMap toTargetPackages+        $ Map.elems (unModuleReexports cfgModuleReexports)+    toTargetPackages = concatMap $ \case+      (Nothing, _) -> []+      (Just x, _) -> [x]  -- | Convert 'RegionIndices' into 'RegionDeltas'. regionIndicesToDeltas ::
src/Ormolu/Exception.hs view
@@ -47,7 +47,8 @@     OrmoluFixityOverridesParseError (ParseErrorBundle Text Void)   deriving (Show) -instance Exception OrmoluException+instance Exception OrmoluException where+  displayException = T.unpack . runTermPure . printOrmoluException  -- | Print an 'OrmoluException'. printOrmoluException ::
src/Ormolu/Fixity/Imports.hs view
@@ -83,9 +83,9 @@       case Map.lookup (fimportModule i) reexports of         Nothing -> pure i         Just exports ->-          let exportToImport mmodule =+          let exportToImport (mpackageName, mmodule) =                 i-                  { fimportPackage = Nothing,+                  { fimportPackage = mpackageName,                     fimportModule = mmodule                   }            in NE.toList exports >>= expand . exportToImport
src/Ormolu/Fixity/Internal.hs view
@@ -166,7 +166,7 @@  -- | Module re-exports newtype ModuleReexports = ModuleReexports-  { unModuleReexports :: Map ModuleName (NonEmpty ModuleName)+  { unModuleReexports :: Map ModuleName (NonEmpty (Maybe PackageName, ModuleName))   }   deriving stock (Eq, Show) @@ -175,7 +175,8 @@ defaultModuleReexports =   ModuleReexports . Map.fromList $     [ ( "Control.Lens",-        NE.fromList+        l+          "lens"           [ "Control.Lens.At",             "Control.Lens.Cons",             "Control.Lens.Each",@@ -201,12 +202,14 @@           ]       ),       ( "Servant",-        NE.fromList+        l+          "servant"           [ "Servant.API"           ]       ),       ( "Optics",-        NE.fromList+        l+          "optics"           [ "Optics.Fold",             "Optics.Operators",             "Optics.IxAffineFold",@@ -214,8 +217,16 @@             "Optics.IxTraversal",             "Optics.Traversal"           ]+      ),+      ( "Test.Hspec",+        l+          "hspec-expectations"+          [ "Test.Hspec.Expectations"+          ]       )     ]+  where+    l packageName xs = (Just packageName,) <$> NE.fromList xs  -- | Fixity information that is specific to a package being formatted. It -- requires module-specific imports in order to be usable.
src/Ormolu/Fixity/Parser.hs view
@@ -70,7 +70,7 @@   -- | Parse result   Either     (ParseErrorBundle Text Void)-    (ModuleName, NonEmpty ModuleName)+    (ModuleName, NonEmpty (Maybe PackageName, ModuleName)) parseModuleReexportDeclaration = runParser (pModuleReexport <* eof) ""  pDotOrmolu :: Parser (FixityOverrides, ModuleReexports)@@ -128,7 +128,7 @@     normalOperator =       takeWhile1P (Just "operator character") isOperatorConstituent -pModuleReexport :: Parser (ModuleName, NonEmpty ModuleName)+pModuleReexport :: Parser (ModuleName, NonEmpty (Maybe PackageName, ModuleName)) pModuleReexport = do   void (string "module")   hidden hspace1@@ -136,9 +136,12 @@   hidden hspace1   void (string "exports")   hidden hspace1+  mexportedPackage <-+    optional $+      between (char '\"') (char '\"') pPackageName <* hidden hspace1   exportedModule <- pModuleName   hidden hspace-  return (exportingModule, NE.singleton exportedModule)+  return (exportingModule, NE.singleton (mexportedPackage, exportedModule))  pModuleName :: Parser ModuleName pModuleName =
src/Ormolu/Fixity/Printer.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} @@ -20,6 +21,7 @@ import Data.Text.Lazy.Builder.Int qualified as B import Distribution.ModuleName (ModuleName) import Distribution.ModuleName qualified as ModuleName+import Distribution.Types.PackageName import Ormolu.Fixity  -- | Print out a textual representation of an @.ormolu@ file.@@ -53,19 +55,23 @@     isTickedOperator = maybe True (Char.isLetter . fst) . T.uncons  renderSingleModuleReexport ::-  (ModuleName, NonEmpty ModuleName) ->+  (ModuleName, NonEmpty (Maybe PackageName, ModuleName)) ->   Builder renderSingleModuleReexport (exportingModule, exports) =   sconcat (renderSingle <$> exports)   where-    renderSingle exportedModule =+    renderSingle (mexportedPackage, exportedModule) =       mconcat         [ "module ",           renderModuleName exportingModule,           " exports ",+          renderOptionalPackageName mexportedPackage,           renderModuleName exportedModule,           "\n"         ]+    renderOptionalPackageName = \case+      Nothing -> mempty+      Just x -> "\"" <> B.fromString (unPackageName x) <> "\" "  renderModuleName :: ModuleName -> Builder renderModuleName = B.fromString . intercalate "." . ModuleName.components
src/Ormolu/Parser.hs view
@@ -54,6 +54,7 @@ import Ormolu.Parser.CommentStream import Ormolu.Parser.Result import Ormolu.Processing.Common+import Ormolu.Processing.Cpp (eraseCppLines) import Ormolu.Processing.Preprocess import Ormolu.Utils (incSpanLine, showOutputable, textToStringBuffer) @@ -81,7 +82,7 @@           GHC.Opt_Haddock           (setDefaultExts baseDynFlags)       extraOpts = dynOptionToLocatedStr <$> cfgDynOptions-      rawInputStringBuffer = textToStringBuffer rawInput+      rawInputStringBuffer = textToStringBuffer (eraseCppLines rawInput)       beginningLoc =         mkSrcSpan           (mkSrcLoc (GHC.mkFastString path) 1 1)
src/Ormolu/Processing/Cpp.hs view
@@ -3,6 +3,7 @@ -- | Support for CPP. module Ormolu.Processing.Cpp   ( cppLines,+    eraseCppLines,   ) where @@ -60,3 +61,14 @@             inConditional = case state of               InConditional {} -> True               _ -> False++-- | Replace all lines affected by CPP with blank lines.+eraseCppLines :: Text -> Text+eraseCppLines input =+  T.unlines . fmap eraseCpp $ T.lines input `zip` [1 ..]+  where+    linesToErase = cppLines input+    eraseCpp (x, i) =+      if i `IntSet.member` linesToErase+        then "\n"+        else x
src/Ormolu/Processing/Preprocess.hs view
@@ -104,7 +104,7 @@     totalLines = length (T.lines input)     regionLines = linesInRegion region input     (magicDisabled, lineUpdates) = magicDisabledLines regionLines-    otherDisabled = (mconcat allLines) regionLines+    otherDisabled = mconcat allLines regionLines       where         allLines = [shebangLines, linePragmaLines] <> [cppLines | cppEnabled] 
src/Ormolu/Utils/Cabal.hs view
@@ -28,7 +28,8 @@ import Language.Haskell.Extension import Ormolu.Config import Ormolu.Exception-import Ormolu.Utils.IO (findClosestFileSatisfying)+import Ormolu.Fixity+import Ormolu.Utils.IO (findClosestFileSatisfying, withIORefCache) import System.Directory import System.FilePath import System.IO.Unsafe (unsafePerformIO)@@ -117,20 +118,17 @@ parseCabalInfo cabalFileAsGiven sourceFileAsGiven = liftIO $ do   cabalFile <- makeAbsolute cabalFileAsGiven   sourceFileAbs <- makeAbsolute sourceFileAsGiven-  cabalCache <- readIORef cacheRef-  CachedCabalFile {..} <- whenNothing (M.lookup cabalFile cabalCache) $ do+  CachedCabalFile {..} <- withIORefCache cacheRef cabalFile $ do     cabalFileBs <- B.readFile cabalFile     genericPackageDescription <-       whenLeft (snd . runParseResult $ parseGenericPackageDescription cabalFileBs) $         throwIO . OrmoluCabalFileParsingFailed cabalFile . snd     let extensionsAndDeps =           getExtensionAndDepsMap cabalFile genericPackageDescription-        cachedCabalFile = CachedCabalFile {..}-    atomicModifyIORef cacheRef $-      (,cachedCabalFile) . M.insert cabalFile cachedCabalFile+    pure CachedCabalFile {..}   let (dynOpts, dependencies, mentioned) =         case M.lookup (dropExtensions sourceFileAbs) extensionsAndDeps of-          Nothing -> ([], [], False)+          Nothing -> ([], Set.toList defaultDependencies, False)           Just (dynOpts', dependencies') -> (dynOpts', dependencies', True)       pdesc = packageDescription genericPackageDescription   return@@ -143,8 +141,6 @@         }     )   where-    whenNothing :: (Applicative f) => Maybe a -> f a -> f a-    whenNothing maya ma = maybe ma pure maya     whenLeft :: (Applicative f) => Either e a -> (e -> f a) -> f a     whenLeft eitha ma = either ma pure eitha 
src/Ormolu/Utils/Fixity.hs view
@@ -16,10 +16,11 @@ import Data.Map.Strict qualified as Map import Data.Text qualified as T import Distribution.ModuleName (ModuleName)+import Distribution.Types.PackageName (PackageName) import Ormolu.Exception import Ormolu.Fixity import Ormolu.Fixity.Parser-import Ormolu.Utils.IO (findClosestFileSatisfying, readFileUtf8)+import Ormolu.Utils.IO (findClosestFileSatisfying, readFileUtf8, withIORefCache) import System.Directory import System.IO.Unsafe (unsafePerformIO) import Text.Megaparsec (errorBundlePretty)@@ -35,19 +36,13 @@   m (FixityOverrides, ModuleReexports) getDotOrmoluForSourceFile sourceFile =   liftIO (findDotOrmoluFile sourceFile) >>= \case-    Just dotOrmoluFile -> liftIO $ do-      cache <- readIORef cacheRef-      case Map.lookup dotOrmoluFile cache of-        Nothing -> do-          dotOrmoluRelative <- makeRelativeToCurrentDirectory dotOrmoluFile-          contents <- readFileUtf8 dotOrmoluFile-          case parseDotOrmolu dotOrmoluRelative contents of-            Left errorBundle ->-              throwIO (OrmoluFixityOverridesParseError errorBundle)-            Right x -> do-              modifyIORef' cacheRef (Map.insert dotOrmoluFile x)-              return x-        Just x -> return x+    Just dotOrmoluFile -> liftIO $ withIORefCache cacheRef dotOrmoluFile $ do+      dotOrmoluRelative <- makeRelativeToCurrentDirectory dotOrmoluFile+      contents <- readFileUtf8 dotOrmoluFile+      case parseDotOrmolu dotOrmoluRelative contents of+        Left errorBundle ->+          throwIO (OrmoluFixityOverridesParseError errorBundle)+        Right x -> return x     Nothing -> return (defaultFixityOverrides, defaultModuleReexports)  -- | Find the path to an appropriate @.ormolu@ file for a Haskell source@@ -82,6 +77,6 @@   -- | Input to parse   String ->   -- | Parse result-  Either String (ModuleName, NonEmpty ModuleName)+  Either String (ModuleName, NonEmpty (Maybe PackageName, ModuleName)) parseModuleReexportDeclarationStr =   first errorBundlePretty . parseModuleReexportDeclaration . T.pack
src/Ormolu/Utils/IO.hs view
@@ -8,6 +8,7 @@     readFileUtf8,     getContentsUtf8,     findClosestFileSatisfying,+    withIORefCache,   ) where @@ -15,6 +16,9 @@ import Control.Monad.IO.Class import Data.ByteString (ByteString) import Data.ByteString qualified as B+import Data.IORef+import Data.Map.Lazy (Map)+import Data.Map.Lazy qualified as M import Data.Text (Text) import Data.Text.Encoding qualified as TE import System.Directory@@ -71,3 +75,15 @@       if isDrive parentDir         then pure Nothing         else findClosestFileSatisfying isRightFile parentDir++-- | Execute an 'IO' action but only if the given key is not found in the+-- 'IORef' cache.+withIORefCache :: (Ord k) => IORef (Map k v) -> k -> IO v -> IO v+withIORefCache cacheRef k action = do+  cache <- readIORef cacheRef+  case M.lookup k cache of+    Just v -> pure v+    Nothing -> do+      v <- action+      modifyIORef' cacheRef (M.insert k v)+      pure v
tests/Ormolu/CabalInfoSpec.hs view
@@ -52,7 +52,7 @@       mentioned `shouldBe` False       unPackageName ciPackageName `shouldBe` "ormolu"       ciDynOpts `shouldBe` []-      Set.map unPackageName ciDependencies `shouldBe` Set.empty+      Set.map unPackageName ciDependencies `shouldBe` Set.fromList ["base"]       ciCabalFilePath `shouldSatisfy` isAbsolute       makeRelativeToCurrentDirectory ciCabalFilePath `shouldReturn` "ormolu.cabal"     it "handles `hs-source-dirs: .`" $ do
tests/Ormolu/Fixity/ParserSpec.hs view
@@ -78,7 +78,7 @@         ""         ( T.unlines             [ "module Control.Lens exports Control.Lens.Lens",-              "module Control.Lens exports Control.Lens.At",+              "module Control.Lens exports \"lens\" Control.Lens.At",               "module Text.Megaparsec exports Control.Monad.Combinators"             ]         )@@ -93,7 +93,7 @@               "infixl 4  <$",               "",               "",-              "module Control.Lens exports Control.Lens.At",+              "module Control.Lens exports \"lens\" Control.Lens.At",               "infixr 9  .",               "module Text.Megaparsec exports Control.Monad.Combinators",               "infixl 1  >>, >>=",@@ -170,8 +170,13 @@     it "parses a re-export declaration" $       parseModuleReexportDeclaration "module Control.Lens exports Control.Lens.Lens"         `shouldParse` ( "Control.Lens",-                        "Control.Lens.Lens" :| []+                        (Nothing, "Control.Lens.Lens") :| []                       )+    it "parses a re-export declaration (explicit package)" $+      parseModuleReexportDeclaration "module Control.Lens exports \"lens\" Control.Lens.Lens"+        `shouldParse` ( "Control.Lens",+                        (Just "lens", "Control.Lens.Lens") :| []+                      )     it "fails with correct parse error (keyword wrong)" $       parseModuleReexportDeclaration "foo Control.Lens exports Control.Lens.Lens"         `shouldFailWith` err@@ -223,10 +228,10 @@ exampleModuleReexports =   ModuleReexports . Map.fromList $     [ ( "Control.Lens",-        "Control.Lens.At" :| ["Control.Lens.Lens"]+        (Nothing, "Control.Lens.Lens") :| [(Just "lens", "Control.Lens.At")]       ),       ( "Text.Megaparsec",-        "Control.Monad.Combinators" :| []+        (Nothing, "Control.Monad.Combinators") :| []       )     ] 
tests/Ormolu/FixitySpec.hs view
@@ -234,7 +234,7 @@           ModuleReexports $             Map.insert               "Foo"-              ("Control.Lens" :| [])+              ((Nothing, "Control.Lens") :| [])               (unModuleReexports defaultModuleReexports)     checkFixities       ["lens"]
tests/Ormolu/PrinterSpec.hs view
@@ -49,6 +49,7 @@               Set.fromList                 [ "base",                   "esqueleto",+                  "hspec",                   "lens",                   "servant"                 ]