1
1
mirror of https://github.com/anoma/juvix.git synced 2024-12-15 01:52:11 +03:00
juvix/app/TopCommand/Options.hs
janmasrovira 3d012cc8fb
Support more paths (#2000)
- Closes #1993 

This pr makes it possible to use `~`, `..` and environment variables in
the `juvix.yaml` and all flags / input of the cli.

In the CLI, the shell will be responsible for replacing environment
variables with their value, so the usual syntax can be used. For the
`dependencies` field, I have implemented a parser that has some
restrictions:
1. Environment variables are given with the makefile-like syntax
`$(VAR)`
2. The three characters `$` `(` `)` are reserved for the environment
variables syntax.
    They cannot be part of the path.
3. `~` is reserved for `$(HOME)`. I.e. the prepath `~~` will expand to
`$HOME$HOME`.
4. Nested environment variables are not allowed.

Thanks @paulcadman for the feedback. I think we are ready to merge this
nightmarish pr 👻

---------

Co-authored-by: Paul Cadman <git@paulcadman.dev>
2023-04-19 15:56:48 +01:00

207 lines
5.2 KiB
Haskell

module TopCommand.Options where
import Commands.Compile.Options
import Commands.Dev.Options qualified as Dev
import Commands.Doctor.Options
import Commands.Eval.Options
import Commands.Format.Options
import Commands.Html.Options
import Commands.Repl.Options
import Commands.Typecheck.Options
import CommonOptions hiding (Doc)
import Data.Generics.Uniplate.Data
import GlobalOptions
import Options.Applicative.Help.Pretty
data TopCommand
= DisplayVersion
| DisplayNumericVersion
| DisplayHelp
| Typecheck TypecheckOptions
| Compile CompileOptions
| Eval EvalOptions
| Html HtmlOptions
| Dev Dev.DevCommand
| Doctor DoctorOptions
| Init
| JuvixRepl ReplOptions
| JuvixFormat FormatOptions
deriving stock (Data)
topCommandInputFile :: TopCommand -> IO (Maybe (Path Abs Dir))
topCommandInputFile t = do
d <- firstJustM getInputFileOrDir (universeBi t)
f <- firstJustM getInputFileDir (universeBi t)
return (f <|> d)
where
getInputFileDir :: AppPath File -> IO (Maybe (Path Abs Dir))
getInputFileDir p
| p ^. pathIsInput = do
cwd <- getCurrentDir
Just . parent <$> prepathToAbsFile cwd (p ^. pathPath)
| otherwise = return Nothing
getInputFileOrDir :: AppPath FileOrDir -> IO (Maybe (Path Abs Dir))
getInputFileOrDir p
| p ^. pathIsInput = do
cwd <- getCurrentDir
lr <- fromPreFileOrDir cwd (p ^. pathPath)
return . Just $ case lr of
Left file -> parent file
Right dir -> dir
| otherwise = return Nothing
parseDisplayVersion :: Parser TopCommand
parseDisplayVersion =
flag'
DisplayVersion
( long "version"
<> short 'v'
<> help "Show version information"
)
parseDisplayNumericVersion :: Parser TopCommand
parseDisplayNumericVersion =
flag'
DisplayNumericVersion
( long "numeric-version"
<> help "Show only the version number"
)
parseDisplayHelp :: Parser TopCommand
parseDisplayHelp =
flag'
DisplayHelp
( long "help"
<> short 'h'
<> help "Show the help text"
)
parseUtility :: Parser TopCommand
parseUtility =
hsubparser
( mconcat
[ commandGroup "Utility commands:",
metavar "UTILITY_CMD",
commandDoctor,
commandInit,
commandDev,
commandRepl,
commandFormat
]
)
where
commandInit :: Mod CommandFields TopCommand
commandInit =
command
"init"
( info
(pure Init)
(progDesc "Interactively initialize a Juvix project in the current directory")
)
commandDoctor :: Mod CommandFields TopCommand
commandDoctor =
command
"doctor"
( info
(Doctor <$> parseDoctorOptions)
(progDesc "Perform checks on your Juvix development environment")
)
commandRepl :: Mod CommandFields TopCommand
commandRepl =
command
"repl"
( info
(JuvixRepl <$> parseRepl)
(progDesc "Run the Juvix REPL")
)
commandFormat :: Mod CommandFields TopCommand
commandFormat =
command "format" $
info
(JuvixFormat <$> parseFormat)
( progDescDoc
( Just
( vsep
[ "Format a Juvix file or Juvix project",
"",
"When the command is run with an unformatted file it prints the reformatted source to standard output.",
"When the command is run with a project directory it prints a list of unformatted files in the project."
]
)
)
)
commandCheck :: Mod CommandFields TopCommand
commandCheck =
command "typecheck" $
info
(Typecheck <$> parseTypecheck)
(progDesc "Typecheck a Juvix file")
commandCompile :: Mod CommandFields TopCommand
commandCompile =
command "compile" $
info
(Compile <$> parseMainCompileOptions)
(progDesc "Compile a Juvix file")
commandEval :: Mod CommandFields TopCommand
commandEval =
command "eval" $
info
(Eval <$> parseEvalOptions)
(progDesc "Evaluate a Juvix file")
commandHtml :: Mod CommandFields TopCommand
commandHtml =
command "html" $
info
(Html <$> parseHtml)
(progDesc "Generate HTML for a Juvix file")
commandDev :: Mod CommandFields TopCommand
commandDev =
command "dev" $
info
(Dev <$> Dev.parseDevCommand)
(progDesc "Commands for the developers")
parseCompilerCommand :: Parser TopCommand
parseCompilerCommand =
hsubparser
( mconcat
[ commandGroup "Compiler commands:",
metavar "COMPILER_CMD",
commandCheck,
commandCompile,
commandEval,
commandHtml
]
)
parseTopCommand :: Parser TopCommand
parseTopCommand =
parseDisplayVersion
<|> parseDisplayNumericVersion
<|> parseDisplayHelp
<|> parseCompilerCommand
<|> parseUtility
descr :: ParserInfo (GlobalOptions, TopCommand)
descr =
info
( do
cli <- parseTopCommand
opts <- parseGlobalFlags
return (opts, cli)
)
( fullDesc
<> progDesc "The Juvix compiler."
<> footerDoc (Just foot)
)
where
foot :: Doc
foot = bold "maintainers: " <> "The Juvix Team"