hnix/main/Main.hs

148 lines
4.9 KiB
Haskell
Raw Normal View History

2018-04-06 06:10:06 +02:00
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
-- {-# LANGUAGE QuasiQuotes #-}
module Main where
2018-04-10 17:34:21 +02:00
import Control.DeepSeq
import qualified Control.Exception as Exc
import Control.Monad
import Control.Monad.ST
import Data.Text (Text, pack)
import qualified Data.Text.IO as Text
import qualified Nix
import Nix.Expr
import Nix.Lint
import Nix.Parser
import Nix.Pretty
import Nix.Stack (NixException(..))
-- import Nix.TH
import Options.Applicative hiding (ParserResult(..))
import System.IO
import Text.PrettyPrint.ANSI.Leijen hiding ((<$>))
data Options = Options
{ verbose :: Bool
, debug :: Bool
, evaluate :: Bool
, check :: Bool
, parse :: Bool
, parseOnly :: Bool
, ignoreErrors :: Bool
, expression :: Maybe Text
, arg :: [NExpr]
, argstr :: [Text]
, fromFile :: Maybe FilePath
, filePaths :: [FilePath]
}
mainOptions :: Parser Options
mainOptions = Options
<$> switch
( short 'v'
<> long "verbose"
<> help "Verbose output")
<*> switch
( short 'd'
<> long "debug"
<> help "Debug output")
<*> switch
( long "eval"
<> help "Whether to evaluate, or just pretty-print")
<*> switch
( long "check"
<> help "Whether to check for syntax errors after parsing")
<*> switch
( long "parse"
<> help "Whether to parse the file (also the default right now)")
2018-04-10 17:34:21 +02:00
<*> switch
( long "parse-only"
<> help "Whether to parse only, no pretty printing or checking")
<*> switch
( long "ignore-errors"
<> help "Continue parsing files, even if there are errors")
<*> optional (strOption
( short 'E'
<> long "expr"
<> help "Expression to parse or evaluate"))
<*> multiString
(\s -> case parseNixText (pack s) of
Success x -> pure x
Failure err -> errorWithoutStackTrace (show err))
( long "arg"
<> help "Argument to pass to an evaluated lambda")
<*> multiString (pure . pack)
( long "argstr"
<> help "Argument string to pass to an evaluated lambda")
<*> optional (strOption
( short 'f'
<> long "file"
<> help "Parse all of the files given in FILE; - means stdin"))
<*> many (strArgument (metavar "FILE" <> help "Path of file to parse"))
where
multiString f desc = many (option (str >>= f) desc)
main :: IO ()
main = do
opts <- execParser optsDef
case expression opts of
Just s -> handleResult opts Nothing (parseNixTextLoc s)
Nothing -> case fromFile opts of
Just "-" ->
mapM_ (processFile opts) =<< (lines <$> getContents)
Just path ->
mapM_ (processFile opts) =<< (lines <$> readFile path)
Nothing -> case filePaths opts of
[] ->
handleResult opts Nothing . parseNixTextLoc
=<< Text.getContents
["-"] ->
handleResult opts Nothing . parseNixTextLoc
=<< Text.getContents
paths ->
mapM_ (processFile opts) paths
where
optsDef :: ParserInfo Options
optsDef = info (helper <*> mainOptions)
(fullDesc <> progDesc "" <> header "hnix")
processFile opts path = do
2018-04-09 11:07:40 +02:00
-- putStrLn "Parsing file..."
eres <- parseNixFileLoc path
handleResult opts (Just path) eres
2018-04-03 23:24:16 +02:00
-- print . printNix =<< Nix.eval [nix|1 + 3|]
handleResult opts mpath = \case
Failure err ->
(if ignoreErrors opts
then hPutStrLn stderr
else errorWithoutStackTrace) $ "Parse failed: " ++ show err
Success expr -> Exc.catch (process expr) $ \case
NixEvalException msg -> errorWithoutStackTrace msg
where
process expr = do
2018-04-09 11:07:40 +02:00
-- expr <- Exc.evaluate $ force expr
-- putStrLn "Parsing file...done"
when (check opts) $
putStrLn $ runST $ Nix.runLintM . renderSymbolic
=<< Nix.lint expr
let _args = arg opts ++ map mkStr (argstr opts)
if | evaluate opts, debug opts ->
print =<< Nix.tracingEvalLoc mpath expr
| evaluate opts ->
putStrLn . printNix =<< Nix.evalLoc mpath expr
| debug opts ->
print $ stripAnnotation expr
2018-04-10 17:34:21 +02:00
| parseOnly opts ->
void $ Exc.evaluate $ force expr
| otherwise ->
displayIO stdout
. renderPretty 0.4 80
. prettyNix
. stripAnnotation $ expr