From de6f55952f3b2ca03bf50318ca223b2305b64b8b Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Fri, 16 Sep 2011 22:04:51 -0400 Subject: [PATCH] allow watching and triggered messages to be customized --- main/Defaults.scala | 6 +++++- main/Keys.scala | 2 ++ main/Watched.scala | 19 +++++++++++++++++-- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/main/Defaults.scala b/main/Defaults.scala index 8c0919979..a83f49f4b 100644 --- a/main/Defaults.scala +++ b/main/Defaults.scala @@ -56,6 +56,8 @@ object Defaults extends BuildCommon autoScalaLibrary :== true, onLoad <<= onLoad ?? idFun[State], onUnload <<= onUnload ?? idFun[State], + watchingMessage <<= watchingMessage ?? Watched.defaultWatchingMessage, + triggeredMessage <<= triggeredMessage ?? Watched.defaultTriggeredMessage, definesClass :== FileValueCache(Locate.definesClass _ ).get, trapExit :== false, trapExit in run :== true, @@ -224,11 +226,13 @@ object Defaults extends BuildCommon def watchTransitiveSourcesTask: Initialize[Task[Seq[File]]] = inDependencies[Task[Seq[File]]](watchSources.task, const(std.TaskExtra.constant(Nil)), includeRoot = true) apply { _.join.map(_.flatten) } - def watchSetting: Initialize[Watched] = (pollInterval, thisProjectRef) { (interval, base) => + def watchSetting: Initialize[Watched] = (pollInterval, thisProjectRef, watchingMessage, triggeredMessage) { (interval, base, msg, trigMsg) => new Watched { val scoped = watchTransitiveSources in base val key = ScopedKey(scoped.scope, scoped.key) override def pollInterval = interval + override def watchingMessage(s: WatchState) = msg(s) + override def triggeredMessage(s: WatchState) = trigMsg(s) override def watchPaths(s: State) = EvaluateTask.evaluateTask(Project structure s, key, s, base) match { case Some(Value(ps)) => ps case Some(Inc(i)) => throw i diff --git a/main/Keys.scala b/main/Keys.scala index 823cf86d1..86cb3b7a3 100644 --- a/main/Keys.scala +++ b/main/Keys.scala @@ -61,6 +61,8 @@ object Keys val pollInterval = SettingKey[Int]("poll-interval", "Interval between checks for modified sources by the continuous execution command.") val watchSources = TaskKey[Seq[File]]("watch-sources", "Defines the sources in this project for continuous execution to watch for changes.") val watchTransitiveSources = TaskKey[Seq[File]]("watch-transitive-sources", "Defines the sources in all projects for continuous execution to watch.") + val watchingMessage = SettingKey[WatchState => String]("watching-message", "The message to show when triggered execution waits for sources to change.") + val triggeredMessage = SettingKey[WatchState => String]("triggered-message", "The message to show before triggered execution executes an action after sources change.") // Path Keys val baseDirectory = SettingKey[File]("base-directory", "The base directory. Depending on the scope, this is the base directory for the build, project, configuration, or task.") diff --git a/main/Watched.scala b/main/Watched.scala index e3570eafe..da595d912 100644 --- a/main/Watched.scala +++ b/main/Watched.scala @@ -6,6 +6,7 @@ package sbt import CommandSupport.{ClearOnFailure,FailureWall} import annotation.tailrec import java.io.File + import Types.const trait Watched { @@ -15,10 +16,19 @@ trait Watched /** The time in milliseconds between checking for changes. The actual time between the last change made to a file and the * execution time is between `pollInterval` and `pollInterval*2`.*/ def pollInterval: Int = Watched.PollDelayMillis + /** The message to show when triggered execution waits for sources to change.*/ + def watchingMessage(s: WatchState): String = Watched.defaultWatchingMessage(s) + /** The message to show before an action is run. */ + def triggeredMessage(s: WatchState): String = Watched.defaultTriggeredMessage(s) } object Watched { + val defaultWatchingMessage: WatchState => String = _.count + ". Waiting for source changes... (press enter to interrupt)" + val defaultTriggeredMessage: WatchState => String = const("") + val clearWhenTriggered: WatchState => String = const(clearScreen) + def clearScreen: String = "\033[2J\033[0;0H" + private[this] class AWatched extends Watched def multi(base: Watched, paths: Seq[Watched]): Watched = @@ -27,11 +37,14 @@ object Watched override def watchPaths(s: State) = (base.watchPaths(s) /: paths)(_ ++ _.watchPaths(s)) override def terminateWatch(key: Int): Boolean = base.terminateWatch(key) override val pollInterval = (base +: paths).map(_.pollInterval).min + override def watchingMessage(s: WatchState) = base.watchingMessage(s) + override def triggeredMessage(s: WatchState) = base.triggeredMessage(s) } def empty: Watched = new AWatched val PollDelayMillis = 500 def isEnter(key: Int): Boolean = key == 10 || key == 13 + def printIfDefined(msg: String) = if(!msg.isEmpty) System.out.println(msg) def executeContinuously(watched: Watched, s: State, next: String, repeat: String): State = { @@ -40,7 +53,7 @@ object Watched val watchState = s get ContinuousState getOrElse WatchState.empty if(watchState.count > 0) - System.out.println(watchState.count + ". Waiting for source changes... (press enter to interrupt)") + printIfDefined(watched watchingMessage watchState) val (triggered, newWatchState, newState) = try { @@ -54,8 +67,10 @@ object Watched (false, watchState, s.fail) } - if(triggered) + if(triggered) { + printIfDefined(watched triggeredMessage newWatchState) (ClearOnFailure :: next :: FailureWall :: repeat :: s).put(ContinuousState, newWatchState) + } else { while (System.in.available() > 0) System.in.read()