From f9328badfe54f9c1d5c9bf9ab528e5ed14849a88 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Fri, 4 Nov 2016 14:23:45 +0100 Subject: Clean up in ConsoleReporter & MessageRendering --- .../tools/dotc/reporting/ConsoleReporter.scala | 35 ++++++---------- .../tools/dotc/reporting/MessageRendering.scala | 48 +++++++++++++++++----- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index 99a80982f..95f468995 100644 --- a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -2,11 +2,10 @@ package dotty.tools package dotc package reporting -import util.SourcePosition import core.Contexts._ import java.io.{ BufferedReader, PrintWriter } import diagnostic.{ Message, MessageContainer } -import diagnostic.messages._ +import diagnostic.messages.{ Error, Warning, ConditionalWarning } /** * This class implements a Reporter that displays messages on a text console @@ -25,36 +24,29 @@ class ConsoleReporter( def printMessage(msg: String): Unit = { writer.print(msg + "\n"); writer.flush() } /** Prints the message with the given position indication. */ - def printMessageAndPos(msg: Message, pos: SourcePosition, diagnosticLevel: String)(implicit ctx: Context): Boolean = { - printMessage(messageAndPos(msg, pos, diagnosticLevel)) - true - } - - def printExplanation(m: Message)(implicit ctx: Context): Unit = { - printMessage(explanation(m)) - } - - override def doReport(m: MessageContainer)(implicit ctx: Context): Unit = { + def doReport(m: MessageContainer)(implicit ctx: Context): Unit = { val didPrint = m match { case m: Error => - val didPrint = printMessageAndPos(m.contained, m.pos, diagnosticLevel(m)) + printMessage(messageAndPos(m.contained, m.pos, diagnosticLevel(m))) if (ctx.settings.prompt.value) displayPrompt() - didPrint + true case m: ConditionalWarning if !m.enablingOption.value => false case m => - printMessageAndPos(m.contained, m.pos, diagnosticLevel(m)) + printMessage(messageAndPos(m.contained, m.pos, diagnosticLevel(m))) + true } if (didPrint && ctx.shouldExplain(m)) - printExplanation(m.contained) + printMessage(explanation(m.contained)) else if (didPrint && m.contained.explanation.nonEmpty) printMessage("\nlonger explanation available when compiling with `-explain`") } - def displayPrompt(): Unit = { - writer.print("\na)bort, s)tack, r)esume: ") - writer.flush() + /** Show prompt if `-Xprompt` is passed as a flag to the compiler */ + def displayPrompt()(implicit ctx: Context): Unit = { + printMessage("\na)bort, s)tack, r)esume: ") + flush() if (reader != null) { val response = reader.read().asInstanceOf[Char].toLower if (response == 'a' || response == 's') { @@ -62,11 +54,10 @@ class ConsoleReporter( if (response == 'a') sys.exit(1) } - writer.print("\n") - writer.flush() + print("\n") + flush() } } override def flush()(implicit ctx: Context): Unit = { writer.flush() } } - diff --git a/src/dotty/tools/dotc/reporting/MessageRendering.scala b/src/dotty/tools/dotc/reporting/MessageRendering.scala index 79632c965..24d583b19 100644 --- a/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -12,15 +12,30 @@ import util.SourcePosition import scala.collection.mutable trait MessageRendering { + /** Remove ANSI coloring from `str`, useful for getting real length of + * strings + * + * @return string stripped of ANSI escape codes + */ def stripColor(str: String): String = str.replaceAll("\u001B\\[[;\\d]*m", "") + /** When inlining a method call, if there's an error we'd like to get the + * outer context and the `pos` at which the call was inlined. + * + * @return a list of strings with inline locations + */ def outer(pos: SourcePosition, prefix: String)(implicit ctx: Context): List[String] = if (pos.outer.exists) { s"$prefix| This location is in code that was inlined at ${pos.outer}" :: outer(pos.outer, prefix) } else Nil + /** Get the sourcelines before and after the position, as well as the offset + * for rendering line numbers + * + * @return (lines before error, lines after error, line numbers offset) + */ def sourceLines(pos: SourcePosition)(implicit ctx: Context): (List[String], List[String], Int) = { var maxLen = Int.MinValue def render(xs: List[Int]) = @@ -39,6 +54,7 @@ trait MessageRendering { (render(before), render(after), maxLen) } + /** The column markers aligned under the error */ def columnMarker(pos: SourcePosition, offset: Int)(implicit ctx: Context): String = { val prefix = " " * (offset - 1) val whitespace = " " * pos.startColumn @@ -51,21 +67,30 @@ trait MessageRendering { s"$prefix|$whitespace${carets.show}" } + /** The error message (`msg`) aligned under `pos` + * + * @return aligned error message + */ 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) + val currPad = math.min( + math.max(0, ctx.settings.pageWidth.value - offset - lineLength), + offset + pos.startColumn + ) - if (padding < minPad) padding - else minPad + math.min(currPad, minPad) } msg.lines - .map { line => " " * (offset - 1) + "|" + (" " * (leastWhitespace - offset)) + line } + .map { line => " " * (offset - 1) + "|" + (" " * (leastWhitespace - offset)) + line} .mkString(sys.props("line.separator")) } + /** The separator between errors containing the source file and error type + * + * @return separator containing error location and kind + */ def posStr(pos: SourcePosition, diagnosticLevel: String, message: Message)(implicit ctx: Context): String = if (pos.exists) Blue({ val file = pos.source.file.toString @@ -82,15 +107,19 @@ trait MessageRendering { ("-" * math.max(ctx.settings.pageWidth.value - stripColor(prefix).length, 0)) }).show else "" + /** Explanation rendered under "Explanation" header */ def explanation(m: Message)(implicit ctx: Context): String = { - val sb = new StringBuilder(hl"""| - |${Blue("Explanation")} - |${Blue("===========")}""".stripMargin) + val sb = new StringBuilder( + hl"""| + |${Blue("Explanation")} + |${Blue("===========")}""" + ) sb.append('\n').append(m.explanation) if (m.explanation.lastOption != Some('\n')) sb.append('\n') sb.toString } + /** The whole message rendered from `msg` */ 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') @@ -103,7 +132,7 @@ trait MessageRendering { sb.toString } - def diagnosticLevel(cont: MessageContainer): String = { + def diagnosticLevel(cont: MessageContainer): String = cont match { case m: Error => "Error" case m: FeatureWarning => "Feature Warning" @@ -113,5 +142,4 @@ trait MessageRendering { case m: Warning => "Warning" case m: Info => "Info" } - } } -- cgit v1.2.3