millfork/src/main/scala/millfork/cli/CliParser.scala

82 lines
2.4 KiB
Scala

package millfork.cli
import fastparse.core.Parsed.Failure
import scala.collection.mutable
/**
* @author Karol Stasiak
*/
class CliParser[T] {
private val options = mutable.ArrayBuffer[CliOption[T, _]]()
private val mapFlags = mutable.Map[String, CliOption[T, _]]()
private val mapOptions = mutable.Map[String, CliOption[T, _]]()
private val _default = new UnknownParamOption[T]().action((p, _) => throw new IllegalArgumentException(s"Unknown option $p"))
private var _status: Option[CliStatus.Value] = None
options += _default
private def add[O <: CliOption[T, _]](o: O) = {
options += o
o.length match {
case 1 =>
o.names.foreach { n => mapFlags(n) = o }
case 2 =>
o.names.foreach { n => mapOptions(n) = o }
case _ => ()
}
o
}
def parse(context: T, args: List[String]): (CliStatus.Value, T) = {
val t = parseInner(context, args)
_status.getOrElse(if (options.forall(_.validate())) CliStatus.Ok else CliStatus.Failed) -> t
}
def assumeStatus(s: CliStatus.Value): Unit = {
_status = Some(s)
}
private def parseInner(context: T, args: List[String]): T = {
args match {
case k :: v :: xs if mapOptions.contains(k) =>
mapOptions(k) match {
case p: ParamOption[T] => parseInner(p.encounter(v, context), xs)
case _ => ???
}
case k :: xs if mapFlags.contains(k) =>
mapFlags(k) match {
case p: FlagOption[T] =>
parseInner(p.encounter(context), xs)
case p: BooleanOption[T] =>
parseInner(p.encounter(k, context), xs)
case p: NoMoreOptions[T] =>
p.encounter()
xs.foldLeft(context)((t, x) => _default.encounter(x, t))
case _ => ???
}
case x :: xs =>
parseInner(_default.encounter(x, context), xs)
case Nil => context
}
}
def fluff(text: String*): Unit = add(new Fluff[T](text))
def flag(names: String*): FlagOption[T] = add(new FlagOption[T](names))
def boolean(trueName: String, falseName: String): BooleanOption[T] = add(new BooleanOption[T](trueName, falseName))
def endOfFlags(names: String*): NoMoreOptions[T] = add(new NoMoreOptions[T](names))
def default: UnknownParamOption[T] = _default
def printHelp(firstTab: Int): List[String] = {
options.filterNot(_._hidden).toList.flatMap(_.toStrings(firstTab))
}
def parameter(names: String*): ParamOption[T] = add(new ParamOption[T](names))
}