@@ -1,32 +1,142 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE LambdaCase #-}
3+{-# LANGUAGE RecordWildCards #-}
4+{-# LANGUAGE TemplateHaskell #-}
5+
16module Main (main) where
27
3−-- import Control.Monad
8+import Control.Monad
9+import Data.List (intercalate)
10+import Data.Version (showVersion)
11+import Development.GitRev
12+import Options.Applicative
413import Ormolu
5−import System.Environment (getArgs)
14+import Paths_ormolu (version)
15+import System.Exit (exitFailure)
616import qualified Data.Text.IO as TIO
7−-- import qualified Outputable as GHC
17+import qualified Data.Yaml as Yaml
18+
19+-- | Entry point of the program.
820
921main :: IO ()
1022main = withPrettyOrmoluExceptions $ do
11− (path:_) <- getArgs
12− r <- ormoluFile defaultConfig path
13− TIO.putStr r
14− -- TIO.
15−
16− -- input <- readFile path
17−
18− -- (ws, r) <- parseModule [] path input
19− -- unless (null ws) $
20− -- putStrLn "dynamic option warnings:"
21− -- case r of
22− -- Left (srcSpan, err) -> do
23− -- putStrLn (showOutputable srcSpan)
24− -- putStrLn err
25− -- Right (anns, parsedModule) -> do
26− -- putStrLn "\nannotations:\n"
27− -- putStrLn (showOutputable anns)
28− -- putStrLn "\nparsed module:\n"
29− -- putStrLn (showOutputable parsedModule)
30−
31−-- showOutputable :: GHC.Outputable o => o -> String
32−-- showOutputable = GHC.showSDocUnsafe . GHC.ppr
23+ Opts {..} <- execParser optsParserInfo
24+ config <- case optConfigFile of
25+ Nothing -> return Config
26+ { cfgDynOptions = optDynOptions
27+ , cfgUnsafe = optUnsafe
28+ }
29+ Just path -> do
30+ Config {..} <- Yaml.decodeFileThrow path
31+ return Config
32+ { cfgDynOptions = cfgDynOptions ++ optDynOptions
33+ , cfgUnsafe = optUnsafe || cfgUnsafe
34+ }
35+ r <- ormoluFile config optDebug optInputFile
36+ case optMode of
37+ Stdout ->
38+ TIO.putStr r
39+ InPlace ->
40+ TIO.writeFile optInputFile r
41+ Check -> do
42+ r' <- TIO.readFile optInputFile
43+ when (r /= r') exitFailure
44+
45+----------------------------------------------------------------------------
46+-- Command line options parsing.
47+
48+data Opts = Opts
49+ { optMode :: !Mode
50+ -- ^ Mode of operation
51+ , optConfigFile :: !(Maybe FilePath)
52+ -- ^ Location of configuration file (optional)
53+ , optUnsafe :: !Bool
54+ -- ^ Whether to skip sanity checking
55+ , optDynOptions :: ![DynOption]
56+ -- ^ GHC options to set
57+ , optDebug :: !Bool
58+ -- ^ Output information useful for debugging
59+ , optInputFile :: !FilePath
60+ -- ^ Input source file
61+ }
62+
63+-- | Mode of operation.
64+
65+data Mode
66+ = Stdout -- ^ Output formatted source code to stdout
67+ | InPlace -- ^ Overwrite original file
68+ | Check -- ^ Exit with non-zero status code if
69+ -- source is not already formatted
70+ deriving (Eq, Show)
71+
72+optsParserInfo :: ParserInfo Opts
73+optsParserInfo = info (helper <*> ver <*> optsParser) . mconcat $
74+ [ fullDesc
75+ , progDesc ""
76+ , header ""
77+ ]
78+ where
79+ ver :: Parser (a -> a)
80+ ver = infoOption verStr . mconcat $
81+ [ long "version"
82+ , short 'v'
83+ , help "Print version of the program"
84+ ]
85+ verStr = intercalate "\n"
86+ [ unwords
87+ [ "ormolu"
88+ , showVersion version
89+ , $gitBranch
90+ , $gitHash
91+ ]
92+ , "using ghc-exactprint " ++ VERSION_ghc_exactprint
93+ , "using ghc " ++ VERSION_ghc
94+ ]
95+
96+optsParser :: Parser Opts
97+optsParser = Opts
98+ <$> (option parseMode . mconcat)
99+ [ long "mode"
100+ , short 'm'
101+ , metavar "MODE"
102+ , value Stdout
103+ , help "Mode of operation: 'stdout', 'inplace', or 'check'"
104+ ]
105+ <*> (optional . strOption . mconcat)
106+ [ long "config"
107+ , short 'c'
108+ , metavar "CONFIG"
109+ , help "Location of configuration file"
110+ ]
111+ <*> (switch . mconcat)
112+ [ long "unsafe"
113+ , short 'u'
114+ , help "Do formatting faster but without automatic detection of defects"
115+ ]
116+ <*> (fmap (fmap DynOption) . many . strOption . mconcat)
117+ [ long "ghc-opt"
118+ , short 'o'
119+ , metavar "OPT"
120+ , help "GHC options to enable (e.g. language extensions)"
121+ ]
122+ <*> (switch . mconcat)
123+ [ long "debug"
124+ , short 'd'
125+ , help "Output information useful for debugging"
126+ ]
127+ <*> (strArgument . mconcat)
128+ [ metavar "FILE"
129+ , help "Haskell source file to format"
130+ ]
131+
132+----------------------------------------------------------------------------
133+-- Helpers
134+
135+-- | Parse 'Mode'.
136+
137+parseMode :: ReadM Mode
138+parseMode = eitherReader $ \case
139+ "stdout" -> Right Stdout
140+ "inplace" -> Right InPlace
141+ "check" -> Right Check
142+ s -> Left $ "unknown mode: " ++ s