From e5aade87a9d7fb6c0319920c81ef3ee9f146bba1 Mon Sep 17 00:00:00 2001 From: Dmitry Melnichenko Date: Mon, 31 Oct 2016 21:01:10 +0200 Subject: #1579 Adapt the sbt bridge for the new error message --- .../tools/dotc/reporting/MessageRendering.scala | 111 +++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 src/dotty/tools/dotc/reporting/MessageRendering.scala (limited to 'src/dotty/tools/dotc/reporting/MessageRendering.scala') diff --git a/src/dotty/tools/dotc/reporting/MessageRendering.scala b/src/dotty/tools/dotc/reporting/MessageRendering.scala new file mode 100644 index 000000000..6d9e45a6e --- /dev/null +++ b/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -0,0 +1,111 @@ +package dotty.tools +package dotc +package reporting + +import core.Contexts.Context +import core.Decorators._ +import printing.Highlighting.{Blue, Red} +import diagnostic.{Message, MessageContainer, NoExplanation} +import diagnostic.messages._ +import util.SourcePosition + +import scala.collection.mutable + +trait MessageRendering { + def stripColor(str: String): String = + str.replaceAll("\u001B\\[[;\\d]*m", "") + + def sourceLines(pos: SourcePosition)(implicit ctx: Context): (List[String], List[String], Int) = { + var maxLen = Int.MinValue + def render(xs: List[Int]) = + xs.map(pos.source.offsetToLine(_)) + .map { lineNbr => + val prefix = s"${lineNbr + 1} |" + maxLen = math.max(maxLen, prefix.length) + (prefix, pos.lineContent(lineNbr).stripLineEnd) + } + .map { case (prefix, line) => + val lnum = Red(" " * math.max(0, maxLen - prefix.length) + prefix) + hl"$lnum$line" + } + + val (before, after) = pos.beforeAndAfterPoint + (render(before), render(after), maxLen) + } + + def columnMarker(pos: SourcePosition, offset: Int)(implicit ctx: Context): String = { + val prefix = " " * (offset - 1) + val whitespace = " " * pos.startColumn + val carets = Red { + if (pos.startLine == pos.endLine) + "^" * math.max(1, pos.endColumn - pos.startColumn) + else "^" + } + + s"$prefix|$whitespace${carets.show}" + } + + def errorMsg(pos: SourcePosition, msg: String, offset: Int)(implicit ctx: Context): String = { + val leastWhitespace = msg.lines.foldLeft(Int.MaxValue) { (minPad, line) => + val lineLength = stripColor(line).length + val padding = + math.min(math.max(0, ctx.settings.pageWidth.value - offset - lineLength), offset + pos.startColumn) + + if (padding < minPad) padding + else minPad + } + + msg.lines + .map { line => " " * (offset - 1) + "|" + (" " * (leastWhitespace - offset)) + line } + .mkString(sys.props("line.separator")) + } + + def posStr(pos: SourcePosition, diagnosticLevel: String, message: Message)(implicit ctx: Context): String = + if (pos.exists) Blue({ + val file = pos.source.file.toString + val errId = + if (message.errorId != NoExplanation.ID) + s"[E${"0" * (3 - message.errorId.toString.length) + message.errorId}] " + else "" + val kind = + if (message.kind == "") diagnosticLevel + else s"${message.kind} $diagnosticLevel" + val prefix = s"-- ${errId}${kind}: $file " + + prefix + + ("-" * math.max(ctx.settings.pageWidth.value - stripColor(prefix).length, 0)) + }).show else "" + + def explanation(m: Message)(implicit ctx: Context): String = { + val sb = new StringBuilder(hl"""| + |${Blue("Explanation")} + |${Blue("===========")}""".stripMargin) + sb.append('\n').append(m.explanation) + if (m.explanation.lastOption != Some('\n')) sb.append('\n') + sb.toString + } + + def messageAndPos(msg: Message, pos: SourcePosition, diagnosticLevel: String)(implicit ctx: Context): String = { + val sb = mutable.StringBuilder.newBuilder + sb.append(posStr(pos, diagnosticLevel, msg)).append('\n') + if (pos.exists) { + val (srcBefore, srcAfter, offset) = sourceLines(pos) + val marker = columnMarker(pos, offset) + val err = errorMsg(pos, msg.msg, offset) + sb.append((srcBefore ::: marker :: err :: srcAfter).mkString("\n")) + } else sb.append(msg.msg) + sb.toString + } + + def diagnosticLevel(cont: MessageContainer): String = { + cont match { + case m: Error => "Error" + case m: FeatureWarning => "Feature Warning" + case m: DeprecationWarning => "Deprecation Warning" + case m: UncheckedWarning => "Unchecked Warning" + case m: MigrationWarning => "Migration Warning" + case m: Warning => "Warning" + case m: Info => "Info" + } + } +} -- cgit v1.2.3