
caseapp.core.Parser.scala Maven / Gradle / Ivy
package caseapp
package core
import shapeless._
import caseapp.util.AnnotationList
trait Parser[T] { self =>
type D
def init: D
def step(args: Seq[String], d: D): Either[String, Option[(D, Seq[String])]]
def get(d: D): Either[String, T]
def args: Seq[Arg]
def parse(args: Seq[String]): Either[String, (T, Seq[String])] =
detailedParse(args).right.map {
case (t, rem, extra) =>
(t, rem ++ extra)
}
def apply(args: Seq[String]): Either[String, (T, Seq[String])] =
parse(args)
/** Keeps the remaining args before and after a possible -- separated */
def detailedParse(args: Seq[String]): Either[String, (T, Seq[String], Seq[String])] = {
import scala.::
def helper(
current: D,
args: Seq[String],
extraArgsReverse: List[String]
): Either[String, (T, List[String], List[String])] =
if (args.isEmpty)
get(current).right.map((_, extraArgsReverse.reverse, Nil))
else
step(args, current) match {
case Right(None) =>
args match {
case "--" :: t =>
get(current).right.map((_, extraArgsReverse.reverse, t))
case opt :: _ if opt startsWith "-" =>
Left(s"Unrecognized argument: $opt")
case userArg :: rem =>
helper(current, rem, userArg :: extraArgsReverse)
}
case Right(Some((newC, newArgs))) =>
assert(newArgs != args)
helper(newC, newArgs, extraArgsReverse)
case Left(msg) =>
Left(msg)
}
helper(init, args.toList, Nil)
}
def withHelp: Parser[WithHelp[T]] = {
implicit val parser: Parser.Aux[T, D] = this
Parser[WithHelp[T]]
}
def map[U](f: T => U): Parser.Aux[U, D] =
new Parser[U] {
type D = self.D
def init = self.init
def step(args: Seq[String], d: D) = self.step(args, d)
def get(d: D) = self.get(d).right.map(f)
def args = self.args
}
}
object Parser {
def apply[T](implicit parser: Parser[T]): Aux[T, parser.D] = parser
type Aux[T, D0] = Parser[T] { type D = D0 }
implicit def generic[CC, L <: HList, D <: HList, N <: HList, V <: HList, M <: HList, H <: HList, R <: HList, P <: HList]
(implicit
gen: LabelledGeneric.Aux[CC, L],
defaults: shapeless.Default.AsOptions.Aux[CC, D],
names: AnnotationList.Aux[Name, CC, N],
valuesDesc: Annotations.Aux[ValueDescription, CC, V],
helpMessages: Annotations.Aux[HelpMessage, CC, M],
noHelp: Annotations.Aux[Hidden, CC, H],
recurse: Annotations.Aux[Recurse, CC, R],
parser: Strict[HListParser.Aux[L, D, N, V, M, H, R, P]]
): Aux[CC, P] =
parser.value(defaults(), names(), valuesDesc(), helpMessages(), noHelp()).map(gen.from)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy