Use standard {build}/id syntax for 'project' command

This commit is contained in:
Mark Harrah 2011-05-07 22:02:06 -04:00
parent 40c6ca3b3d
commit 9dc9ccd0d3
3 changed files with 25 additions and 34 deletions

View File

@ -118,21 +118,22 @@ object Act
def projectRef(index: KeyIndex, currentBuild: URI): Parser[Option[ResolvedReference]] = def projectRef(index: KeyIndex, currentBuild: URI): Parser[Option[ResolvedReference]] =
{ {
def some[T](p: Parser[T]): Parser[Option[T]] = p map { v => Some(v) } val global = token(GlobalString <~ '/') ^^^ None
def projectID(uri: URI) = token( examplesStrict(ID, index projects uri, "project ID") <~ '/' ) global | some(resolvedReference(index, currentBuild, '/'))
}
def resolvedReference(index: KeyIndex, currentBuild: URI, trailing: Parser[_]): Parser[ResolvedReference] =
{
def projectID(uri: URI) = token( examplesStrict(ID, index projects uri, "project ID") <~ trailing )
def projectRef(uri: URI) = projectID(uri) map { id => ProjectRef(uri, id) } def projectRef(uri: URI) = projectID(uri) map { id => ProjectRef(uri, id) }
val uris = index.buildURIs val uris = index.buildURIs
val resolvedURI = Uri(uris).map(uri => Scope.resolveBuild(currentBuild, uri)) val resolvedURI = Uri(uris).map(uri => Scope.resolveBuild(currentBuild, uri))
val buildRef = token( '{' ~> resolvedURI <~ '}' ).? val buildRef = token( '{' ~> resolvedURI <~ '}' ).?
val global = token(GlobalString <~ '/') ^^^ None
val resolvedRef = buildRef flatMap { buildRef flatMap {
case None => projectRef(currentBuild) case None => projectRef(currentBuild)
case Some(uri) => projectRef(uri) | ( token('/') ^^^ BuildRef(uri) ) case Some(uri) => projectRef(uri) | token(trailing ~> success(BuildRef(uri)))
} }
some(resolvedRef) | global
} }
def optProjectRef(index: KeyIndex, current: ProjectRef): Parser[Option[ResolvedReference]] = def optProjectRef(index: KeyIndex, current: ProjectRef): Parser[Option[ResolvedReference]] =
projectRef(index, current.build) ?? Some(current) projectRef(index, current.build) ?? Some(current)

View File

