diff --git a/main/Command.scala b/main/Command.scala index 39b193e88..b06909eab 100644 --- a/main/Command.scala +++ b/main/Command.scala @@ -32,30 +32,32 @@ object Command val HistoryPath = SettingKey[Option[File]]("history") val Analysis = AttributeKey[inc.Analysis]("analysis") val Watch = SettingKey[Watched]("continuous-watch") - val Sample = SettingKey[String]("sample-setting") - val SampleTask = TaskKey[String]("sample-task") - val SampleInput = InputKey[String]("sample-input-task") def command(name: String)(f: State => State): Command = command(name, Nil)(f) def command(name: String, briefHelp: String, detail: String)(f: State => State): Command = command(name, Help(name, (name, briefHelp), detail) :: Nil)(f) - def command(name: String, help: Seq[Help])(f: State => State): Command = apply(name, help : _*)(state => success(() => f(state))) + def command(name: String, help: Seq[Help])(f: State => State): Command = make(name, help : _*)(state => success(() => f(state))) - def apply(name: String, briefHelp: (String, String), detail: String)(parser: State => Parser[() => State]): Command = - apply(name, Help(name, briefHelp, detail) )(parser) - def apply(name: String, help: Help*)(parser: State => Parser[() => State]): Command = new SimpleCommand(name, help, parser, AttributeMap.empty) + def make(name: String, briefHelp: (String, String), detail: String)(parser: State => Parser[() => State]): Command = + make(name, Help(name, briefHelp, detail) )(parser) + def make(name: String, help: Help*)(parser: State => Parser[() => State]): Command = new SimpleCommand(name, help, parser, AttributeMap.empty) + + 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)) ) 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) def args(name: String, display: String, help: Help*)(f: (State, Seq[String]) => State): Command = - apply(name, help : _*)( state => spaceDelimited(display) map apply1(f, state) ) + make(name, help : _*)( state => spaceDelimited(display) map apply1(f, state) ) def single(name: String, briefHelp: (String, String), detail: String)(f: (State, String) => State): Command = single(name, Help(name, briefHelp, detail) )(f) def single(name: String, help: Help*)(f: (State, String) => State): Command = - apply(name, help : _*)( state => token(trimmed(any.+.string) map apply1(f, state)) ) + make(name, help : _*)( state => token(trimmed(any.+.string) map apply1(f, state)) ) - def custom(parser: State => Parser[() => State], help: Seq[Help]): Command = new ArbitraryCommand(parser, help, AttributeMap.empty) + def custom(parser: State => Parser[() => State], help: Seq[Help] = Nil): Command = new ArbitraryCommand(parser, help, AttributeMap.empty) def validID(name: String) = Parser(OpOrID)(name).resultEmpty.isDefined diff --git a/main/Default.scala b/main/Default.scala index 27cf1aaee..c390fc24b 100755 --- a/main/Default.scala +++ b/main/Default.scala @@ -187,6 +187,7 @@ object Default Name :== "test", Version :== "0.1", MaxErrors :== 100, + Project.Commands :== Nil, Data <<= EvaluateTask.state map { state => Project.structure(state).data } ) def paths = Seq( diff --git a/main/Main.scala b/main/Main.scala index 516aa529a..f8c3fcaef 100644 --- a/main/Main.scala +++ b/main/Main.scala @@ -24,7 +24,7 @@ class xMain extends xsbti.AppMain { final def run(configuration: xsbti.AppConfiguration): xsbti.MainResult = { - import Commands.{initialize, defaults} + import BuiltinCommands.{initialize, defaults} import CommandSupport.{DefaultsCommand, InitCommand} val initialCommandDefs = Seq(initialize, defaults) val commands = DefaultsCommand :: InitCommand :: configuration.arguments.map(_.trim).toList @@ -50,24 +50,24 @@ class xMain extends xsbti.AppMain ErrorHandling.wideConvert { state.process(Command.process) } match { case Right(s) => s - case Left(t) => Commands.handleException(t, state) + case Left(t) => BuiltinCommands.handleException(t, state) } } import DefaultParsers._ import CommandSupport._ -object Commands +object BuiltinCommands { def DefaultCommands: Seq[Command] = Seq(ignore, help, reload, read, history, continuous, exit, loadCommands, loadProject, compile, discover, projects, project, setOnFailure, ifLast, multi, shell, set, get, eval, delegates,alias, append, nop, sessionCommand, act) - def nop = Command.custom(s => success(() => s), Nil) + def nop = Command.custom(s => success(() => s)) def ignore = Command.command(FailureWall)(identity) def detail(selected: Iterable[String])(h: Help): Option[String] = h.detail match { case (commands, value) => if( selected exists commands ) Some(value) else None } - def help = Command(HelpCommand, helpBrief, helpDetailed)(helpParser) + def help = Command.make(HelpCommand, helpBrief, helpDetailed)(helpParser) def helpParser(s: State) = { @@ -88,7 +88,7 @@ object Commands s } - def alias = Command(AliasCommand, AliasBrief, AliasDetailed) { s => + def alias = Command.make(AliasCommand, AliasBrief, AliasDetailed) { s => val name = token(OpOrID.examples( aliasNames(s) : _*) ) val assign = token(Space ~ '=' ~ OptSpace) val sfree = removeAliases(s) @@ -155,7 +155,7 @@ object Commands portAndSuccess || files } - def read = Command(ReadCommand, ReadBrief, ReadDetailed)(s => applyEffect(readParser(s))(doRead(s)) ) + def read = Command.make(ReadCommand, ReadBrief, ReadDetailed)(s => applyEffect(readParser(s))(doRead(s)) ) def doRead(s: State)(arg: Either[Int, Seq[File]]): State = arg match @@ -201,7 +201,7 @@ object Commands def history = Command.command("!!")(s => s) //TODO: convert - /*def history = Command( historyHelp: _* ) { case (in, s) if in.line startsWith "!" => + /*def history = Command.make( historyHelp: _* ) { case (in, s) if in.line startsWith "!" => val logError = (msg: String) => CommandSupport.logger(s).error(msg) HistoryCommands(in.line.substring(HistoryPrefix.length).trim, (s get HistoryPath.key) getOrElse None, 500/*JLine.MaxHistorySize*/, logError) match { @@ -220,7 +220,7 @@ object Commands log.info("ans: " + result.tpe + " = " + result.value.toString) s } - def sessionCommand = Command(SessionCommand, sessionBrief, SessionSettings.Help)(SessionSettings.command) + def sessionCommand = Command.make(SessionCommand, sessionBrief, SessionSettings.Help)(SessionSettings.command) def reapply(newSession: SessionSettings, structure: Load.BuildStructure, s: State): State = { logger(s).info("Reapplying settings...") @@ -268,7 +268,7 @@ object Commands for(id <- build.defined.keys) log.info("\t" + prefix(id) + id) } - def act = Command.custom(Act.actParser, Nil) + def act = Command.custom(Act.actParser) def projects = Command.command(ProjectsCommand, projectsBrief, projectsDetailed ) { s => val extracted = Project extract s @@ -284,7 +284,7 @@ object Commands case Some(nav) => f(nav) } - def project = Command(ProjectCommand, projectBrief, projectDetailed)(ProjectNavigation.command) + def project = Command.make(ProjectCommand, projectBrief, projectDetailed)(ProjectNavigation.command) def exit = Command.command(TerminateAction, Help(exitBrief) :: Nil ) ( doExit ) @@ -381,9 +381,12 @@ object Commands s.fail } - def removeAliases(s: State): State = s.copy(processors = removeAliases(s.processors)) - def removeAliases(as: Seq[Command]): Seq[Command] = as.filter(c => ! (c.tags contains CommandAliasKey)) + def removeAliases(s: State): State = removeTagged(s, CommandAliasKey) def removeAlias(s: State, name: String): State = s.copy(processors = s.processors.filter(c => !isAliasNamed(name, c)) ) + + def removeTagged(s: State, tag: AttributeKey[_]): State = s.copy(processors = removeTagged(s.processors, tag)) + def removeTagged(as: Seq[Command], tag: AttributeKey[_]): Seq[Command] = as.filter(c => ! (c.tags contains tag)) + def isAliasNamed(name: String, c: Command): Boolean = isNamed(name, getAlias(c)) def isNamed(name: String, alias: Option[(String,String)]): Boolean = alias match { case None => false; case Some((n,_)) => name == n } @@ -400,7 +403,7 @@ object Commands s.processors.flatMap(c => getAlias(c).filter(tupled(pred))) def newAlias(name: String, value: String): Command = - Command(name, (name, "'" + value + "'"), "Alias of '" + value + "'")(aliasBody(name, value)).tag(CommandAliasKey, (name, value)) + Command.make(name, (name, "'" + value + "'"), "Alias of '" + value + "'")(aliasBody(name, value)).tag(CommandAliasKey, (name, value)) def aliasBody(name: String, value: String)(state: State): Parser[() => State] = Parser(Command.combine(state.processors)(state))(value) diff --git a/main/Project.scala b/main/Project.scala index 98a03ae37..4474709ee 100644 --- a/main/Project.scala +++ b/main/Project.scala @@ -72,8 +72,10 @@ object Project extends Init[Scope] val data = structure.data val historyPath = HistoryPath in ref get data flatMap identity + val commands = (Commands in ref get data).toList.flatten[Command].map(_ tag (ProjectCommand, true)) + val newProcessors = commands ++ BuiltinCommands.removeTagged(s.processors, ProjectCommand) val newAttrs = s.attributes.put(Watch.key, makeWatched(data, ref, project)).put(HistoryPath.key, historyPath) - s.copy(attributes = newAttrs) + s.copy(attributes = newAttrs, processors = newProcessors) } def makeSettings(settings: Seq[Setting[_]], delegates: Scope => Seq[Scope], scopeLocal: ScopedKey[_] => Seq[Setting[_]]) = translateUninitialized( make(settings)(delegates, scopeLocal) ) @@ -133,12 +135,14 @@ object Project extends Init[Scope] def reverseDependencies(cMap: CompiledMap, scoped: ScopedKey[_]): Iterable[ScopedKey[_]] = for( (key,compiled) <- cMap; dep <- compiled.dependencies if dep == scoped) yield key + val ProjectCommand = AttributeKey[Boolean]("project-command") val SessionKey = AttributeKey[SessionSettings]("session-settings") val StructureKey = AttributeKey[Load.BuildStructure]("build-structure") val AppConfig = SettingKey[xsbti.AppConfiguration]("app-configuration") val ThisProject = SettingKey[Project]("project") val ThisProjectRef = SettingKey[ProjectRef]("project-ref") val Config = SettingKey[Configuration]("configuration") + val Commands = SettingKey[Seq[Command]]("commands") } import SessionSettings._ @@ -166,7 +170,7 @@ object SessionSettings type SessionMap = Map[(URI, String), Seq[SessionSetting]] def reapply(session: SessionSettings, s: State): State = - Commands.reapply(session, Project.structure(s), s) + BuiltinCommands.reapply(session, Project.structure(s), s) def clearSettings(s: State): State = withSettings(s)(session => reapply(session.copy(append = session.append - session.current), s))