All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ammonite.main.Cli.scala Maven / Gradle / Ivy

There is a newer version: 3.0.0-M0-71-1e75159e
Show newest version
package ammonite.main

import ammonite.runtime.Storage
import ammonite.util.Util

import scala.annotation.tailrec




object Cli{
  case class Arg[T, V](name: String,
                       shortName: Option[Char],
                       doc: String,
                       action: (T, V) => T)
                      (implicit val reader: scopt.Read[V]){
    def runAction(t: T, s: String) = action(t, reader.reads(s))
  }
  case class Config(predefCode: String = "",
                    defaultPredef: Boolean = true,
                    homePredef: Boolean = true,
                    wd: os.Path = os.pwd,
                    welcomeBanner: Option[String] = Some(Defaults.welcomeBanner),
                    verboseOutput: Boolean = true,
                    remoteLogging: Boolean = true,
                    watch: Boolean = false,
                    code: Option[String] = None,
                    home: os.Path = Defaults.ammoniteHome,
                    predefFile: Option[os.Path] = None,
                    help: Boolean = false,
                    colored: Option[Boolean] = None,
                    classBased: Boolean = false)


  import ammonite.main.Scripts.pathScoptRead
  val genericSignature = Seq(
    Arg[Config, String](
      "predef-code", None,
      "Any commands you want to execute at the start of the REPL session",
      (c, v) => c.copy(predefCode = v)
    ),

    Arg[Config, String](
      "code", Some('c'),
      "Pass in code to be run immediately in the REPL",
      (c, v) => c.copy(code = Some(v))
    ),
    Arg[Config, os.Path](
      "home", Some('h'),
      "The home directory of the REPL; where it looks for config and caches",
      (c, v) => c.copy(home = v)
    ),
    Arg[Config, os.Path](
      "predef", Some('p'),
      """Lets you load your predef from a custom location, rather than the
        |default location in your Ammonite home""".stripMargin,
      (c, v) => c.copy(predefFile = Some(v))
    ),
    Arg[Config, Unit](
      "no-home-predef", None,
      """Disables the default behavior of loading predef files from your
        |~/.ammonite/predef.sc, predefScript.sc, or predefShared.sc. You can
        |choose an additional predef to use using `--predef
        |""".stripMargin,
      (c, v) => c.copy(homePredef = false)
    ),

    Arg[Config, Unit](
      "no-default-predef", None,
      """Disable the default predef and run Ammonite with the minimal predef
        |possible
        |""".stripMargin,
      (c, v) => c.copy(defaultPredef = false)
    ),

    Arg[Config, Unit](
      "silent", Some('s'),
      """Make ivy logs go silent instead of printing though failures will
        |still throw exception""".stripMargin,
      (c, v) => c.copy(verboseOutput = false)
    ),
    Arg[Config, Unit](
      "help", None,
      """Print this message""".stripMargin,
      (c, v) => c.copy(help = true)
    ),
    Arg[Config, Boolean](
      "color", None,
      """Enable or disable colored output; by default colors are enabled
        |in both REPL and scripts if the console is interactive, and disabled
        |otherwise""".stripMargin,
      (c, v) => c.copy(colored = Some(v))
    ),
    Arg[Config, Unit](
      "watch", Some('w'),
      "Watch and re-run your scripts when they change",
      (c, v) => c.copy(watch = true)
    )
  )
  val replSignature = Seq(
    Arg[Config, String](
      "banner", Some('b'),
      "Customize the welcome banner that gets shown when Ammonite starts",
      (c, v) => c.copy(welcomeBanner = if (v.nonEmpty) Some(v) else None)
    ),
    Arg[Config, Unit](
      "no-remote-logging", None,
      """Disable remote logging of the number of times a REPL starts and runs
        |commands
        |""".stripMargin,
      (c, v) => c.copy(remoteLogging= false)
    ),
    Arg[Config, Unit](
      "class-based", None,
      """Wrap user code in classes rather than singletons, typically for Java serialization
        |friendliness.
        |""".stripMargin,
      (c, v) => c.copy(classBased=true)
    )

  )

  val ammoniteArgSignature = genericSignature ++ replSignature

  def showArg(arg: Arg[_, _]) =
    "  " + arg.shortName.fold("")("-" + _ + ", ") + "--" + arg.name

  def formatBlock(args: Seq[Arg[_, _]], leftMargin: Int) = {

    for(arg <- args) yield {
      showArg(arg).padTo(leftMargin, ' ').mkString +
      Predef.augmentString(arg.doc).lines.mkString(Util.newLine + " " * leftMargin)
    }
  }
  def ammoniteHelp = {
    val leftMargin = ammoniteArgSignature.map(showArg(_).length).max + 2


    s"""Ammonite REPL & Script-Runner, ${ammonite.Constants.version}
       |usage: amm [ammonite-options] [script-file [script-options]]
       |
       |${formatBlock(genericSignature, leftMargin).mkString(Util.newLine)}
       |
       |REPL-specific args:
       |${formatBlock(replSignature, leftMargin).mkString(Util.newLine)}
    """.stripMargin
  }

  def groupArgs[T](flatArgs: List[String],
                   args: Seq[Arg[T, _]],
                   initial: T): Either[String, (T, List[String])] = {

    val argsMap0: Seq[(String, Arg[T, _])] = args
      .flatMap{x => Seq(x.name -> x) ++ x.shortName.map(_.toString -> x)}

    val argsMap = argsMap0.toMap

    @tailrec def rec(keywordTokens: List[String],
                     current: T): Either[String, (T, List[String])] = {
      keywordTokens match{
        case head :: rest if head(0) == '-' =>
          val realName = if(head(1) == '-') head.drop(2) else head.drop(1)

          argsMap.get(realName) match {
            case Some(cliArg) =>
              if (cliArg.reader == scopt.Read.unitRead) {
                rec(rest, cliArg.runAction(current, ""))
              } else rest match{
                case next :: rest2 => rec(rest2, cliArg.runAction(current, next))
                case Nil => Left(s"Expected a value after argument $head")
              }

            case None => Right((current, keywordTokens))
          }

        case _ => Right((current, keywordTokens))

      }
    }
    rec(flatArgs, initial)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy