From 41822495269e346250a2ae98f9f59a753399a474 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 8 May 2017 21:54:58 -0400 Subject: [PATCH] Add InteractionService from sbt-core-next Fixes sbt/sbt#3167 --- .../main/scala/sbt/CommandLineUIService.scala | 24 +++++++++++++++++++ main/src/main/scala/sbt/Defaults.scala | 1 + .../main/scala/sbt/InteractionService.scala | 17 +++++++++++++ main/src/main/scala/sbt/Keys.scala | 1 + 4 files changed, 43 insertions(+) create mode 100644 main/src/main/scala/sbt/CommandLineUIService.scala create mode 100644 main/src/main/scala/sbt/InteractionService.scala diff --git a/main/src/main/scala/sbt/CommandLineUIService.scala b/main/src/main/scala/sbt/CommandLineUIService.scala new file mode 100644 index 000000000..7f04b32c2 --- /dev/null +++ b/main/src/main/scala/sbt/CommandLineUIService.scala @@ -0,0 +1,24 @@ +package sbt + +import sbt.internal.util.SimpleReader + +trait CommandLineUIService extends InteractionService { + override def readLine(prompt: String, mask: Boolean): Option[String] = { + val maskChar = if (mask) Some('*') else None + SimpleReader.readLine(prompt, maskChar) + } + // TODO - Implement this better. + override def confirm(msg: String): Boolean = { + object Assent { + def unapply(in: String): Boolean = { + (in == "y" || in == "yes") + } + } + SimpleReader.readLine(msg + " (yes/no): ", None) match { + case Some(Assent()) => true + case _ => false + } + } +} + +object CommandLineUIService extends CommandLineUIService diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 4c958c62d..1720c2dff 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -258,6 +258,7 @@ object Defaults extends BuildCommon { .map(java.lang.Boolean.parseBoolean) .getOrElse(GCUtil.defaultForceGarbageCollection), minForcegcInterval :== GCUtil.defaultMinForcegcInterval, + interactionService :== CommandLineUIService, serverPort := 5000 + (Hash .toHex(Hash(appConfiguration.value.baseDirectory.toString)) .## % 1000) diff --git a/main/src/main/scala/sbt/InteractionService.scala b/main/src/main/scala/sbt/InteractionService.scala new file mode 100644 index 000000000..59ae3e187 --- /dev/null +++ b/main/src/main/scala/sbt/InteractionService.scala @@ -0,0 +1,17 @@ +package sbt + +/** + * InteractionService provides an abstration over standard input. + * In the future this could be used to ask for inputs from + * other forms of sbt clients such as thin clients and IDEs. + */ +abstract class InteractionService { + + /** Prompts the user for input, optionally with a mask for characters. */ + def readLine(prompt: String, mask: Boolean): Option[String] + + /** Ask the user to confirm something (yes or no) before continuing. */ + def confirm(msg: String): Boolean + + // TODO - Ask for input with autocomplete? +} diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 07ee9da27..24b69956d 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -429,6 +429,7 @@ object Keys { val sbtBinaryVersion = SettingKey[String]("sbt-binary-version", "Defines the binary compatibility version substring.", BPlusSetting) val skip = TaskKey[Boolean]("skip", "For tasks that support it (currently only 'compile' and 'update'), setting skip to true will force the task to not to do its work. This exact semantics may vary by task.", BSetting) val templateResolverInfos = SettingKey[Seq[TemplateResolverInfo]]("templateResolverInfos", "Template resolvers used for 'new'.", BSetting) + val interactionService = TaskKey[InteractionService]("interactionService", "Service used to ask for user input through the current user interface(s).", CTask) // special val sessionVars = AttributeKey[SessionVar.Map]("session-vars", "Bindings that exist for the duration of the session.", Invisible)