add 'project /' and 'project ..' commands

This commit is contained in:
Mark Harrah 2010-10-30 13:24:23 -04:00
parent 730b613007
commit f462cda1fb
4 changed files with 47 additions and 9 deletions

View File

@ -79,9 +79,18 @@ trait Named
{ {
def name: String def name: String
} }
trait Navigation[Project]
{
def parentProject: Option[Project]
def self: Project
def initialProject(s: State): Project
def projectClosure(s: State): Seq[Project]
def rootProject: Project
}
trait Member[Node <: Member[Node]] trait Member[Node <: Member[Node]]
{ self: Node => {
def projectClosure(state: State): Seq[Node] def navigation: Navigation[Node]
} }
trait Tasked trait Tasked
{ {

View File

@ -53,6 +53,14 @@ ProjectCommand +
""" + ProjectCommand + """ name """ + ProjectCommand + """ name
Changes to the project with the provided name. Changes to the project with the provided name.
This command fails if there is no project with the given name. This command fails if there is no project with the given name.
""" + ProjectCommand + """ /
Changes to the initial project.
""" + ProjectCommand + """ ..
Changes to the parent project of the current project.
If there is no parent project, the current project is unchanged.
Use n+1 dots to change to the nth parent.
For example, 'project ....' is equivalent to three consecutive 'project ..' commands.
""" """
def projectsBrief = (ProjectsCommand, projectsDetailed) def projectsBrief = (ProjectsCommand, projectsDetailed)

View File

@ -199,7 +199,7 @@ object Commands
def projects = Command { case s @ State(d: Member[_]) => def projects = Command { case s @ State(d: Member[_]) =>
Apply.simple(ProjectsCommand, projectsBrief, projectsDetailed ) { (in,s) => Apply.simple(ProjectsCommand, projectsBrief, projectsDetailed ) { (in,s) =>
val log = logger(s) val log = logger(s)
d.projectClosure(s).foreach { case n: Named => listProject(n, d eq n, log); case _ => () } d.navigation.projectClosure(s).foreach { case n: Named => listProject(n, d eq n, log); case _ => () }
s s
}(s) }(s)
} }
@ -212,17 +212,34 @@ object Commands
logger(s).info(d.name) logger(s).info(d.name)
s s
} }
else if(to == "/")
setProject(d.navigation.initialProject(s), s)
else if(to.forall(_ == '.'))
if(to.length > 1) gotoParent(to.length - 1, d, s) else s
else else
{ {
d.projectClosure(s).find { case n: Named => n.name == to; case _ => false } match d.navigation.projectClosure(s).find { case n: Named => n.name == to; case _ => false } match
{ {
case Some(np) => logger(s).info("Set current project to " + to); s.copy(np)() case Some(np) => setProject(np, s)
case None => logger(s).error("Invalid project name '" + to + "' (type 'projects' to list available projects)."); s.fail case None => logger(s).error("Invalid project name '" + to + "' (type 'projects' to list available projects)."); s.fail
} }
} }
}(s) }(s)
} }
@tailrec def gotoParent[Node <: Member[Node]](n: Int, base: Member[Node], s: State): State =
base.navigation.parentProject match
{
case Some(pp) => if(n <= 1) setProject(pp, s) else gotoParent(n-1, pp, s)
case None => if(s.project == base) s else setProject(base, s)
}
def setProject(np: AnyRef, s: State): State =
{
np match { case n: Named =>
logger(s).info("Set current project to " + n.name)
}
s.copy(np)()
}
def exit = Command { case s => Apply( Help(exitBrief) ) { def exit = Command { case s => Apply( Help(exitBrief) ) {
case in if TerminateActions contains in.line => case in if TerminateActions contains in.line =>
runExitHooks(s).exit(true) runExitHooks(s).exit(true)

View File

@ -152,7 +152,12 @@ object MultiContext
val static = (o: Owner, s: String) => context(o).static(o, s) val static = (o: Owner, s: String) => context(o).static(o, s)
} }
} }
final class MultiNavigation(val self: Project, val parentProject: Option[Project]) extends Navigation[Project]
{
def initialProject(s: State): Project = MultiProject.initialProject(s, rootProject)
def projectClosure(s: State): Seq[Project] = MultiProject.topologicalSort(initialProject(s))
@tailrec final lazy val rootProject: Project = parentProject match { case Some(p) => p.navigation.rootProject; case None => self }
}
trait Project extends Tasked with HistoryEnabled with Member[Project] with Named with ConsoleTask with Watched trait Project extends Tasked with HistoryEnabled with Member[Project] with Named with ConsoleTask with Watched
{ {
val info: ProjectInfo val info: ProjectInfo
@ -165,8 +170,7 @@ trait Project extends Tasked with HistoryEnabled with Member[Project] with Named
def historyPath = Some(outputRootPath / ".history") def historyPath = Some(outputRootPath / ".history")
def streamBase = outputRootPath / "streams" def streamBase = outputRootPath / "streams"
def projectClosure(s: State): Seq[Project] = MultiProject.topologicalSort(MultiProject.initialProject(s, rootProject)) def navigation: Navigation[Project] = new MultiNavigation(this, info.parent)
@tailrec final def rootProject: Project = info.parent match { case Some(p) => p.rootProject; case None => this }
implicit def streams = Dummy.Streams implicit def streams = Dummy.Streams
def input = Dummy.In def input = Dummy.In