@ -13,12 +13,6 @@ package sbt
object ProjectNavigation object ProjectNavigation
{ {
sealed trait Navigate
final object ShowCurrent extends Navigate
final object Root extends Navigate
final class ChangeBuild(val base: URI) extends Navigate
final class ChangeProject(val id: String) extends Navigate
def command(s: State): Parser[() => State] = def command(s: State): Parser[() => State] =
if(s get sessionSettings isEmpty) failure("No project loaded") else (new ProjectNavigation(s)).command if(s get sessionSettings isEmpty) failure("No project loaded") else (new ProjectNavigation(s)).command
} }
@ -26,44 +20,38 @@ final class ProjectNavigation(s: State)
{ {
val extracted = Project extract s val extracted = Project extract s
import extracted.{currentRef, structure, session} import extracted.{currentRef, structure, session}
import currentRef.{build => uri, project => pid}
val builds = structure.units.keys.toSet
val projects = Load.getBuild(structure.units, uri).defined.keys
def setProject(nuri: URI, nid: String) = def setProject(nuri: URI, nid: String) =
{ {
val neval = if(uri == nuri) session.currentEval else mkEval(nuri) val neval = if(currentRef.build == nuri) session.currentEval else mkEval(nuri)
updateCurrent(s.put(sessionSettings, session.setCurrent(nuri, nid, neval))) updateCurrent(s.put(sessionSettings, session.setCurrent(nuri, nid, neval)))
} }
def mkEval(nuri: URI) = Load.lazyEval(structure.units(nuri).unit) def mkEval(nuri: URI) = Load.lazyEval(structure.units(nuri).unit)
def getRoot(uri: URI) = Load.getRootProject(structure.units)(uri) def getRoot(uri: URI) = Load.getRootProject(structure.units)(uri)
def apply(action: Navigate): State = def apply(action: Option[ResolvedReference]): State =
action match action match
{ {
case ShowCurrent => show(); s case None => show(); s
case Root => setProject(uri, getRoot(uri)) case Some(BuildRef(uri)) => changeBuild(uri)
case b: ChangeBuild => changeBuild(b.base) case Some(ProjectRef(uri, id)) => selectProject(uri, id)
/* else if(to.forall(_ == '.')) /* else if(to.forall(_ == '.'))
if(to.length > 1) gotoParent(to.length - 1, nav, s) else s */ // semantics currently undefined if(to.length > 1) gotoParent(to.length - 1, nav, s) else s */ // semantics currently undefined
case s: ChangeProject => selectProject(s.id)
} }
def show(): Unit = logger(s).info(pid + " (in build " + uri + ")") def show(): Unit = logger(s).info(currentRef.project + " (in build " + currentRef.build + ")")
def selectProject(to: String): State = def selectProject(uri: URI, to: String): State =
if( structure.units(uri).defined.contains(to) ) if( structure.units(uri).defined.contains(to) )
setProject(uri, to) setProject(uri, to)
else else
fail("Invalid project name '" + to + "' (type 'projects' to list available projects).") fail("Invalid project name '" + to + "' in build " + uri + " (type 'projects' to list available projects).")
def changeBuild(to: URI): State = def changeBuild(newBuild: URI): State =
{
val newBuild = (uri resolve to).normalize
if(structure.units contains newBuild) if(structure.units contains newBuild)
setProject(newBuild, getRoot(newBuild)) setProject(newBuild, getRoot(newBuild))
else else
fail("Invalid build unit '" + newBuild + "' (type 'projects' to list available builds).") fail("Invalid build unit '" + newBuild + "' (type 'projects' to list available builds).")
}
def fail(msg: String): State = def fail(msg: String): State =
{ {
logger(s).error(msg) logger(s).error(msg)
@ -73,11 +61,12 @@ final class ProjectNavigation(s: State)
import complete.Parser._ import complete.Parser._
import complete.Parsers._ import complete.Parsers._
val parser: Parser[Navigate] = val parser: Parser[Option[ResolvedReference]] =
{ {
val buildP = token('^') ~> token(Uri(builds) map(u => new ChangeBuild(u) ) ) val reference = Act.resolvedReference(structure.index.keyIndex, currentRef.build, success(()))
val projectP = token(ID map (id => new ChangeProject(id)) examples projects.toSet ) val root = token('/' ^^^ rootRef)
success(ShowCurrent) | ( token(Space) ~> (token('/' ^^^ Root) | buildP | projectP) ) success(None) | some( token(Space) ~> (root | reference) )
} }
def rootRef = ProjectRef(currentRef.build, getRoot(currentRef.build))
val command: Parser[() => State] = Command.applyEffect(parser)(apply) val command: Parser[() => State] = Command.applyEffect(parser)(apply)
} }

View File

@ -35,7 +35,7 @@ trait Parsers
lazy val OptSpace = SpaceClass.*.examples(" ") lazy val OptSpace = SpaceClass.*.examples(" ")
lazy val URIClass = URIChar.+.string !!! "Invalid URI" lazy val URIClass = URIChar.+.string !!! "Invalid URI"
lazy val URIChar = charClass(alphanum) | chars("_-!.~'()*,;:$&+=?/[]@%") lazy val URIChar = charClass(alphanum) | chars("_-!.~'()*,;:$&+=?/[]@%#")
def alphanum(c: Char) = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') def alphanum(c: Char) = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9')
// TODO: implement // TODO: implement
@ -52,6 +52,7 @@ trait Parsers
def rep1sep[T](rep: Parser[T], sep: Parser[_]): Parser[Seq[T]] = def rep1sep[T](rep: Parser[T], sep: Parser[_]): Parser[Seq[T]] =
(rep ~ (sep ~> rep).*).map { case (x ~ xs) => x +: xs } (rep ~ (sep ~> rep).*).map { case (x ~ xs) => x +: xs }
def some[T](p: Parser[T]): Parser[Option[T]] = p map { v => Some(v) }
def mapOrFail[S,T](p: Parser[S])(f: S => T): Parser[T] = def mapOrFail[S,T](p: Parser[S])(f: S => T): Parser[T] =
p flatMap { s => try { success(f(s)) } catch { case e: Exception => failure(e.toString) } } p flatMap { s => try { success(f(s)) } catch { case e: Exception => failure(e.toString) } }