diff --git a/main/Command.scala b/main/Command.scala index 3b5567062..cbeeddab4 100644 --- a/main/Command.scala +++ b/main/Command.scala @@ -39,7 +39,7 @@ object Command def apply[T](name: String, briefHelp: (String, String), detail: String)(parser: State => Parser[T])(effect: (State,T) => State): Command = apply(name, Help(name, briefHelp, detail) )(parser)(effect) def apply[T](name: String, help: Help*)(parser: State => Parser[T])(effect: (State,T) => State): Command = - make(name, help : _* )(s => applyEffect(parser(s))(t => effect(s,t)) ) + make(name, help : _* )(applyEffect(parser)(effect) ) def args(name: String, briefHelp: (String, String), detail: String, display: String)(f: (State, Seq[String]) => State): Command = args(name, display, Help(name, briefHelp, detail) )(f) @@ -53,9 +53,12 @@ object Command make(name, help : _*)( state => token(trimmed(any.+.string) map apply1(f, state)) ) def custom(parser: State => Parser[() => State], help: Seq[Help] = Nil): Command = new ArbitraryCommand(parser, help, AttributeMap.empty) + def arb[T](parser: State => Parser[T], help: Help*)(effect: (State, T) => State): Command = custom(applyEffect(parser)(effect), help) def validID(name: String) = DefaultParsers.matches(OpOrID, name) + def applyEffect[T](parser: State => Parser[T])(effect: (State, T) => State): State => Parser[() => State] = + s => applyEffect(parser(s))(t => effect(s,t)) def applyEffect[T](p: Parser[T])(f: T => State): Parser[() => State] = p map { t => () => f(t) } diff --git a/main/Cross.scala b/main/Cross.scala new file mode 100644 index 000000000..6b8655fd9 --- /dev/null +++ b/main/Cross.scala @@ -0,0 +1,50 @@ +/* sbt -- Simple Build Tool + * Copyright 2011 Mark Harrah + */ +package sbt + + import Keys._ + import complete.{DefaultParsers, Parser} + import DefaultParsers._ + + +object Cross +{ + final val Switch = "++" + final val Cross = "+" + + def switchParser(state: State): Parser[(String, String)] = + { + val knownVersions = crossVersions(state) + token(Switch ~ Space) flatMap { _ => token(NotSpace.examples(knownVersions : _*)) ~ (token(Space ~> matched(state.combinedParser)) ?? "") } + } + lazy val switchVersion = Command.arb(requireSession(switchParser)) { case (state, (version, command)) => + val x = Project.extract(state) + import x._ + val add = (scalaVersion := version) :: Nil + val append = Load.transformSettings(Load.projectScope(currentRef), currentRef.build, rootProject, add) + val newStructure = Load.reapply(session.original ++ append, structure) + Project.setProject(session, newStructure, command :: state) + } + + def crossParser(state: State): Parser[String] = + token(Cross ~ Space) flatMap { _ => token(matched(state.combinedParser)) } + + lazy val crossBuild = Command.arb(requireSession(crossParser)) { (state, command) => + val x = Project.extract(state) + import x._ + val versions = crossVersions(state) + val current = scalaVersion in currentRef get structure.data map(Switch + " " + _) toList; + if(versions.isEmpty) command :: state else versions.map(Switch + " " + _ + " " + command) ::: current ::: state + } + def crossVersions(state: State): Seq[String] = + { + val x = Project.extract(state) + import x._ + crossScalaVersions in currentRef get structure.data getOrElse Nil + } + + def requireSession[T](p: State => Parser[T]): State => Parser[T] = s => + if(s get sessionSettings isEmpty) failure("No project loaded") else p(s) + +} \ No newline at end of file diff --git a/main/Defaults.scala b/main/Defaults.scala index f446efdf3..17424d84a 100644 --- a/main/Defaults.scala +++ b/main/Defaults.scala @@ -125,6 +125,7 @@ object Defaults scalacOptions in GlobalScope :== Nil, scalaInstance <<= scalaInstanceSetting, scalaVersion in GlobalScope <<= appConfiguration( _.provider.scalaProvider.version), + crossScalaVersions <<= Seq(scalaVersion).join, target <<= (target, scalaInstance, crossPaths)( (t,si,cross) => if(cross) t / ("scala-" + si.actualVersion) else t ) ) diff --git a/main/Keys.scala b/main/Keys.scala index 84858ca03..2d0fe1b3e 100644 --- a/main/Keys.scala +++ b/main/Keys.scala @@ -76,6 +76,7 @@ object Keys val scalaHome = SettingKey[Option[File]]("scala-home") val scalaInstance = SettingKey[ScalaInstance]("scala-instance") val scalaVersion = SettingKey[String]("scala-version") + val crossScalaVersions = SettingKey[Seq[String]]("cross-scala-versions") val classpathOptions = SettingKey[ClasspathOptions]("classpath-options") val definedSbtPlugins = TaskKey[Set[String]]("defined-sbt-plugins") val sbtPlugin = SettingKey[Boolean]("sbt-plugin") diff --git a/main/Main.scala b/main/Main.scala index 36734d621..a1622f402 100644 --- a/main/Main.scala +++ b/main/Main.scala @@ -4,10 +4,10 @@ package sbt import Execute.NodeView - import complete.HistoryCommands + import complete.{DefaultParsers, HistoryCommands, Parser} import HistoryCommands.{Start => HistoryPrefix} import compiler.EvalImports - import sbt.complete.{DefaultParsers, Parser} + import Command.applyEffect import Keys.{analysis,historyPath,logged,shellPrompt} @@ -59,7 +59,7 @@ class xMain extends xsbti.AppMain import CommandSupport._ object BuiltinCommands { - def DefaultCommands: Seq[Command] = Seq(ignore, help, reboot, read, history, continuous, exit, loadProject, loadProjectImpl, loadFailed, Script.command, + def DefaultCommands: Seq[Command] = Seq(ignore, help, reboot, read, history, continuous, exit, loadProject, loadProjectImpl, loadFailed, Script.command, Cross.crossBuild, Cross.switchVersion, projects, project, setOnFailure, clearOnFailure, ifLast, multi, shell, set, inspect, eval, alias, append, last, lastGrep, nop, sessionCommand, act) def DefaultBootCommands: Seq[String] = LoadProject :: (IfLast + " " + Shell) :: Nil