2023-10-20 11:42:01 -04:00
|
|
|
module Options
|
|
|
|
|
|
|
|
import Quox.Pretty
|
|
|
|
import System
|
|
|
|
import System.Console.GetOpt
|
|
|
|
import System.File
|
|
|
|
import System.Term
|
|
|
|
import Derive.Prelude
|
|
|
|
|
2023-10-24 12:25:56 -04:00
|
|
|
%default total
|
2023-10-20 11:42:01 -04:00
|
|
|
%language ElabReflection
|
|
|
|
|
|
|
|
public export
|
2023-11-05 09:47:52 -05:00
|
|
|
data OutFile = File String | Console | NoOut
|
2023-10-20 11:42:01 -04:00
|
|
|
%name OutFile f
|
|
|
|
%runElab derive "OutFile" [Eq, Ord, Show]
|
|
|
|
|
|
|
|
public export
|
2023-10-24 17:52:19 -04:00
|
|
|
data Phase = Parse | Check | Erase | Scheme
|
2023-10-20 11:42:01 -04:00
|
|
|
%name Phase p
|
|
|
|
%runElab derive "Phase" [Eq, Ord, Show]
|
|
|
|
|
|
|
|
||| a list of all `Phase`s
|
|
|
|
public export %inline
|
|
|
|
allPhases : List Phase
|
|
|
|
allPhases = %runElab do
|
|
|
|
-- as a script so it stays up to date
|
|
|
|
cs <- getCons $ fst !(lookupName "Phase")
|
|
|
|
traverse (check . var) cs
|
|
|
|
|
2023-11-05 09:47:52 -05:00
|
|
|
||| "guess" is Term for a terminal and NoHL for a file
|
|
|
|
public export
|
|
|
|
data HLType = Guess | NoHL | Term | Html
|
|
|
|
%runElab derive "HLType" [Eq, Ord, Show]
|
|
|
|
|
2023-10-20 11:42:01 -04:00
|
|
|
public export
|
|
|
|
record Options where
|
|
|
|
constructor MkOpts
|
2023-11-05 09:47:52 -05:00
|
|
|
hlType : HLType
|
2023-10-20 11:42:01 -04:00
|
|
|
outFile : OutFile
|
|
|
|
until : Maybe Phase
|
|
|
|
flavor : Pretty.Flavor
|
|
|
|
width : Nat
|
|
|
|
include : List String
|
|
|
|
%name Options opts
|
|
|
|
%runElab derive "Options" [Show]
|
|
|
|
|
2023-11-05 09:40:19 -05:00
|
|
|
export
|
|
|
|
defaultWidth : IO Nat
|
|
|
|
defaultWidth = do
|
|
|
|
w <- cast {to = Nat} <$> getTermCols
|
|
|
|
pure $ if w == 0 then 80 else w
|
|
|
|
|
2023-10-20 11:42:01 -04:00
|
|
|
export
|
|
|
|
defaultOpts : IO Options
|
|
|
|
defaultOpts = pure $ MkOpts {
|
2023-11-05 09:47:52 -05:00
|
|
|
hlType = Guess,
|
2023-11-01 09:16:03 -04:00
|
|
|
outFile = Console,
|
2023-10-20 11:42:01 -04:00
|
|
|
until = Nothing,
|
|
|
|
flavor = Unicode,
|
2023-11-05 09:40:19 -05:00
|
|
|
width = !defaultWidth,
|
2023-10-20 11:42:01 -04:00
|
|
|
include = ["."]
|
|
|
|
}
|
|
|
|
|
|
|
|
private
|
|
|
|
data HelpType = Common | All
|
|
|
|
|
|
|
|
private
|
|
|
|
data OptAction = ShowHelp HelpType | Err String | Ok (Options -> Options)
|
|
|
|
%name OptAction act
|
|
|
|
|
|
|
|
private
|
|
|
|
toOutFile : String -> OptAction
|
2023-11-05 09:47:52 -05:00
|
|
|
toOutFile "" = Ok {outFile := NoOut}
|
2023-11-01 09:16:03 -04:00
|
|
|
toOutFile "-" = Ok {outFile := Console}
|
2023-10-20 11:42:01 -04:00
|
|
|
toOutFile f = Ok {outFile := File f}
|
|
|
|
|
|
|
|
private
|
|
|
|
toPhase : String -> OptAction
|
2023-10-24 12:25:56 -04:00
|
|
|
toPhase str =
|
|
|
|
let lstr = toLower str in
|
|
|
|
case find (\p => toLower (show p) == lstr) allPhases of
|
|
|
|
Just p => Ok {until := Just p}
|
|
|
|
Nothing => Err "unknown phase name \{show str}\nphases: \{phaseNames}"
|
|
|
|
where phaseNames = joinBy ", " $ map (toLower . show) allPhases
|
2023-10-20 11:42:01 -04:00
|
|
|
|
|
|
|
private
|
|
|
|
toWidth : String -> OptAction
|
|
|
|
toWidth s = case parsePositive s of
|
|
|
|
Just n => Ok {width := n}
|
|
|
|
Nothing => Err "invalid width: \{show s}"
|
|
|
|
|
2023-11-05 09:47:52 -05:00
|
|
|
private
|
|
|
|
toHLType : String -> OptAction
|
|
|
|
toHLType str = case toLower str of
|
|
|
|
"none" => Ok {hlType := NoHL}
|
|
|
|
"term" => Ok {hlType := Term}
|
|
|
|
"html" => Ok {hlType := Html}
|
|
|
|
_ => Err "unknown highlighting type \{str}\ntypes: term, html, none"
|
|
|
|
|
2023-10-20 11:42:01 -04:00
|
|
|
private
|
|
|
|
commonOptDescrs' : List (OptDescr OptAction)
|
|
|
|
commonOptDescrs' = [
|
|
|
|
MkOpt ['i'] ["include"] (ReqArg (\i => Ok {include $= (i ::)}) "<dir>")
|
|
|
|
"add a directory to look for source files",
|
|
|
|
MkOpt ['o'] ["output"] (ReqArg toOutFile "<file>")
|
|
|
|
"output file (\"-\" for stdout, \"\" for no output)",
|
|
|
|
MkOpt ['P'] ["phase"] (ReqArg toPhase "<phase>")
|
|
|
|
"phase to stop at (by default go as far as exists)"
|
|
|
|
]
|
|
|
|
|
|
|
|
private
|
|
|
|
extraOptDescrs : List (OptDescr OptAction)
|
|
|
|
extraOptDescrs = [
|
|
|
|
MkOpt [] ["unicode"] (NoArg $ Ok {flavor := Unicode})
|
|
|
|
"use unicode syntax when printing (default)",
|
|
|
|
MkOpt [] ["ascii"] (NoArg $ Ok {flavor := Ascii})
|
|
|
|
"use ascii syntax when printing",
|
|
|
|
MkOpt [] ["width"] (ReqArg toWidth "<width>")
|
|
|
|
"max output width (defaults to terminal width)",
|
2023-11-05 09:47:52 -05:00
|
|
|
MkOpt [] ["color", "colour"] (ReqArg toHLType "<type>")
|
|
|
|
"select highlighting type"
|
2023-10-20 11:42:01 -04:00
|
|
|
]
|
|
|
|
|
|
|
|
private
|
|
|
|
helpOptDescrs : List (OptDescr OptAction)
|
|
|
|
helpOptDescrs = [
|
|
|
|
MkOpt ['h'] ["help"] (NoArg $ ShowHelp Common) "show common options",
|
|
|
|
MkOpt [] ["help-all"] (NoArg $ ShowHelp All) "show all options"
|
|
|
|
]
|
|
|
|
|
|
|
|
commonOptDescrs = commonOptDescrs' ++ helpOptDescrs
|
|
|
|
allOptDescrs = commonOptDescrs' ++ extraOptDescrs ++ helpOptDescrs
|
|
|
|
|
|
|
|
export
|
|
|
|
usageHeader : String
|
2023-11-05 09:47:52 -05:00
|
|
|
usageHeader = trim """
|
|
|
|
quox [options] [file.quox ...]
|
|
|
|
rawr
|
|
|
|
"""
|
2023-10-20 11:42:01 -04:00
|
|
|
|
|
|
|
export
|
|
|
|
usage : List (OptDescr _) -> IO a
|
|
|
|
usage ds = do
|
|
|
|
ignore $ fPutStr stderr $ usageInfo usageHeader ds
|
|
|
|
exitSuccess
|
|
|
|
|
|
|
|
private
|
|
|
|
applyAction : Options -> OptAction -> IO Options
|
|
|
|
applyAction opts (ShowHelp Common) = usage commonOptDescrs
|
|
|
|
applyAction opts (ShowHelp All) = usage allOptDescrs
|
|
|
|
applyAction opts (Err err) = die err
|
|
|
|
applyAction opts (Ok f) = pure $ f opts
|
|
|
|
|
|
|
|
private
|
|
|
|
finalise : Options -> Options
|
|
|
|
finalise = {include $= reverse}
|
|
|
|
|
|
|
|
export
|
|
|
|
options : IO (String, Options, List String)
|
|
|
|
options = do
|
|
|
|
app :: args <- getArgs
|
|
|
|
| [] => die "couldn't get command line arguments"
|
|
|
|
let res = getOpt Permute allOptDescrs args
|
|
|
|
unless (null res.errors) $
|
|
|
|
die $ trim $ concat res.errors
|
|
|
|
unless (null res.unrecognized) $
|
|
|
|
die "unrecognised options: \{joinBy ", " res.unrecognized}"
|
|
|
|
opts <- foldlM applyAction !defaultOpts res.options
|
|
|
|
pure (app, finalise opts, res.nonOptions)
|