reintegrate history commands, add proper parsing for recursive commands

This commit is contained in:
Mark Harrah 2011-03-11 16:52:44 -05:00
parent b996a95157
commit c0c287d50e
4 changed files with 58 additions and 82 deletions

View File

@ -120,22 +120,23 @@ object BuiltinCommands
}
}
// TODO: this should nest Parsers for other commands
def multi = Command.single(Multi, MultiBrief, MultiDetailed) { (s,arg) =>
arg.split(";").toSeq ::: s
}
def multiParser(s: State): Parser[Seq[String]] =
( token(';' ~> OptSpace) flatMap { _ => token(matched(s.combinedParser) <~ OptSpace ) } ).+
def multiApplied(s: State) =
Command.applyEffect( multiParser(s) )( _ ::: s )
def multi = Command.custom(multiApplied, Help(MultiBrief, (Set(Multi), MultiDetailed)) :: Nil )
// TODO: nest
def ifLast = Command.single(IfLast, IfLastBrief, IfLastDetailed) { (s, arg) =>
lazy val otherCommandParser = (s: State) => token(OptSpace ~> matched(s.combinedParser) )
def ifLast = Command(IfLast, IfLastBrief, IfLastDetailed)(otherCommandParser) { (s, arg) =>
if(s.commands.isEmpty) arg :: s else s
}
// TODO: nest
def append = Command.single(Append, AppendLastBrief, AppendLastDetailed) { (s, arg) =>
def append = Command(Append, AppendLastBrief, AppendLastDetailed)(otherCommandParser) { (s, arg) =>
s.copy(commands = s.commands :+ arg)
}
// TODO: nest
def setOnFailure = Command.single(OnFailure, OnFailureBrief, OnFailureDetailed) { (s, arg) =>
def setOnFailure = Command(OnFailure, OnFailureBrief, OnFailureDetailed)(otherCommandParser) { (s, arg) =>
s.copy(onFailure = Some(arg))
}
def clearOnFailure = Command.command(ClearOnFailure)(s => s.copy(onFailure = None))
@ -195,27 +196,28 @@ object BuiltinCommands
}
}
// TODO: nest
def continuous =
Command.single(ContinuousExecutePrefix, Help(continuousBriefHelp) ) { (s, arg) =>
Command(ContinuousExecutePrefix, Help(continuousBriefHelp) )(otherCommandParser) { (s, arg) =>
withAttribute(s, Watched.Configuration, "Continuous execution not configured.") { w =>
val repeat = ContinuousExecutePrefix + (if(arg.startsWith(" ")) arg else " " + arg)
Watched.executeContinuously(w, s, arg, repeat)
}
}
def history = Command.command("!!")(s => s)
//TODO: convert
/*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
{
case Some(commands) =>
commands.foreach(println) //printing is more appropriate than logging
(commands ::: s).continue
case None => s.fail
def history = Command.custom(historyParser, historyHelp)
def historyParser(s: State): Parser[() => State] =
Command.applyEffect(HistoryCommands.actionParser) { histFun =>
val logError = (msg: String) => CommandSupport.logger(s).error(msg)
val hp = s get historyPath.key getOrElse None
val lines = hp.toList.flatMap( p => IO.readLines(p) ).toIndexedSeq
histFun( complete.History(lines, hp, logError) ) match
{
case Some(commands) =>
commands foreach println //printing is more appropriate than logging
(commands ::: s).continue
case None => s.fail
}
}
}*/
def eval = Command.single(EvalCommand, evalBrief, evalDetailed) { (s, arg) =>
val log = logger(s)

View File

@ -4,9 +4,10 @@
package sbt
package complete
import History.number
import History.number
import java.io.File
final class History private(lines: IndexedSeq[String], error: String => Unit) extends NotNull
final class History private(val lines: IndexedSeq[String], val path: Option[File], error: String => Unit) extends NotNull
{
private def reversed = lines.reverse
@ -41,7 +42,7 @@ final class History private(lines: IndexedSeq[String], error: String => Unit) ex
object History
{
def apply(lines: Seq[String], error: String => Unit): History = new History(lines.toIndexedSeq, error)
def apply(lines: Seq[String], path: Option[File], error: String => Unit): History = new History(lines.toIndexedSeq, path, error)
def number(s: String): Option[Int] =
try { Some(s.toInt) }

View File

@ -39,63 +39,34 @@ object HistoryCommands
def helpString = "History commands:\n " + (descriptions.map{ case (c,d) => c + " " + d}).mkString("\n ")
def printHelp(): Unit =
println(helpString)
def printHistory(history: complete.History, historySize: Int, show: Int): Unit =
history.list(historySize, show).foreach(println)
def apply(s: String, historyPath: Option[File], maxLines: Int, error: String => Unit): Option[List[String]] =
if(s.isEmpty)
{
printHelp()
Some(Nil)
}
else
{
val lines = historyPath.toList.flatMap( p => IO.readLines(p) ).toArray
if(lines.isEmpty)
{
error("No history")
None
}
else
{
val history = complete.History(lines, error)
if(s.startsWith(ListCommands))
{
val rest = s.substring(ListCommands.length)
val show = complete.History.number(rest).getOrElse(lines.length)
printHistory(history, maxLines, show)
Some(Nil)
}
else
{
val command = historyCommand(history, s)
command.foreach(lines(lines.length - 1) = _)
historyPath foreach { h => IO.writeLines(h, lines) }
Some(command.toList)
}
}
}
def printHistory(history: complete.History, historySize: Int, show: Int): Unit = history.list(historySize, show).foreach(println)
def historyCommand(history: complete.History, s: String): Option[String] =
{
if(s == Last)
history !!
else if(s.startsWith(Contains))
history !? s.substring(Contains.length)
else
history ! s
import DefaultParsers._
val MaxLines = 500
lazy val num = token(NatBasic, "<integer>")
lazy val last = Last ^^^ { execute(_ !!) }
lazy val list = ListCommands ~> (num ?? Int.MaxValue) map { show =>
(h: History) => { printHistory(h, MaxLines, show); Some(Nil) }
}
/*
import parse.{Parser,Parsers}
import Parser._
import Parsers._
val historyParser: Parser[complete.History => Option[String]] =
{
Start ~> Specific)
lazy val execStr = flag('?') ~ token(any.+.string, "<string>") map { case (contains, str) =>
execute(h => if(contains) h !? str else h ! str)
}
!! Execute the last command again
!: Show all previous commands
!:n Show the last n commands
!n Execute the command with index n, as shown by the !: command
!-n Execute the nth command before this one
!string Execute the most recent command starting with 'string'
!?string*/
lazy val execInt = flag('-') ~ num map { case (neg, value) =>
execute(h => if(neg) h !- value else h ! value)
}
lazy val help = success( (h: History) => { printHelp(); Some(Nil) } )
def execute(f: History => Option[String]): History => Option[List[String]] = (h: History) =>
{
val command = f(h)
val lines = h.lines.toArray
command.foreach(lines(lines.length - 1) = _)
h.path foreach { h => IO.writeLines(h, lines) }
Some(command.toList)
}
val actionParser: Parser[complete.History => Option[List[String]]] =
Start ~> (help | last | execInt | list | execStr ) // execStr must come last
}

View File

@ -52,6 +52,8 @@ trait Parsers
def spaceDelimited(display: String): Parser[Seq[String]] = (token(Space) ~> token(NotSpace, display)).* <~ SpaceClass.*
def flag[T](p: Parser[T]): Parser[Boolean] = (p ^^^ true) ?? false
def trimmed(p: Parser[String]) = p map { _.trim }
def Uri(ex: Set[URI]) = mapOrFail(URIClass)( uri => new URI(uri)) examples(ex.map(_.toString))
}