searchable help

This commit is contained in:
Mark Harrah 2012-03-12 19:54:18 -04:00
parent eef3a1ed31
commit 4e4937e706
4 changed files with 73 additions and 28 deletions

View File

@ -9,24 +9,11 @@ package sbt
import Project.ScopedKey
import Aggregation.{KeyValue, Values}
import Types.idFun
import Highlight.{bold, showMatches}
import annotation.tailrec
import scala.Console.{BOLD, RESET}
object Output
{
def showMatches(pattern: Pattern)(line: String): Option[String] =
{
val matcher = pattern.matcher(line)
if(ConsoleLogger.formatEnabled)
{
val highlighted = matcher.replaceAll(scala.Console.RED + "$0" + scala.Console.RESET)
if(highlighted == line) None else Some(highlighted)
}
else if(matcher.find)
Some(line)
else
None
}
final val DefaultTail = "> "
def last(keys: Values[_], streams: Streams, printLines: Seq[String] => Unit)(implicit display: Show[ScopedKey[_]]): Unit =
@ -54,7 +41,6 @@ object Output
if(!single) bold(display(key)) +: flines else flines
}
}
def bold(s: String) = if(ConsoleLogger.formatEnabled) BOLD + s + RESET else s
def lastLines(keys: Values[_], streams: Streams): Values[Seq[String]] =
{

View File

@ -18,10 +18,19 @@ object BasicCommandStrings
/** The command name to terminate the program.*/
val TerminateAction: String = Exit
def helpBrief = (HelpCommand + " [command]*", "Displays this help message or prints detailed help on requested commands.")
def helpDetailed = """
If an argument is provided, this prints detailed help for that command.
Otherwise, this prints a help summary."""
def helpBrief = (HelpCommand + " [command]", "Displays this help message or prints detailed help on requested commands.")
def helpDetailed = HelpCommand + """
Prints a help summary.
""" + HelpCommand + """ <command>
Prints detailed help for command <command>.
""" + HelpCommand + """ <regular expression>
Searches the help according to the provided regular expression.
"""
def historyHelp = Help.briefDetail(HistoryCommands.descriptions)

View File

@ -12,6 +12,7 @@ package sbt
import BasicKeys._
import java.io.File
import java.util.regex.Pattern
object BasicCommands
{
@ -26,22 +27,46 @@ object BasicCommands
{
val h = (Help.empty /: s.definedCommands)(_ ++ _.help(s))
val helpCommands = h.detail.keySet
val args = (token(Space) ~> token( NotSpace examples helpCommands )).*
applyEffect(args)(runHelp(s, h))
val arg = (NotSpaceClass ~ any.*) map { case (ns, s) => (ns +: s).mkString }
val spacedArg = token(Space) ~> token( arg examples helpCommands ).?
applyEffect(spacedArg)(runHelp(s, h))
}
def runHelp(s: State, h: Help)(args: Seq[String]): State =
def runHelp(s: State, h: Help)(arg: Option[String]): State =
{
val message =
if(args.isEmpty)
val message = arg match {
case None =>
aligned(" ", " ", h.brief).mkString("\n", "\n", "\n")
else
detail(args, h.detail) mkString("\n", "\n\n", "\n")
case Some(x) =>
detail(x, h.detail)
}
System.out.println(message)
s
}
def detail(selected: Seq[String], detailMap: Map[String, String]): Seq[String] =
selected.distinct flatMap { detailMap get _ }
def detail(selected: String, detailMap: Map[String, String]): String =
detailMap.get(selected) match
{
case Some(exactDetail) =>exactDetail
case None => layoutDetails(searchHelp(selected, detailMap))
}
def searchHelp(selected: String, detailMap: Map[String, String]): Map[String, String] =
{
val pattern = Pattern.compile(selected, HelpPatternFlags)
detailMap flatMap { case (k,v) =>
val contentMatches = Highlight.showMatches(pattern)(v)
val keyMatches = Highlight.showMatches(pattern)(k)
val keyString = Highlight.bold(keyMatches getOrElse k)
val contentString = contentMatches getOrElse v
if(keyMatches.isDefined || contentMatches.isDefined)
(keyString, contentString) :: Nil
else
Nil
}
}
def layoutDetails(details: Map[String,String]): String =
details.map { case (k,v) => k + ":\n\n " + v } mkString("\n", "\n\n", "\n")
final val HelpPatternFlags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE
def multiParser(s: State): Parser[Seq[String]] =
{

View File

@ -0,0 +1,25 @@
package sbt
import java.util.regex.Pattern
import scala.Console.{BOLD, RESET}
object Highlight
{
final val NormalIntensity = "\033[22m"
final val NormalTextColor = "\033[39m"
def showMatches(pattern: Pattern)(line: String): Option[String] =
{
val matcher = pattern.matcher(line)
if(ConsoleLogger.formatEnabled)
{
val highlighted = matcher.replaceAll(scala.Console.RED + "$0" + NormalTextColor)
if(highlighted == line) None else Some(highlighted)
}
else if(matcher.find)
Some(line)
else
None
}
def bold(s: String) = if(ConsoleLogger.formatEnabled) BOLD + s + NormalIntensity else s
}