「命令」看起來與任務類似:它是一個可從 sbt 主控台執行的具名操作。
然而,命令的實作將整個建置狀態(由 State 表示)作為其參數,並計算新的 State。這表示命令可以查看或修改其他 sbt 設定,例如。通常,當您需要執行常規任務中無法實現的操作時,您會使用命令。
命令主要有三個面向
使用者用來調用命令的語法,包括
在 sbt 中,語法部分(包括 Tab 鍵自動完成)是使用剖析器組合子指定的。如果您熟悉 Scala 標準程式庫中的剖析器組合子,這些非常相似。動作部分是函式 (State, T) => State
,其中 T
是剖析器產生的資料結構。請參閱 剖析輸入 頁面,瞭解如何使用剖析器組合子。
State 提供對建置狀態的存取權,例如所有已註冊的 Command
、要執行的其餘命令以及所有專案相關資訊。有關 State 的詳細資訊,請參閱 狀態和動作。
最後,可能會提供基本說明資訊,help
命令會使用這些資訊來顯示命令說明。
命令將函式 State => Parser[T]
與動作 (State, T) => State
結合。使用 State => Parser[T]
而不只是 Parser[T]
的原因是,目前的 State
通常用於建構剖析器。例如,目前載入的專案(由 State
提供)會決定 project
命令的有效完成。以下章節將說明一般和特定情況的範例。
有關建構命令的來源 API 詳細資訊,請參閱 Command.scala。
一般命令建構如下所示
val action: (State, T) => State = ...
val parser: State => Parser[T] = ...
val command: Command = Command("name")(parser)(action)
有一個方便的方法可建構不接受任何參數的命令。
val action: State => State = ...
val command: Command = Command.command("name")(action)
有一個方便的方法可建構接受單一任意內容參數的命令。
// accepts the state and the single argument
val action: (State, String) => State = ...
val command: Command = Command.single("name")(action)
有一個方便的方法可建構接受以空格分隔的多個參數的命令。
val action: (State, Seq[String]) => State = ...
// <arg> is the suggestion printed for tab completion on an argument
val command: Command = Command.args("name", "<arg>")(action)
以下範例是一個將命令新增至專案的範例建置。若要試用它
build.sbt
和 project/CommandExample.scala
。hello
、helloAll
、failIfTrue
、color
和 printState 命令。這是 build.sbt
import CommandExample._
ThisBuild / organization := "com.example"
ThisBuild / scalaVersion := "2.12.18"
ThisBuild / version := "0.1.0-SNAPSHOT"
lazy val root = (project in file("."))
.settings(
commands ++= Seq(hello, helloAll, failIfTrue, changeColor, printState)
)
這是 project/CommandExample.scala
import sbt._
import Keys._
// imports standard command parsing functionality
import complete.DefaultParsers._
object CommandExample {
// A simple, no-argument command that prints "Hi",
// leaving the current state unchanged.
def hello = Command.command("hello") { state =>
println("Hi!")
state
}
// A simple, multiple-argument command that prints "Hi" followed by the arguments.
// Again, it leaves the current state unchanged.
def helloAll = Command.args("helloAll", "<name>") { (state, args) =>
println("Hi " + args.mkString(" "))
state
}
// A command that demonstrates failing or succeeding based on the input
def failIfTrue = Command.single("failIfTrue") {
case (state, "true") => state.fail
case (state, _) => state
}
// Demonstration of a custom parser.
// The command changes the foreground or background terminal color
// according to the input.
lazy val change = Space ~> (reset | setColor)
lazy val reset = token("reset" ^^^ "\033[0m")
lazy val color = token( Space ~> ("blue" ^^^ "4" | "green" ^^^ "2") )
lazy val select = token( "fg" ^^^ "3" | "bg" ^^^ "4" )
lazy val setColor = (select ~ color) map { case (g, c) => "\033[" + g + c + "m" }
def changeColor = Command("color")(_ => change) { (state, ansicode) =>
print(ansicode)
state
}
// A command that demonstrates getting information out of State.
def printState = Command.command("printState") { state =>
import state._
println(definedCommands.size + " registered commands")
println("commands to run: " + show(remainingCommands))
println()
println("original arguments: " + show(configuration.arguments))
println("base directory: " + configuration.baseDirectory)
println()
println("sbt version: " + configuration.provider.id.version)
println("Scala version (for sbt): " + configuration.provider.scalaProvider.version)
println()
val extracted = Project.extract(state)
import extracted._
println("Current build: " + currentRef.build)
println("Current project: " + currentRef.project)
println("Original setting count: " + session.original.size)
println("Session setting count: " + session.append.size)
state
}
def show[T](s: Seq[T]) =
s.map("'" + _ + "'").mkString("[", ", ", "]")
}