summaryrefslogtreecommitdiff
path: root/cask/src/cask/main/Main.scala
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2018-07-25 18:46:43 +0800
committerLi Haoyi <haoyi.sg@gmail.com>2018-07-25 18:48:25 +0800
commite52c6f57ef42b54a355d0976cb43f6762280e855 (patch)
treec3cc0d8a971c7f8b112886c725bb759c3471151d /cask/src/cask/main/Main.scala
parent5c8a2030c048f96a7ded0c2f701e1612b53a2046 (diff)
downloadcask-e52c6f57ef42b54a355d0976cb43f6762280e855.tar.gz
cask-e52c6f57ef42b54a355d0976cb43f6762280e855.tar.bz2
cask-e52c6f57ef42b54a355d0976cb43f6762280e855.zip
Basic invocation error renderer copied from Ammonite
Diffstat (limited to 'cask/src/cask/main/Main.scala')
-rw-r--r--cask/src/cask/main/Main.scala125
1 files changed, 117 insertions, 8 deletions
diff --git a/cask/src/cask/main/Main.scala b/cask/src/cask/main/Main.scala
index 045c2ed..680dd04 100644
--- a/cask/src/cask/main/Main.scala
+++ b/cask/src/cask/main/Main.scala
@@ -7,7 +7,7 @@ import io.undertow.Undertow
import io.undertow.server.{HttpHandler, HttpServerExchange}
import io.undertow.server.handlers.BlockingHandler
import io.undertow.util.HttpString
-
+import fastparse.utils.Utils.literalize
class MainRoutes extends BaseMain with Routes{
def allRoutes = Seq(this)
@@ -47,6 +47,111 @@ abstract class BaseMain{
response.data.write(exchange.getOutputStream)
}
+ def getLeftColWidth(items: Seq[Router.ArgSig[_, _, _,_]]) = {
+ items.map(_.name.length + 2) match{
+ case Nil => 0
+ case x => x.max
+ }
+ }
+
+ def renderArg[T](base: T,
+ arg: Router.ArgSig[_, T, _, _],
+ leftOffset: Int,
+ wrappedWidth: Int): (String, String) = {
+ val suffix = arg.default match{
+ case Some(f) => " (default " + f(base) + ")"
+ case None => ""
+ }
+ val docSuffix = arg.doc match{
+ case Some(d) => ": " + d
+ case None => ""
+ }
+ val wrapped = Util.softWrap(
+ arg.typeString + suffix + docSuffix,
+ leftOffset,
+ wrappedWidth - leftOffset
+ )
+ (arg.name, wrapped)
+ }
+
+ def formatMainMethodSignature[T](base: T,
+ main: Router.EntryPoint[_, T, _],
+ leftIndent: Int,
+ leftColWidth: Int) = {
+ // +2 for space on right of left col
+ val args = main.argSignatures.map(renderArg(base, _, leftColWidth + leftIndent + 2 + 2, 80))
+
+ val leftIndentStr = " " * leftIndent
+ val argStrings =
+ for((lhs, rhs) <- args)
+ yield {
+ val lhsPadded = lhs.padTo(leftColWidth, ' ')
+ val rhsPadded = rhs.lines.mkString("\n")
+ s"$leftIndentStr $lhsPadded $rhsPadded"
+ }
+ val mainDocSuffix = main.doc match{
+ case Some(d) => "\n" + leftIndentStr + Util.softWrap(d, leftIndent, 80)
+ case None => ""
+ }
+
+ s"""$leftIndentStr${main.name}$mainDocSuffix
+ |${argStrings.map(_ + "\n").mkString}""".stripMargin
+ }
+
+ def formatInvokeError[T](base: T, route: Router.EntryPoint[_, T, _], x: Router.Result.Error): String = {
+ def expectedMsg = formatMainMethodSignature(base: T, route, 0, 0)
+
+ x match{
+ case Router.Result.Error.Exception(x) => ???
+ case Router.Result.Error.MismatchedArguments(missing, unknown) =>
+ val missingStr =
+ if (missing.isEmpty) ""
+ else {
+ val chunks =
+ for (x <- missing)
+ yield x.name + ": " + x.typeString
+
+ val argumentsStr = Util.pluralize("argument", chunks.length)
+ s"Missing $argumentsStr: (${chunks.mkString(", ")})\n"
+ }
+
+
+ val unknownStr =
+ if (unknown.isEmpty) ""
+ else {
+ val argumentsStr = Util.pluralize("argument", unknown.length)
+ s"Unknown $argumentsStr: " + unknown.map(literalize(_)).mkString(" ") + "\n"
+ }
+
+
+ s"""$missingStr$unknownStr
+ |Arguments provided did not match expected signature:
+ |
+ |$expectedMsg
+ |""".stripMargin
+
+ case Router.Result.Error.InvalidArguments(x) =>
+ val argumentsStr = Util.pluralize("argument", x.length)
+ val thingies = x.map{
+ case Router.Result.ParamError.Invalid(p, v, ex) =>
+ val literalV = literalize(v)
+
+ s"${p.name}: ${p.typeString} = $literalV failed to parse with $ex"
+ case Router.Result.ParamError.DefaultFailed(p, ex) =>
+ s"${p.name}'s default value failed to evaluate with $ex"
+ }
+
+ s"""The following $argumentsStr failed to parse:
+ |
+ |${thingies.mkString("\n")}
+ |
+ |expected signature:
+ |
+ |$expectedMsg
+ |""".stripMargin
+
+ }
+ }
lazy val defaultHandler = new HttpHandler() {
def handleRequest(exchange: HttpServerExchange): Unit = {
routeTrie.lookup(Util.splitPath(exchange.getRequestPath).toList, Map()) match{
@@ -61,13 +166,17 @@ abstract class BaseMain{
result match{
case Router.Result.Success(response) => writeResponse(exchange, response)
- case Router.Result.Error.Exception(e) =>
- println(e)
- e.printStackTrace()
- writeResponse(exchange, handleError(500))
- case err: Router.Result.Error =>
- println(err)
- writeResponse(exchange, handleError(400))
+ case e: Router.Result.Error =>
+
+ writeResponse(exchange,
+ Response(
+ formatInvokeError(
+ routes,
+ metadata.entryPoint.asInstanceOf[EntryPoint[_, cask.main.Routes, _]],
+ e
+ ),
+ statusCode = 500)
+ )
}