packages feed

cabal-gild 1.0.2.4 → 1.1.0.0

raw patch · 14 files changed

+266/−100 lines, 14 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- CabalGild.Class.MonadLog: log :: MonadLog m => String -> m ()
+ CabalGild.Exception.SpecifiedOutputWithCheckMode: SpecifiedOutputWithCheckMode :: SpecifiedOutputWithCheckMode
+ CabalGild.Exception.SpecifiedOutputWithCheckMode: data SpecifiedOutputWithCheckMode
+ CabalGild.Exception.SpecifiedOutputWithCheckMode: instance GHC.Classes.Eq CabalGild.Exception.SpecifiedOutputWithCheckMode.SpecifiedOutputWithCheckMode
+ CabalGild.Exception.SpecifiedOutputWithCheckMode: instance GHC.Exception.Type.Exception CabalGild.Exception.SpecifiedOutputWithCheckMode.SpecifiedOutputWithCheckMode
+ CabalGild.Exception.SpecifiedOutputWithCheckMode: instance GHC.Show.Show CabalGild.Exception.SpecifiedOutputWithCheckMode.SpecifiedOutputWithCheckMode
+ CabalGild.Exception.SpecifiedStdinWithFileInput: SpecifiedStdinWithFileInput :: SpecifiedStdinWithFileInput
+ CabalGild.Exception.SpecifiedStdinWithFileInput: data SpecifiedStdinWithFileInput
+ CabalGild.Exception.SpecifiedStdinWithFileInput: instance GHC.Classes.Eq CabalGild.Exception.SpecifiedStdinWithFileInput.SpecifiedStdinWithFileInput
+ CabalGild.Exception.SpecifiedStdinWithFileInput: instance GHC.Exception.Type.Exception CabalGild.Exception.SpecifiedStdinWithFileInput.SpecifiedStdinWithFileInput
+ CabalGild.Exception.SpecifiedStdinWithFileInput: instance GHC.Show.Show CabalGild.Exception.SpecifiedStdinWithFileInput.SpecifiedStdinWithFileInput
+ CabalGild.Type.Context: Context :: Input -> Mode -> Output -> FilePath -> Context
+ CabalGild.Type.Context: [input] :: Context -> Input
+ CabalGild.Type.Context: [mode] :: Context -> Mode
+ CabalGild.Type.Context: [output] :: Context -> Output
+ CabalGild.Type.Context: [stdin] :: Context -> FilePath
+ CabalGild.Type.Context: data Context
+ CabalGild.Type.Context: fromConfig :: (MonadLog m, MonadThrow m) => Config -> m Context
+ CabalGild.Type.Context: instance GHC.Classes.Eq CabalGild.Type.Context.Context
+ CabalGild.Type.Context: instance GHC.Show.Show CabalGild.Type.Context.Context
+ CabalGild.Type.Input: File :: FilePath -> Input
+ CabalGild.Type.Input: Stdin :: Input
+ CabalGild.Type.Input: data Input
+ CabalGild.Type.Input: fromString :: String -> Input
+ CabalGild.Type.Input: instance GHC.Classes.Eq CabalGild.Type.Input.Input
+ CabalGild.Type.Input: instance GHC.Classes.Ord CabalGild.Type.Input.Input
+ CabalGild.Type.Input: instance GHC.Show.Show CabalGild.Type.Input.Input
+ CabalGild.Type.Optional: Default :: Optional a
+ CabalGild.Type.Optional: Specific :: a -> Optional a
+ CabalGild.Type.Optional: data Optional a
+ CabalGild.Type.Optional: instance GHC.Classes.Eq a => GHC.Classes.Eq (CabalGild.Type.Optional.Optional a)
+ CabalGild.Type.Optional: instance GHC.Show.Show a => GHC.Show.Show (CabalGild.Type.Optional.Optional a)
+ CabalGild.Type.Optional: optional :: b -> (a -> b) -> Optional a -> b
+ CabalGild.Type.Optional: withDefault :: a -> Optional a -> a
+ CabalGild.Type.Output: File :: FilePath -> Output
+ CabalGild.Type.Output: Stdout :: Output
+ CabalGild.Type.Output: data Output
+ CabalGild.Type.Output: fromString :: String -> Output
+ CabalGild.Type.Output: instance GHC.Classes.Eq CabalGild.Type.Output.Output
+ CabalGild.Type.Output: instance GHC.Classes.Ord CabalGild.Type.Output.Output
+ CabalGild.Type.Output: instance GHC.Show.Show CabalGild.Type.Output.Output
- CabalGild.Class.MonadRead: read :: MonadRead m => Maybe FilePath -> m ByteString
+ CabalGild.Class.MonadRead: read :: MonadRead m => Input -> m ByteString
- CabalGild.Class.MonadWrite: write :: MonadWrite m => Maybe FilePath -> ByteString -> m ()
+ CabalGild.Class.MonadWrite: write :: MonadWrite m => Output -> ByteString -> m ()
- CabalGild.Main: mainWith :: (MonadLog m, MonadRead m, MonadThrow m, MonadWalk m, MonadWrite m) => String -> [String] -> m ()
+ CabalGild.Main: mainWith :: (MonadLog m, MonadRead m, MonadThrow m, MonadWalk m, MonadWrite m) => [String] -> m ()
- CabalGild.Type.Config: Config :: Bool -> Maybe FilePath -> Mode -> Maybe FilePath -> FilePath -> Bool -> Config
+ CabalGild.Type.Config: Config :: Optional Bool -> Optional Input -> Optional Mode -> Optional Output -> Optional FilePath -> Optional Bool -> Config
- CabalGild.Type.Config: [help] :: Config -> Bool
+ CabalGild.Type.Config: [help] :: Config -> Optional Bool
- CabalGild.Type.Config: [input] :: Config -> Maybe FilePath
+ CabalGild.Type.Config: [input] :: Config -> Optional Input
- CabalGild.Type.Config: [mode] :: Config -> Mode
+ CabalGild.Type.Config: [mode] :: Config -> Optional Mode
- CabalGild.Type.Config: [output] :: Config -> Maybe FilePath
+ CabalGild.Type.Config: [output] :: Config -> Optional Output
- CabalGild.Type.Config: [stdin] :: Config -> FilePath
+ CabalGild.Type.Config: [stdin] :: Config -> Optional FilePath
- CabalGild.Type.Config: [version] :: Config -> Bool
+ CabalGild.Type.Config: [version] :: Config -> Optional Bool

Files

README.md view
@@ -147,7 +147,7 @@   $ cabal-gild --input p.cabal --output p.cabal   ``` -  This option is ignored when the mode is `check`.+  It is an error to provide a value for this option when the mode is `check`.  - `--stdin=FILE`: When reading input from STDIN, use `FILE` as the effective   input file. This is useful when a file's contents are already available, like@@ -157,7 +157,7 @@   $ cabal-gild --stdin p.cabal < p.cabal   ``` -  This option is ignored when the input is not `-`.+  It is an error to provide a value for this option unless the input is `-`.  ### Pragmas @@ -188,8 +188,8 @@   `signatures` fields. It will be ignored on all other fields.    Any existing modules or signatures in the list will be ignored. The entire-  field (including comments) will be replaced. This means adding, removing, and-  renaming modules or signatures should be handled automatically.+  field will be replaced. This means adding, removing, and renaming modules or+  signatures should be handled automatically.    This pragma searches for files with any of the following extensions: `*.chs`,   `*.cpphs`, `*.gc`, `*.hs`, `*.hsc`, `*.hsig`, `*.lhs`, `*.lhsig`, `*.ly`,
cabal-gild.cabal view
@@ -11,7 +11,7 @@ maintainer: Taylor Fausak name: cabal-gild synopsis: Formats package descriptions.-version: 1.0.2.4+version: 1.1.0.0  source-repository head   type: git@@ -85,6 +85,8 @@     CabalGild.Exception.InvalidMode     CabalGild.Exception.InvalidOption     CabalGild.Exception.ParseError+    CabalGild.Exception.SpecifiedOutputWithCheckMode+    CabalGild.Exception.SpecifiedStdinWithFileInput     CabalGild.Exception.UnexpectedArgument     CabalGild.Exception.UnknownOption     CabalGild.Extra.Either@@ -100,17 +102,21 @@     CabalGild.Type.Chunk     CabalGild.Type.Comment     CabalGild.Type.Config+    CabalGild.Type.Context     CabalGild.Type.Dependency     CabalGild.Type.ExeDependency     CabalGild.Type.Extension     CabalGild.Type.Flag     CabalGild.Type.ForeignLibOption+    CabalGild.Type.Input     CabalGild.Type.Language     CabalGild.Type.LegacyExeDependency     CabalGild.Type.Line     CabalGild.Type.List     CabalGild.Type.Mode     CabalGild.Type.ModuleReexport+    CabalGild.Type.Optional+    CabalGild.Type.Output     CabalGild.Type.PkgconfigDependency     CabalGild.Type.PkgconfigVersionRange     CabalGild.Type.Pragma
source/library/CabalGild/Class/MonadLog.hs view
@@ -2,13 +2,9 @@  -- | A 'Monad' that can also log messages. class (Monad m) => MonadLog m where-  -- | Logs the given message. Typical usage should prefer 'logLn'.-  log :: String -> m ()+  -- | Logs the given message followed by a newline.+  logLn :: String -> m () --- | Uses 'putStr'.+-- | Uses 'putStrLn'. instance MonadLog IO where-  log = putStr---- | Logs the message followed by a newline.-logLn :: (MonadLog m) => String -> m ()-logLn = CabalGild.Class.MonadLog.log . (<> "\n")+  logLn = putStrLn
source/library/CabalGild/Class/MonadRead.hs view
@@ -1,14 +1,16 @@ module CabalGild.Class.MonadRead where +import qualified CabalGild.Type.Input as Input import qualified Data.ByteString as ByteString  -- | A 'Monad' that can also read input, either from standard input (STDIN) or -- from a file. class (Monad m) => MonadRead m where-  -- | Reads input from the given file, or from STDIN if the given file is-  -- 'Nothing'.-  read :: Maybe FilePath -> m ByteString.ByteString+  -- | Reads input from the given 'Input.Input'.+  read :: Input.Input -> m ByteString.ByteString  -- | Uses 'ByteString.getContents' or 'ByteString.readFile'. instance MonadRead IO where-  read = maybe ByteString.getContents ByteString.readFile+  read i = case i of+    Input.Stdin -> ByteString.getContents+    Input.File f -> ByteString.readFile f
source/library/CabalGild/Class/MonadWrite.hs view
@@ -1,14 +1,16 @@ module CabalGild.Class.MonadWrite where +import qualified CabalGild.Type.Output as Output import qualified Data.ByteString as ByteString  -- | A 'Monad' that can also write output, either to standard output (STDOUT) -- or to a file. class (Monad m) => MonadWrite m where-  -- | Writes output to the given file, or to STDOUT if the given file is-  -- 'Nothing'.-  write :: Maybe FilePath -> ByteString.ByteString -> m ()+  -- | Writes output to the given 'Output.Output'.+  write :: Output.Output -> ByteString.ByteString -> m ()  -- | Uses 'ByteString.putStr' or 'ByteString.writeFile'. instance MonadWrite IO where-  write = maybe ByteString.putStr ByteString.writeFile+  write o = case o of+    Output.Stdout -> ByteString.putStr+    Output.File f -> ByteString.writeFile f
+ source/library/CabalGild/Exception/SpecifiedOutputWithCheckMode.hs view
@@ -0,0 +1,12 @@+module CabalGild.Exception.SpecifiedOutputWithCheckMode where++import qualified Control.Monad.Catch as Exception++-- | This exception is thrown when the user specifies the output while using+-- the check mode. In other words, when @--mode=check@ and @--output=anything@.+data SpecifiedOutputWithCheckMode+  = SpecifiedOutputWithCheckMode+  deriving (Eq, Show)++instance Exception.Exception SpecifiedOutputWithCheckMode where+  displayException = const "cannot use --output when --mode is check"
+ source/library/CabalGild/Exception/SpecifiedStdinWithFileInput.hs view
@@ -0,0 +1,13 @@+module CabalGild.Exception.SpecifiedStdinWithFileInput where++import qualified Control.Monad.Catch as Exception++-- | This exception is thrown when the user specifies the STDIN name while+-- using an input file. In other words, when @--input=file@ and+-- @--stdin=anything@.+data SpecifiedStdinWithFileInput+  = SpecifiedStdinWithFileInput+  deriving (Eq, Show)++instance Exception.Exception SpecifiedStdinWithFileInput where+  displayException = const "cannot use --stdin when --input is a file"
source/library/CabalGild/Main.hs view
@@ -17,17 +17,15 @@ import qualified CabalGild.Exception.CheckFailure as CheckFailure import qualified CabalGild.Exception.ParseError as ParseError import qualified CabalGild.Type.Config as Config+import qualified CabalGild.Type.Context as Context import qualified CabalGild.Type.Flag as Flag+import qualified CabalGild.Type.Input as Input import qualified CabalGild.Type.Mode as Mode import qualified Control.Monad as Monad import qualified Control.Monad.Catch as Exception import qualified Data.ByteString as ByteString import qualified Data.ByteString.Char8 as Latin1-import qualified Data.Maybe as Maybe-import qualified Data.Version as Version import qualified Distribution.Fields as Fields-import qualified Paths_cabal_gild as This-import qualified System.Console.GetOpt as GetOpt import qualified System.Environment as Environment import qualified System.Exit as Exit import qualified System.IO as IO@@ -37,9 +35,8 @@ -- thrown, they will be handled by 'onException'. defaultMain :: IO () defaultMain = Exception.handle onException $ do-  name <- Environment.getProgName   arguments <- Environment.getArgs-  mainWith name arguments+  mainWith arguments  -- | If the exception was an 'Exit.ExitCode', simply exit with that code. -- Otherwise handle exceptions by printing them to STDERR using@@ -62,46 +59,35 @@     MonadWalk.MonadWalk m,     MonadWrite.MonadWrite m   ) =>-  String ->   [String] ->   m ()-mainWith name arguments = do+mainWith arguments = do   flags <- Flag.fromArguments arguments   config <- Config.fromFlags flags-  let version = Version.showVersion This.version--  Monad.when (Config.help config) $ do-    let header =-          unlines-            [ name <> " version " <> version,-              "",-              "<https://github.com/tfausak/cabal-gild>"-            ]-    MonadLog.log $ GetOpt.usageInfo header Flag.options-    Exception.throwM Exit.ExitSuccess--  Monad.when (Config.version config) $ do-    MonadLog.logLn version-    Exception.throwM Exit.ExitSuccess+  context <- Context.fromConfig config -  input <- MonadRead.read $ Config.input config+  let source = Context.input context+  input <- MonadRead.read source   fields <-     either (Exception.throwM . ParseError.ParseError) pure $       Fields.readFields input   let csv = GetCabalVersion.fromFields fields       comments = ExtractComments.fromByteString input+      path = case source of+        Input.Stdin -> Context.stdin context+        Input.File f -> f   output <-     ( StripBlanks.run         Monad.>=> AttachComments.run         Monad.>=> ReflowText.run csv         Monad.>=> RemovePositions.run-        Monad.>=> EvaluatePragmas.run (Maybe.fromMaybe (Config.stdin config) $ Config.input config)+        Monad.>=> EvaluatePragmas.run path         Monad.>=> FormatFields.run csv         Monad.>=> Render.run       )       (fields, comments) -  case Config.mode config of+  case Context.mode context of     Mode.Check -> do       -- The input might have CRLF ("\r\n", 0x0d 0x0a) line endings, but the       -- output will always have LF line endings. For the purposes of the check@@ -114,4 +100,6 @@           inputLines = stripCR <$> Latin1.lines input       Monad.when (outputLines /= inputLines) $         Exception.throwM CheckFailure.CheckFailure-    Mode.Format -> MonadWrite.write (Config.output config) output+    Mode.Format -> do+      let target = Context.output context+      MonadWrite.write target output
source/library/CabalGild/Type/Config.hs view
@@ -2,19 +2,22 @@ module CabalGild.Type.Config where  import qualified CabalGild.Type.Flag as Flag+import qualified CabalGild.Type.Input as Input import qualified CabalGild.Type.Mode as Mode+import qualified CabalGild.Type.Optional as Optional+import qualified CabalGild.Type.Output as Output import qualified Control.Monad as Monad import qualified Control.Monad.Catch as Exception  -- | This data type represents the configuration for the command line utility. -- Each field typically corresponds to a flag. data Config = Config-  { help :: Bool,-    input :: Maybe FilePath,-    mode :: Mode.Mode,-    output :: Maybe FilePath,-    stdin :: FilePath,-    version :: Bool+  { help :: Optional.Optional Bool,+    input :: Optional.Optional Input.Input,+    mode :: Optional.Optional Mode.Mode,+    output :: Optional.Optional Output.Output,+    stdin :: Optional.Optional FilePath,+    version :: Optional.Optional Bool   }   deriving (Eq, Show) @@ -22,29 +25,25 @@ initial :: Config initial =   Config-    { help = False,-      input = Nothing,-      mode = Mode.Format,-      output = Nothing,-      stdin = ".",-      version = False+    { help = Optional.Default,+      input = Optional.Default,+      mode = Optional.Default,+      output = Optional.Default,+      stdin = Optional.Default,+      version = Optional.Default     }  -- | Applies a flag to the config, returning the new config. applyFlag :: (Exception.MonadThrow m) => Config -> Flag.Flag -> m Config applyFlag config flag = case flag of-  Flag.Help b -> pure config {help = b}-  Flag.Input s -> case s of-    "-" -> pure config {input = Nothing}-    _ -> pure config {input = Just s}+  Flag.Help b -> pure config {help = Optional.Specific b}+  Flag.Input s -> pure config {input = Optional.Specific $ Input.fromString s}   Flag.Mode s -> do     m <- Mode.fromString s-    pure config {mode = m}-  Flag.Output s -> case s of-    "-" -> pure config {output = Nothing}-    _ -> pure config {output = Just s}-  Flag.Stdin s -> pure config {stdin = s}-  Flag.Version b -> pure config {version = b}+    pure config {mode = Optional.Specific m}+  Flag.Output s -> pure config {output = Optional.Specific $ Output.fromString s}+  Flag.Stdin s -> pure config {stdin = Optional.Specific s}+  Flag.Version b -> pure config {version = Optional.Specific b}  -- | Converts a list of flags into a config by starting with 'initial' and -- repeatedly calling 'applyFlag'.
+ source/library/CabalGild/Type/Context.hs view
@@ -0,0 +1,73 @@+module CabalGild.Type.Context where++import qualified CabalGild.Class.MonadLog as MonadLog+import qualified CabalGild.Exception.SpecifiedOutputWithCheckMode as SpecifiedOutputWithCheckMode+import qualified CabalGild.Exception.SpecifiedStdinWithFileInput as SpecifiedStdinWithFileInput+import qualified CabalGild.Type.Config as Config+import qualified CabalGild.Type.Flag as Flag+import qualified CabalGild.Type.Input as Input+import qualified CabalGild.Type.Mode as Mode+import qualified CabalGild.Type.Optional as Optional+import qualified CabalGild.Type.Output as Output+import qualified Control.Monad as Monad+import qualified Control.Monad.Catch as Exception+import qualified Data.Char as Char+import qualified Data.List as List+import qualified Data.Version as Version+import qualified Paths_cabal_gild as This+import qualified System.Console.GetOpt as GetOpt+import qualified System.Exit as Exit++-- | Represents the context necessary to run the program. This is essentially a+-- simplified 'Config.Config'.+data Context = Context+  { input :: Input.Input,+    mode :: Mode.Mode,+    output :: Output.Output,+    stdin :: FilePath+  }+  deriving (Eq, Show)++-- | Creates a 'Context' from a 'Config.Config'. If the help or version was+-- requested, then this will throw an 'Exit.ExitSuccess'. Otherwise this makes+-- sure the config is valid before returning the context.+fromConfig ::+  (MonadLog.MonadLog m, Exception.MonadThrow m) =>+  Config.Config ->+  m Context+fromConfig config = do+  let version = Version.showVersion This.version++  Monad.when (Optional.withDefault False $ Config.help config) $ do+    let header =+          unlines+            [ "cabal-gild version " <> version,+              "",+              "<https://github.com/tfausak/cabal-gild>"+            ]+    MonadLog.logLn+      . List.dropWhileEnd Char.isSpace+      $ GetOpt.usageInfo header Flag.options+    Exception.throwM Exit.ExitSuccess++  Monad.when (Optional.withDefault False $ Config.version config) $ do+    MonadLog.logLn version+    Exception.throwM Exit.ExitSuccess++  case (Config.input config, Config.stdin config) of+    (Optional.Specific (Input.File _), Optional.Specific _) ->+      Exception.throwM SpecifiedStdinWithFileInput.SpecifiedStdinWithFileInput+    _ -> pure ()++  case (Config.mode config, Config.output config) of+    (Optional.Specific Mode.Check, Optional.Specific _) ->+      Exception.throwM SpecifiedOutputWithCheckMode.SpecifiedOutputWithCheckMode+    _ -> pure ()++  pure+    Context+      { input = Optional.withDefault Input.Stdin $ Config.input config,+        mode = Optional.withDefault Mode.Format $ Config.mode config,+        output = Optional.withDefault Output.Stdout $ Config.output config,+        stdin = Optional.withDefault "." $ Config.stdin config+      }
+ source/library/CabalGild/Type/Input.hs view
@@ -0,0 +1,15 @@+module CabalGild.Type.Input where++-- | Represents an input stream, which can either be standard input (STDIN) or+-- a file.+data Input+  = Stdin+  | File FilePath+  deriving (Eq, Ord, Show)++-- | Converts a string into an input. The string @"-"@ will be converted into+-- 'Stdin', and any other string will be converted into 'File'.+fromString :: String -> Input+fromString s = case s of+  "-" -> Stdin+  _ -> File s
+ source/library/CabalGild/Type/Optional.hs view
@@ -0,0 +1,20 @@+module CabalGild.Type.Optional where++-- | Represents a value that may or may not be present. Isomorphic to 'Maybe'.+-- Useful to distinguish between a value not being given and a value happening+-- to be the same as the default.+data Optional a+  = Default+  | Specific a+  deriving (Eq, Show)++-- | Uses the provided default value if the optional is 'Default', otherwise+-- gets the value out of the 'Specific'. Similar to 'Data.Maybe.fromMaybe'.+withDefault :: a -> Optional a -> a+withDefault = flip optional id++-- | Basic destructor, similar to 'maybe'.+optional :: b -> (a -> b) -> Optional a -> b+optional b f o = case o of+  Default -> b+  Specific s -> f s
+ source/library/CabalGild/Type/Output.hs view
@@ -0,0 +1,15 @@+module CabalGild.Type.Output where++-- | Represents an output stream, which can either be standard output+-- (STDOUT) or a file.+data Output+  = Stdout+  | File FilePath+  deriving (Eq, Ord, Show)++-- | Converts a string into an output. The string @"-"@ will be converted into+-- 'Stdout', and any other string will be converted into 'File'.+fromString :: String -> Output+fromString s = case s of+  "-" -> Stdout+  _ -> File s
source/test-suite/Main.hs view
@@ -4,18 +4,23 @@ import qualified CabalGild.Class.MonadRead as MonadRead import qualified CabalGild.Class.MonadWalk as MonadWalk import qualified CabalGild.Class.MonadWrite as MonadWrite+import qualified CabalGild.Exception.CheckFailure as CheckFailure+import qualified CabalGild.Exception.SpecifiedOutputWithCheckMode as SpecifiedOutputWithCheckMode+import qualified CabalGild.Exception.SpecifiedStdinWithFileInput as SpecifiedStdinWithFileInput import qualified CabalGild.Extra.String as String import qualified CabalGild.Main as Gild+import qualified CabalGild.Type.Input as Input+import qualified CabalGild.Type.Output as Output import qualified Control.Monad.Catch as Exception import qualified Control.Monad.Trans.Class as Trans import qualified Control.Monad.Trans.Except as ExceptT import qualified Control.Monad.Trans.RWS as RWST import qualified Data.ByteString as ByteString-import qualified Data.Either as Either import qualified Data.Function as Function import qualified Data.Functor.Identity as Identity import qualified Data.Map as Map import qualified GHC.Stack as Stack+import qualified System.Exit as Exit import qualified System.FilePath as FilePath import qualified Test.Hspec as Hspec @@ -24,48 +29,48 @@   Hspec.it "shows the help" $ do     let (a, s, w) =           runTest-            (Gild.mainWith "" ["--help"])+            (Gild.mainWith ["--help"])             (Map.empty, Map.empty)             Map.empty-    a `Hspec.shouldSatisfy` Either.isLeft+    a `Hspec.shouldBe` Left (Problem $ Exception.toException Exit.ExitSuccess)     w `Hspec.shouldNotSatisfy` null     s `Hspec.shouldBe` Map.empty    Hspec.it "shows the version" $ do     let (a, s, w) =           runTest-            (Gild.mainWith "" ["--version"])+            (Gild.mainWith ["--version"])             (Map.empty, Map.empty)             Map.empty-    a `Hspec.shouldSatisfy` Either.isLeft+    a `Hspec.shouldBe` Left (Problem $ Exception.toException Exit.ExitSuccess)     w `Hspec.shouldNotSatisfy` null     s `Hspec.shouldBe` Map.empty    Hspec.it "reads from an input file" $ do     let (a, s, w) =           runTest-            (Gild.mainWith "" ["--input", "input.cabal"])-            (Map.singleton (Just "input.cabal") (String.toUtf8 ""), Map.empty)+            (Gild.mainWith ["--input", "input.cabal"])+            (Map.singleton (Input.File "input.cabal") (String.toUtf8 ""), Map.empty)             Map.empty     a `Hspec.shouldBe` Right ()     w `Hspec.shouldBe` []-    s `Hspec.shouldSatisfy` Map.member Nothing+    s `Hspec.shouldSatisfy` Map.member Output.Stdout    Hspec.it "writes to an output file" $ do     let (a, s, w) =           runTest-            (Gild.mainWith "" ["--output", "output.cabal"])-            (Map.singleton Nothing (String.toUtf8 ""), Map.empty)+            (Gild.mainWith ["--output", "output.cabal"])+            (Map.singleton Input.Stdin (String.toUtf8 ""), Map.empty)             Map.empty     a `Hspec.shouldBe` Right ()     w `Hspec.shouldBe` []-    s `Hspec.shouldSatisfy` Map.member (Just "output.cabal")+    s `Hspec.shouldSatisfy` Map.member (Output.File "output.cabal")    Hspec.it "succeeds when checking formatted input" $ do     let (a, s, w) =           runTest-            (Gild.mainWith "" ["--mode", "check"])-            (Map.singleton Nothing (String.toUtf8 ""), Map.empty)+            (Gild.mainWith ["--mode", "check"])+            (Map.singleton Input.Stdin (String.toUtf8 ""), Map.empty)             Map.empty     a `Hspec.shouldBe` Right ()     w `Hspec.shouldBe` []@@ -74,23 +79,43 @@   Hspec.it "fails when checking unformatted input" $ do     let (a, s, w) =           runTest-            (Gild.mainWith "" ["--mode", "check"])-            (Map.singleton Nothing (String.toUtf8 "fail:yes"), Map.empty)+            (Gild.mainWith ["--mode", "check"])+            (Map.singleton Input.Stdin (String.toUtf8 "fail:yes"), Map.empty)             Map.empty-    a `Hspec.shouldSatisfy` Either.isLeft+    a `Hspec.shouldBe` Left (Problem $ Exception.toException CheckFailure.CheckFailure)     w `Hspec.shouldBe` []     s `Hspec.shouldBe` Map.empty    Hspec.it "succeeds when checking CRLF input" $ do     let (a, s, w) =           runTest-            (Gild.mainWith "" ["--mode", "check"])-            (Map.singleton Nothing (String.toUtf8 "pass: yes\r\n"), Map.empty)+            (Gild.mainWith ["--mode", "check"])+            (Map.singleton Input.Stdin (String.toUtf8 "pass: yes\r\n"), Map.empty)             Map.empty     a `Hspec.shouldBe` Right ()     w `Hspec.shouldBe` []     s `Hspec.shouldBe` Map.empty +  Hspec.it "fails when --stdin is given with an input file" $ do+    let (a, s, w) =+          runTest+            (Gild.mainWith ["--input", "f", "--stdin", "g"])+            (Map.empty, Map.empty)+            Map.empty+    a `Hspec.shouldBe` Left (Problem $ Exception.toException SpecifiedStdinWithFileInput.SpecifiedStdinWithFileInput)+    w `Hspec.shouldBe` []+    s `Hspec.shouldBe` Map.empty++  Hspec.it "fails when --output is given with check mode" $ do+    let (a, s, w) =+          runTest+            (Gild.mainWith ["--mode", "check", "--output", "-"])+            (Map.empty, Map.empty)+            Map.empty+    a `Hspec.shouldBe` Left (Problem $ Exception.toException SpecifiedOutputWithCheckMode.SpecifiedOutputWithCheckMode)+    w `Hspec.shouldBe` []+    s `Hspec.shouldBe` Map.empty+   Hspec.it "succeeds with empty input" $ do     expectGilded       ""@@ -949,13 +974,13 @@ expectGilded input expected = do   let (a, s, w) =         runTest-          (Gild.mainWith "" [])-          (Map.singleton Nothing $ String.toUtf8 input, Map.empty)+          (Gild.mainWith [])+          (Map.singleton Input.Stdin $ String.toUtf8 input, Map.empty)           Map.empty   a `Hspec.shouldBe` Right ()   w `Hspec.shouldBe` []   actual <- case Map.toList s of-    [(Nothing, x)] -> pure x+    [(Output.Stdout, x)] -> pure x     _ -> fail $ "impossible: " <> show s   actual `Hspec.shouldBe` String.toUtf8 expected   -- After formatting, the output should not change if we format it again.@@ -965,13 +990,13 @@ expectStable input = do   let (a, s, w) =         runTest-          (Gild.mainWith "" [])-          (Map.singleton Nothing input, Map.empty)+          (Gild.mainWith [])+          (Map.singleton Input.Stdin input, Map.empty)           Map.empty   a `Hspec.shouldBe` Right ()   w `Hspec.shouldBe` []   output <- case Map.toList s of-    [(Nothing, x)] -> pure x+    [(Output.Stdout, x)] -> pure x     _ -> fail $ "impossible: " <> show s   output `Hspec.shouldBe` input @@ -979,15 +1004,15 @@ expectDiscover files input expected = do   let (a, s, w) =         runTest-          (Gild.mainWith "" [])-          ( Map.singleton Nothing $ String.toUtf8 input,+          (Gild.mainWith [])+          ( Map.singleton Input.Stdin $ String.toUtf8 input,             Map.fromList $ fmap (\(d, fs) -> (d, FilePath.combine d <$> fs)) files           )           Map.empty   a `Hspec.shouldBe` Right ()   w `Hspec.shouldBe` []   actual <- case Map.toList s of-    [(Nothing, x)] -> pure x+    [(Output.Stdout, x)] -> pure x     _ -> fail $ "impossible: " <> show s   actual `Hspec.shouldBe` String.toUtf8 expected @@ -1006,9 +1031,9 @@  type E = Problem -type R = (S, Map.Map FilePath [FilePath])+type R = (Map.Map Input.Input ByteString.ByteString, Map.Map FilePath [FilePath]) -type S = Map.Map (Maybe FilePath) ByteString.ByteString+type S = Map.Map Output.Output ByteString.ByteString  type W = [String] @@ -1018,7 +1043,7 @@   deriving (Applicative, Functor, Monad)  instance (Monad m) => MonadLog.MonadLog (TestT m) where-  log = TestT . Trans.lift . RWST.tell . pure+  logLn = TestT . Trans.lift . RWST.tell . pure  instance (Monad m) => MonadRead.MonadRead (TestT m) where   read k = do