millfork/src/main/scala/millfork/cli/CliOption.scala

201 lines
4.3 KiB
Scala

package millfork.cli
/**
* @author Karol Stasiak
*/
trait CliOption[T, O <: CliOption[T, O]] {
this: O =>
def toStrings(firstTab: Int): List[String] = {
val fl = firstLine
if (_description == "") {
List(fl)
} else if (fl.length < firstTab) {
List(fl.padTo(firstTab, ' ') + _description)
} else {
List(fl, "".padTo(firstTab, ' ') + _description)
}
}
protected def firstLine: String = names.mkString(" | ")
def names: Seq[String]
private[cli] def length: Int
private[cli] val _shortName: String
private[cli] var _description: String = ""
private[cli] var _hidden = false
private[cli] var _maxEncounters = 1
private[cli] var _minEncounters = 0
private[cli] var _actualEncounters = 0
private[cli] var _onTooFew: Option[Int => Unit] = None
private[cli] var _onTooMany: Option[Int => Unit] = None
def validate(): Boolean = {
var ok = true
if (_actualEncounters < _minEncounters) {
_onTooFew.fold(throw new IllegalArgumentException(s"Too few ${_shortName} options: required ${_minEncounters}, given ${_actualEncounters}"))(_ (_actualEncounters))
ok = false
}
if (_actualEncounters > _maxEncounters) {
_onTooMany.fold()(_ (_actualEncounters))
ok = false
}
ok
}
def onWrongNumber(action: Int => Unit): Unit = {
_onTooFew = Some(action)
_onTooMany = Some(action)
}
def onTooFew(action: Int => Unit): Unit = {
_onTooFew = Some(action)
}
def onTooMany(action: Int => Unit): Unit = {
_onTooMany = Some(action)
}
def encounter(): Unit = {
_actualEncounters += 1
}
def description(d: String): O = {
_description = d
this
}
def hidden(): O = {
_hidden = true
this
}
def minCount(count: Int): O = {
_minEncounters = count
this
}
def maxCount(count: Int): O = {
_maxEncounters = count
this
}
def required(): O = minCount(1)
def repeatable(): O = maxCount(Int.MaxValue)
}
class Fluff[T](val text: Seq[String]) extends CliOption[T, Fluff[T]] {
this.repeatable()
override def toStrings(firstTab: Int): List[String] = text.toList
override def length = 0
override val _shortName = ""
override def names = Nil
}
class NoMoreOptions[T](val names: Seq[String]) extends CliOption[T, NoMoreOptions[T]] {
this.repeatable()
override def length = 1
override val _shortName = names.head
}
class UnknownParamOption[T] extends CliOption[T, UnknownParamOption[T]] {
this._hidden = true
override def length = 0
val names: Seq[String] = Nil
private var _action: ((String, T) => T) = (_, x) => x
def action(a: ((String, T) => T)): UnknownParamOption[T] = {
_action = a
this
}
def encounter(value: String, t: T): T = {
encounter()
_action(value, t)
}
override private[cli] val _shortName = ""
}
class FlagOption[T](val names: Seq[String]) extends CliOption[T, FlagOption[T]] {
override def length = 1
private var _action: (T => T) = x => x
def action(a: (T => T)): FlagOption[T] = {
_action = a
this
}
def encounter(t: T): T = {
encounter()
_action(t)
}
override val _shortName = names.head
}
class BooleanOption[T](val trueName: String, val falseName: String) extends CliOption[T, BooleanOption[T]] {
override def length = 1
private var _action: ((T,Boolean) => T) = (x,_) => x
def action(a: ((T,Boolean) => T)): BooleanOption[T] = {
_action = a
this
}
def encounter(asName: String, t: T): T = {
encounter()
if (asName == trueName) {
return _action(t, true)
}
if (asName == falseName) {
return _action(t, false)
}
t
}
override val _shortName = names.head
override protected def firstLine: String = trueName + " | " + falseName
override def names = Seq(trueName, falseName)
}
class ParamOption[T](val names: Seq[String]) extends CliOption[T, ParamOption[T]] {
override protected def firstLine: String = names.mkString(" | ") + " " + _paramPlaceholder
override def length = 2
private var _action: ((String, T) => T) = (_, x) => x
private var _paramPlaceholder: String = "<x>"
def placeholder(p: String): ParamOption[T] = {
_paramPlaceholder = p
this
}
def action(a: ((String, T) => T)): ParamOption[T] = {
_action = a
this
}
def encounter(value: String, t: T): T = {
encounter()
_action(value, t)
}
override val _shortName = names.head
}