2020-01-24 18:06:51 +03:00
|
|
|
{-# LANGUAGE CPP #-}
|
2021-11-10 19:00:04 +03:00
|
|
|
{-# LANGUAGE DataKinds #-}
|
2020-01-24 18:06:51 +03:00
|
|
|
{-# LANGUAGE LambdaCase #-}
|
2021-11-10 19:00:04 +03:00
|
|
|
{-# LANGUAGE QuasiQuotes #-}
|
2019-02-24 23:38:10 +03:00
|
|
|
{-# LANGUAGE RecordWildCards #-}
|
|
|
|
{-# LANGUAGE TemplateHaskell #-}
|
|
|
|
|
2020-04-24 20:43:45 +03:00
|
|
|
module Main (main) where
|
2018-11-25 16:34:28 +03:00
|
|
|
|
2021-08-11 12:57:27 +03:00
|
|
|
import Control.Exception (throwIO)
|
2019-02-24 23:38:10 +03:00
|
|
|
import Control.Monad
|
2020-06-26 11:51:39 +03:00
|
|
|
import Data.Bool (bool)
|
2019-09-02 18:10:08 +03:00
|
|
|
import Data.List (intercalate, sort)
|
2023-05-03 21:23:07 +03:00
|
|
|
import Data.List.NonEmpty (NonEmpty)
|
2023-03-31 21:32:44 +03:00
|
|
|
import Data.Map.Strict qualified as Map
|
2023-01-02 20:47:20 +03:00
|
|
|
import Data.Maybe (fromMaybe, mapMaybe, maybeToList)
|
2023-03-31 21:32:44 +03:00
|
|
|
import Data.Set qualified as Set
|
|
|
|
import Data.Text.IO qualified as TIO
|
2019-02-24 23:38:10 +03:00
|
|
|
import Data.Version (showVersion)
|
2023-05-03 21:23:07 +03:00
|
|
|
import Distribution.ModuleName (ModuleName)
|
2023-06-02 12:27:07 +03:00
|
|
|
import Distribution.Types.PackageName (PackageName)
|
2023-01-02 20:47:20 +03:00
|
|
|
import Language.Haskell.TH.Env (envQ)
|
2019-02-24 23:38:10 +03:00
|
|
|
import Options.Applicative
|
2019-02-24 22:50:42 +03:00
|
|
|
import Ormolu
|
2020-11-11 02:37:33 +03:00
|
|
|
import Ormolu.Diff.Text (diffText, printTextDiff)
|
2023-05-03 21:23:07 +03:00
|
|
|
import Ormolu.Fixity
|
2019-07-10 05:56:15 +03:00
|
|
|
import Ormolu.Parser (manualExts)
|
2020-11-14 21:51:07 +03:00
|
|
|
import Ormolu.Terminal
|
2019-07-10 05:56:15 +03:00
|
|
|
import Ormolu.Utils (showOutputable)
|
2023-05-03 21:23:07 +03:00
|
|
|
import Ormolu.Utils.Fixity
|
2021-08-11 13:41:22 +03:00
|
|
|
import Ormolu.Utils.IO
|
2019-02-24 23:38:10 +03:00
|
|
|
import Paths_ormolu (version)
|
2023-01-24 21:20:49 +03:00
|
|
|
import System.Directory
|
2019-06-17 01:21:43 +03:00
|
|
|
import System.Exit (ExitCode (..), exitWith)
|
2023-03-31 21:32:44 +03:00
|
|
|
import System.FilePath qualified as FP
|
2019-07-04 03:52:35 +03:00
|
|
|
import System.IO (hPutStrLn, stderr)
|
2019-02-24 23:38:10 +03:00
|
|
|
|
|
|
|
-- | Entry point of the program.
|
2018-11-25 16:34:28 +03:00
|
|
|
main :: IO ()
|
2020-11-11 02:37:33 +03:00
|
|
|
main = do
|
2019-02-24 23:38:10 +03:00
|
|
|
Opts {..} <- execParser optsParserInfo
|
2021-10-18 17:00:46 +03:00
|
|
|
let formatOne' =
|
|
|
|
formatOne
|
2023-05-15 22:35:35 +03:00
|
|
|
optConfigFileOpts
|
2021-10-18 17:00:46 +03:00
|
|
|
optMode
|
|
|
|
optSourceType
|
|
|
|
optConfig
|
2020-11-11 02:37:33 +03:00
|
|
|
exitCode <- case optInputFiles of
|
2019-08-16 23:36:34 +03:00
|
|
|
[] -> formatOne' Nothing
|
|
|
|
["-"] -> formatOne' Nothing
|
2020-01-27 23:47:14 +03:00
|
|
|
[x] -> formatOne' (Just x)
|
|
|
|
xs -> do
|
2020-11-11 02:37:33 +03:00
|
|
|
let selectFailure = \case
|
|
|
|
ExitSuccess -> Nothing
|
|
|
|
ExitFailure n -> Just n
|
|
|
|
errorCodes <-
|
|
|
|
mapMaybe selectFailure <$> mapM (formatOne' . Just) (sort xs)
|
|
|
|
return $
|
|
|
|
if null errorCodes
|
|
|
|
then ExitSuccess
|
|
|
|
else
|
|
|
|
ExitFailure $
|
|
|
|
if all (== 100) errorCodes
|
|
|
|
then 100
|
|
|
|
else 102
|
|
|
|
exitWith exitCode
|
2019-08-16 23:36:34 +03:00
|
|
|
|
|
|
|
-- | Format a single input.
|
2020-01-24 18:06:51 +03:00
|
|
|
formatOne ::
|
2021-11-10 19:00:04 +03:00
|
|
|
-- | How to use .cabal files
|
2023-05-15 22:35:35 +03:00
|
|
|
ConfigFileOpts ->
|
2020-01-24 18:06:51 +03:00
|
|
|
-- | Mode of operation
|
|
|
|
Mode ->
|
2021-10-18 17:00:46 +03:00
|
|
|
-- | The 'SourceType' requested by the user
|
|
|
|
Maybe SourceType ->
|
2020-01-24 18:06:51 +03:00
|
|
|
-- | Configuration
|
2020-04-23 19:41:32 +03:00
|
|
|
Config RegionIndices ->
|
2020-01-24 18:06:51 +03:00
|
|
|
-- | File to format or stdin as 'Nothing'
|
|
|
|
Maybe FilePath ->
|
2020-11-11 02:37:33 +03:00
|
|
|
IO ExitCode
|
2023-05-15 22:35:35 +03:00
|
|
|
formatOne ConfigFileOpts {..} mode reqSourceType rawConfig mpath =
|
2021-10-18 17:00:46 +03:00
|
|
|
withPrettyOrmoluExceptions (cfgColorMode rawConfig) $ do
|
2023-01-24 21:20:49 +03:00
|
|
|
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)
|
2023-05-15 22:35:35 +03:00
|
|
|
getDotOrmoluForSourceFile' sourceFile = do
|
|
|
|
if optDoNotUseDotOrmolu
|
|
|
|
then return Nothing
|
|
|
|
else Just <$> getDotOrmoluForSourceFile sourceFile
|
2021-08-11 12:57:27 +03:00
|
|
|
case FP.normalise <$> mpath of
|
2021-09-30 11:26:49 +03:00
|
|
|
-- input source = STDIN
|
2021-08-11 12:57:27 +03:00
|
|
|
Nothing -> do
|
2023-05-15 22:35:35 +03:00
|
|
|
mcabalInfo <- case (optStdinInputFile, optDoNotUseCabal) of
|
|
|
|
(_, True) -> return Nothing
|
|
|
|
(Nothing, False) -> throwIO OrmoluMissingStdinInputFile
|
|
|
|
(Just inputFile, False) -> getCabalInfoForSourceFile' inputFile
|
|
|
|
mdotOrmolu <- case optStdinInputFile of
|
|
|
|
Nothing -> return Nothing
|
|
|
|
Just inputFile -> getDotOrmoluForSourceFile' inputFile
|
|
|
|
config <- patchConfig Nothing mcabalInfo mdotOrmolu
|
2021-08-11 12:57:27 +03:00
|
|
|
case mode of
|
|
|
|
Stdout -> do
|
2023-05-15 22:35:35 +03:00
|
|
|
ormoluStdin config >>= TIO.putStr
|
2021-08-11 12:57:27 +03:00
|
|
|
return ExitSuccess
|
2021-09-30 11:26:49 +03:00
|
|
|
InPlace -> do
|
2021-08-11 12:57:27 +03:00
|
|
|
hPutStrLn
|
|
|
|
stderr
|
2021-09-30 11:26:49 +03:00
|
|
|
"In place editing is not supported when input comes from stdin."
|
2021-08-11 12:57:27 +03:00
|
|
|
-- 101 is different from all the other exit codes we already use.
|
|
|
|
return (ExitFailure 101)
|
2021-09-30 11:26:49 +03:00
|
|
|
Check -> do
|
|
|
|
-- ormoluStdin is not used because we need the originalInput
|
|
|
|
originalInput <- getContentsUtf8
|
|
|
|
let stdinRepr = "<stdin>"
|
|
|
|
formattedInput <-
|
2023-05-15 22:35:35 +03:00
|
|
|
ormolu config stdinRepr originalInput
|
2021-09-30 11:26:49 +03:00
|
|
|
handleDiff originalInput formattedInput stdinRepr
|
|
|
|
-- input source = a file
|
2021-08-11 12:57:27 +03:00
|
|
|
Just inputFile -> do
|
2023-05-15 22:35:35 +03:00
|
|
|
mcabalInfo <-
|
|
|
|
if optDoNotUseCabal
|
|
|
|
then return Nothing
|
|
|
|
else getCabalInfoForSourceFile' inputFile
|
|
|
|
mdotOrmolu <- getDotOrmoluForSourceFile' inputFile
|
|
|
|
config <-
|
|
|
|
patchConfig
|
|
|
|
(Just (detectSourceType inputFile))
|
|
|
|
mcabalInfo
|
|
|
|
mdotOrmolu
|
2021-08-11 12:57:27 +03:00
|
|
|
case mode of
|
|
|
|
Stdout -> do
|
2023-05-15 22:35:35 +03:00
|
|
|
ormoluFile config inputFile >>= TIO.putStr
|
2021-08-11 12:57:27 +03:00
|
|
|
return ExitSuccess
|
|
|
|
InPlace -> do
|
2021-09-30 11:26:49 +03:00
|
|
|
-- ormoluFile is not used because we need originalInput
|
|
|
|
originalInput <- readFileUtf8 inputFile
|
2021-10-18 17:00:46 +03:00
|
|
|
formattedInput <-
|
2023-05-15 22:35:35 +03:00
|
|
|
ormolu config inputFile originalInput
|
2021-08-11 12:57:27 +03:00
|
|
|
when (formattedInput /= originalInput) $
|
|
|
|
writeFileUtf8 inputFile formattedInput
|
|
|
|
return ExitSuccess
|
2021-09-30 11:26:49 +03:00
|
|
|
Check -> do
|
|
|
|
-- ormoluFile is not used because we need originalInput
|
|
|
|
originalInput <- readFileUtf8 inputFile
|
2021-10-18 17:00:46 +03:00
|
|
|
formattedInput <-
|
2023-05-15 22:35:35 +03:00
|
|
|
ormolu config inputFile originalInput
|
2021-09-30 11:26:49 +03:00
|
|
|
handleDiff originalInput formattedInput inputFile
|
2021-08-11 12:57:27 +03:00
|
|
|
where
|
2023-05-15 22:35:35 +03:00
|
|
|
patchConfig mdetectedSourceType mcabalInfo mdotOrmolu = do
|
2023-01-24 21:20:49 +03:00
|
|
|
let sourceType =
|
|
|
|
fromMaybe
|
|
|
|
ModuleSource
|
|
|
|
(reqSourceType <|> mdetectedSourceType)
|
2023-05-03 21:23:07 +03:00
|
|
|
return $
|
|
|
|
refineConfig
|
|
|
|
sourceType
|
|
|
|
mcabalInfo
|
2024-02-01 19:21:56 +03:00
|
|
|
(Just (cfgFixityOverrides rawConfig))
|
|
|
|
(Just (cfgModuleReexports rawConfig))
|
|
|
|
( rawConfig
|
|
|
|
{ cfgFixityOverrides = maybe defaultFixityOverrides fst mdotOrmolu,
|
|
|
|
cfgModuleReexports = maybe defaultModuleReexports snd mdotOrmolu
|
|
|
|
}
|
|
|
|
)
|
2021-09-30 11:26:49 +03:00
|
|
|
handleDiff originalInput formattedInput fileRepr =
|
|
|
|
case diffText originalInput formattedInput fileRepr of
|
|
|
|
Nothing -> return ExitSuccess
|
|
|
|
Just diff -> do
|
2021-10-18 17:00:46 +03:00
|
|
|
runTerm (printTextDiff diff) (cfgColorMode rawConfig) stderr
|
2021-09-30 11:26:49 +03:00
|
|
|
-- 100 is different to all the other exit code that are emitted
|
|
|
|
-- either from an 'OrmoluException' or from 'error' and
|
|
|
|
-- 'notImplemented'.
|
|
|
|
return (ExitFailure 100)
|
2019-02-24 23:38:10 +03:00
|
|
|
|
|
|
|
----------------------------------------------------------------------------
|
2020-12-12 00:06:38 +03:00
|
|
|
-- Command line options parsing
|
2019-02-24 23:38:10 +03:00
|
|
|
|
2021-11-10 19:00:04 +03:00
|
|
|
-- | All command line options.
|
2020-04-10 18:52:25 +03:00
|
|
|
data Opts = Opts
|
|
|
|
{ -- | Mode of operation
|
|
|
|
optMode :: !Mode,
|
|
|
|
-- | Ormolu 'Config'
|
2020-04-23 19:41:32 +03:00
|
|
|
optConfig :: !(Config RegionIndices),
|
2023-05-15 22:35:35 +03:00
|
|
|
-- | Options related to info extracted from files
|
|
|
|
optConfigFileOpts :: ConfigFileOpts,
|
2021-10-18 17:00:46 +03:00
|
|
|
-- | Source type option, where 'Nothing' means autodetection
|
|
|
|
optSourceType :: !(Maybe SourceType),
|
2021-08-14 17:27:44 +03:00
|
|
|
-- | Haskell source files to format or stdin (when the list is empty)
|
|
|
|
optInputFiles :: ![FilePath]
|
2020-04-10 18:52:25 +03:00
|
|
|
}
|
2019-02-24 23:38:10 +03:00
|
|
|
|
|
|
|
-- | Mode of operation.
|
|
|
|
data Mode
|
2020-01-24 18:06:51 +03:00
|
|
|
= -- | Output formatted source code to stdout
|
|
|
|
Stdout
|
|
|
|
| -- | Overwrite original file
|
|
|
|
InPlace
|
|
|
|
| -- | Exit with non-zero status code if
|
|
|
|
-- source is not already formatted
|
|
|
|
Check
|
2019-02-24 23:38:10 +03:00
|
|
|
deriving (Eq, Show)
|
|
|
|
|
2023-05-15 22:35:35 +03:00
|
|
|
-- | Options related to configuration stored in the file system.
|
|
|
|
data ConfigFileOpts = ConfigFileOpts
|
2021-11-10 19:00:04 +03:00
|
|
|
{ -- | DO NOT extract default-extensions and dependencies from .cabal files
|
|
|
|
optDoNotUseCabal :: Bool,
|
2023-05-15 22:35:35 +03:00
|
|
|
-- | DO NOT look for @.ormolu@ files
|
|
|
|
optDoNotUseDotOrmolu :: Bool,
|
2021-11-10 19:00:04 +03:00
|
|
|
-- | Optional path to a file which will be used to find a .cabal file
|
|
|
|
-- when using input from stdin
|
2021-08-11 12:57:27 +03:00
|
|
|
optStdinInputFile :: Maybe FilePath
|
|
|
|
}
|
|
|
|
deriving (Show)
|
|
|
|
|
2019-02-24 23:38:10 +03:00
|
|
|
optsParserInfo :: ParserInfo Opts
|
2020-01-24 18:06:51 +03:00
|
|
|
optsParserInfo =
|
|
|
|
info (helper <*> ver <*> exts <*> optsParser) . mconcat $
|
2020-12-12 00:06:38 +03:00
|
|
|
[fullDesc]
|
2019-02-24 23:38:10 +03:00
|
|
|
where
|
|
|
|
ver :: Parser (a -> a)
|
2020-01-24 18:06:51 +03:00
|
|
|
ver =
|
|
|
|
infoOption verStr . mconcat $
|
|
|
|
[ long "version",
|
|
|
|
short 'v',
|
|
|
|
help "Print version of the program"
|
|
|
|
]
|
|
|
|
verStr =
|
|
|
|
intercalate
|
|
|
|
"\n"
|
2023-01-02 20:47:20 +03:00
|
|
|
[ unwords $
|
|
|
|
["ormolu", showVersion version]
|
|
|
|
<> maybeToList $$(envQ @String "ORMOLU_REV"),
|
2020-01-24 18:06:51 +03:00
|
|
|
"using ghc-lib-parser " ++ VERSION_ghc_lib_parser
|
2019-02-24 23:38:10 +03:00
|
|
|
]
|
2019-07-10 05:56:15 +03:00
|
|
|
exts :: Parser (a -> a)
|
2020-01-24 18:06:51 +03:00
|
|
|
exts =
|
|
|
|
infoOption displayExts . mconcat $
|
|
|
|
[ long "manual-exts",
|
|
|
|
help "Display extensions that need to be enabled manually"
|
|
|
|
]
|
2019-09-02 18:10:08 +03:00
|
|
|
displayExts = unlines $ sort (showOutputable <$> manualExts)
|
2019-02-24 23:38:10 +03:00
|
|
|
|
|
|
|
optsParser :: Parser Opts
|
2020-01-24 18:06:51 +03:00
|
|
|
optsParser =
|
|
|
|
Opts
|
2020-06-26 11:51:39 +03:00
|
|
|
<$> ( (fmap (bool Stdout InPlace) . switch . mconcat)
|
|
|
|
[ short 'i',
|
|
|
|
help "A shortcut for --mode inplace"
|
|
|
|
]
|
|
|
|
<|> (option parseMode . mconcat)
|
|
|
|
[ long "mode",
|
|
|
|
short 'm',
|
|
|
|
metavar "MODE",
|
|
|
|
value Stdout,
|
2020-11-14 21:51:07 +03:00
|
|
|
help "Mode of operation: 'stdout' (the default), 'inplace', or 'check'"
|
2020-06-26 11:51:39 +03:00
|
|
|
]
|
|
|
|
)
|
2020-01-24 18:06:51 +03:00
|
|
|
<*> configParser
|
2023-05-15 22:35:35 +03:00
|
|
|
<*> configFileOptsParser
|
2021-10-18 17:00:46 +03:00
|
|
|
<*> sourceTypeParser
|
2020-01-24 18:06:51 +03:00
|
|
|
<*> (many . strArgument . mconcat)
|
|
|
|
[ metavar "FILE",
|
2020-11-14 21:51:07 +03:00
|
|
|
help "Haskell source files to format or stdin (the default)"
|
2020-01-24 18:06:51 +03:00
|
|
|
]
|
2021-08-11 12:57:27 +03:00
|
|
|
|
2023-05-15 22:35:35 +03:00
|
|
|
configFileOptsParser :: Parser ConfigFileOpts
|
|
|
|
configFileOptsParser =
|
|
|
|
ConfigFileOpts
|
2021-08-11 12:57:27 +03:00
|
|
|
<$> (switch . mconcat)
|
2021-11-10 19:00:04 +03:00
|
|
|
[ long "no-cabal",
|
2023-05-15 22:35:35 +03:00
|
|
|
help "Do not extract default-extensions and dependencies from .cabal files"
|
|
|
|
]
|
|
|
|
<*> (switch . mconcat)
|
|
|
|
[ long "no-dot-ormolu",
|
|
|
|
help "Do not look for .ormolu files"
|
2021-08-11 12:57:27 +03:00
|
|
|
]
|
|
|
|
<*> (optional . strOption . mconcat)
|
|
|
|
[ long "stdin-input-file",
|
|
|
|
help "Path which will be used to find the .cabal file when using input from stdin"
|
|
|
|
]
|
2019-03-01 00:16:15 +03:00
|
|
|
|
2020-04-23 19:41:32 +03:00
|
|
|
configParser :: Parser (Config RegionIndices)
|
2020-01-24 18:06:51 +03:00
|
|
|
configParser =
|
|
|
|
Config
|
|
|
|
<$> (fmap (fmap DynOption) . many . strOption . mconcat)
|
|
|
|
[ long "ghc-opt",
|
|
|
|
short 'o',
|
|
|
|
metavar "OPT",
|
|
|
|
help "GHC options to enable (e.g. language extensions)"
|
|
|
|
]
|
2023-02-25 19:47:24 +03:00
|
|
|
<*> ( fmap (FixityOverrides . Map.fromList . mconcat)
|
2022-05-03 18:00:21 +03:00
|
|
|
. many
|
|
|
|
. option parseFixityDeclaration
|
|
|
|
. mconcat
|
|
|
|
)
|
|
|
|
[ long "fixity",
|
|
|
|
short 'f',
|
|
|
|
metavar "FIXITY",
|
|
|
|
help "Fixity declaration to use (an override)"
|
|
|
|
]
|
2023-05-03 21:23:07 +03:00
|
|
|
<*> ( fmap (ModuleReexports . Map.fromListWith (<>) . mconcat . pure)
|
|
|
|
. many
|
|
|
|
. option parseModuleReexportDeclaration
|
|
|
|
. mconcat
|
|
|
|
)
|
|
|
|
[ long "reexport",
|
|
|
|
short 'r',
|
|
|
|
metavar "REEXPORT",
|
|
|
|
help "Module re-export that Ormolu should know about"
|
|
|
|
]
|
2021-11-10 19:00:04 +03:00
|
|
|
<*> (fmap Set.fromList . many . strOption . mconcat)
|
|
|
|
[ long "package",
|
|
|
|
short 'p',
|
|
|
|
metavar "PACKAGE",
|
|
|
|
help "Explicitly specified dependency (for operator fixity/precedence only)"
|
|
|
|
]
|
2020-01-24 18:06:51 +03:00
|
|
|
<*> (switch . mconcat)
|
|
|
|
[ long "unsafe",
|
|
|
|
short 'u',
|
|
|
|
help "Do formatting faster but without automatic detection of defects"
|
|
|
|
]
|
|
|
|
<*> (switch . mconcat)
|
|
|
|
[ long "debug",
|
|
|
|
short 'd',
|
|
|
|
help "Output information useful for debugging"
|
|
|
|
]
|
|
|
|
<*> (switch . mconcat)
|
2020-04-27 16:06:12 +03:00
|
|
|
[ long "check-idempotence",
|
2020-01-24 18:06:51 +03:00
|
|
|
short 'c',
|
|
|
|
help "Fail if formatting is not idempotent"
|
|
|
|
]
|
2021-10-18 17:00:46 +03:00
|
|
|
-- We cannot parse the source type here, because we might need to do
|
|
|
|
-- autodection based on the input file extension (not available here)
|
|
|
|
-- before storing the resolved value in the config struct.
|
|
|
|
<*> pure ModuleSource
|
2020-11-14 21:51:07 +03:00
|
|
|
<*> (option parseColorMode . mconcat)
|
|
|
|
[ long "color",
|
|
|
|
metavar "WHEN",
|
|
|
|
value Auto,
|
|
|
|
help "Colorize the output; WHEN can be 'never', 'always', or 'auto' (the default)"
|
|
|
|
]
|
2020-04-23 19:41:32 +03:00
|
|
|
<*> ( RegionIndices
|
|
|
|
<$> (optional . option auto . mconcat)
|
|
|
|
[ long "start-line",
|
2020-04-25 00:10:23 +03:00
|
|
|
metavar "START",
|
|
|
|
help "Start line of the region to format (starts from 1)"
|
2020-04-23 19:41:32 +03:00
|
|
|
]
|
|
|
|
<*> (optional . option auto . mconcat)
|
|
|
|
[ long "end-line",
|
2020-04-25 00:10:23 +03:00
|
|
|
metavar "END",
|
2020-04-23 19:41:32 +03:00
|
|
|
help "End line of the region to format (inclusive)"
|
|
|
|
]
|
|
|
|
)
|
2019-02-24 23:38:10 +03:00
|
|
|
|
2021-10-18 17:00:46 +03:00
|
|
|
sourceTypeParser :: Parser (Maybe SourceType)
|
|
|
|
sourceTypeParser =
|
|
|
|
(option parseSourceType . mconcat)
|
|
|
|
[ long "source-type",
|
|
|
|
short 't',
|
|
|
|
metavar "TYPE",
|
|
|
|
value Nothing,
|
|
|
|
help "Set the type of source; TYPE can be 'module', 'sig', or 'auto' (the default)"
|
|
|
|
]
|
|
|
|
|
2019-02-24 23:38:10 +03:00
|
|
|
----------------------------------------------------------------------------
|
|
|
|
-- Helpers
|
|
|
|
|
|
|
|
-- | Parse 'Mode'.
|
|
|
|
parseMode :: ReadM Mode
|
|
|
|
parseMode = eitherReader $ \case
|
|
|
|
"stdout" -> Right Stdout
|
|
|
|
"inplace" -> Right InPlace
|
|
|
|
"check" -> Right Check
|
|
|
|
s -> Left $ "unknown mode: " ++ s
|
2020-11-14 21:51:07 +03:00
|
|
|
|
2022-05-03 18:00:21 +03:00
|
|
|
-- | Parse a fixity declaration.
|
2023-01-06 16:42:22 +03:00
|
|
|
parseFixityDeclaration :: ReadM [(OpName, FixityInfo)]
|
2022-05-03 18:00:21 +03:00
|
|
|
parseFixityDeclaration = eitherReader parseFixityDeclarationStr
|
|
|
|
|
2023-05-03 21:23:07 +03:00
|
|
|
-- | Parse a module reexport declaration.
|
2023-06-02 12:27:07 +03:00
|
|
|
parseModuleReexportDeclaration ::
|
|
|
|
ReadM (ModuleName, NonEmpty (Maybe PackageName, ModuleName))
|
2023-05-03 21:23:07 +03:00
|
|
|
parseModuleReexportDeclaration = eitherReader parseModuleReexportDeclarationStr
|
|
|
|
|
2021-10-18 17:00:46 +03:00
|
|
|
-- | Parse 'ColorMode'.
|
2020-11-14 21:51:07 +03:00
|
|
|
parseColorMode :: ReadM ColorMode
|
|
|
|
parseColorMode = eitherReader $ \case
|
|
|
|
"never" -> Right Never
|
|
|
|
"always" -> Right Always
|
|
|
|
"auto" -> Right Auto
|
|
|
|
s -> Left $ "unknown color mode: " ++ s
|
2021-10-18 17:00:46 +03:00
|
|
|
|
|
|
|
-- | Parse the 'SourceType'. 'Nothing' means that autodetection based on
|
|
|
|
-- file extension is requested.
|
|
|
|
parseSourceType :: ReadM (Maybe SourceType)
|
|
|
|
parseSourceType = eitherReader $ \case
|
|
|
|
"module" -> Right (Just ModuleSource)
|
|
|
|
"sig" -> Right (Just SignatureSource)
|
|
|
|
"auto" -> Right Nothing
|
|
|
|
s -> Left $ "unknown source type: " ++ s
|