From 0781b31fa4e3d22cb6a51882b8d632ea9a16ed6f Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Thu, 29 Sep 2016 15:45:46 +0200 Subject: Handle multiline messages in ConsoleReporter --- .../tools/dotc/reporting/ConsoleReporter.scala | 46 ++++++----- src/dotty/tools/dotc/util/SourceFile.scala | 2 +- src/dotty/tools/dotc/util/SourcePosition.scala | 11 +++ tests/repl/errmsgs.check | 90 +++++++++++----------- tests/repl/imports.check | 16 ++-- 5 files changed, 90 insertions(+), 75 deletions(-) diff --git a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index 45933d954..d96ff48a4 100644 --- a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -32,24 +32,35 @@ class ConsoleReporter( def stripColor(str: String): String = str.replaceAll("\u001B\\[[;\\d]*m", "") - def sourceLine(pos: SourcePosition)(implicit ctx: Context): (String, Int) = { - val lineNum = s"${pos.line}:" - (lineNum + hl"${pos.lineContent.stripLineEnd}", lineNum.length) - } + def sourceLines(pos: SourcePosition)(implicit ctx: Context): (List[String], Int) = { + var maxLen = Int.MinValue + val lines = pos.lines + .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" + } - def columnMarker(pos: SourcePosition, offset: Int)(implicit ctx: Context) = - if (pos.startLine == pos.endLine) { - val whitespace = " " * (pos.startColumn + offset) - val carets = - Red("^" * math.max(1, pos.endColumn - pos.startColumn)) + (lines, maxLen) + } - whitespace + carets.show - } else { - Red(" " * (pos.column + offset) + "^").show + def columnMarker(pos: SourcePosition, offset: Int)(implicit ctx: Context) = { + 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) = { - var hasLongLines = false val leastWhitespace = msg.lines.foldLeft(Int.MaxValue) { (minPad, line) => val lineLength = stripColor(line).length val padding = @@ -59,9 +70,8 @@ class ConsoleReporter( else minPad } - msg - .lines - .map { line => " " * leastWhitespace + line } + msg.lines + .map { line => " " * (offset - 1) + "|" + (" " * (leastWhitespace - offset)) + line } .mkString(sys.props("line.separator")) } @@ -85,11 +95,11 @@ class ConsoleReporter( def printMessageAndPos(msg: Message, pos: SourcePosition, diagnosticLevel: String)(implicit ctx: Context): Unit = { printMessage(posStr(pos, diagnosticLevel, msg)) if (pos.exists) { - val (src, offset) = sourceLine(pos) + val (srcLines, offset) = sourceLines(pos) val marker = columnMarker(pos, offset) val err = errorMsg(pos, msg.msg, offset) - printMessage(List(src, marker, err).mkString("\n")) + printMessage((srcLines ::: marker :: err :: Nil).mkString("\n")) } else printMessage(msg.msg) } diff --git a/src/dotty/tools/dotc/util/SourceFile.scala b/src/dotty/tools/dotc/util/SourceFile.scala index 8bd0ecfd6..1d4c9c2ab 100644 --- a/src/dotty/tools/dotc/util/SourceFile.scala +++ b/src/dotty/tools/dotc/util/SourceFile.scala @@ -97,7 +97,7 @@ case class SourceFile(file: AbstractFile, content: Array[Char]) extends interfac private lazy val lineIndices: Array[Int] = calculateLineIndices(content) /** Map line to offset of first character in line */ - def lineToOffset(index : Int): Int = lineIndices(index) + def lineToOffset(index: Int): Int = lineIndices(index) /** A cache to speed up offsetToLine searches to similar lines */ private var lastLine = 0 diff --git a/src/dotty/tools/dotc/util/SourcePosition.scala b/src/dotty/tools/dotc/util/SourcePosition.scala index 68a9b6403..d0f9cb887 100644 --- a/src/dotty/tools/dotc/util/SourcePosition.scala +++ b/src/dotty/tools/dotc/util/SourcePosition.scala @@ -14,6 +14,17 @@ extends interfaces.SourcePosition { def point: Int = pos.point /** The line of the position, starting at 0 */ def line: Int = source.offsetToLine(point) + + /** The lines of the position */ + def lines: List[Int] = + List.range(source.offsetToLine(start), source.offsetToLine(end)) match { + case Nil => line :: Nil + case xs => xs + } + + def lineContent(lineNumber: Int): String = + source.lineContent(source.lineToOffset(lineNumber)) + /** The column of the position, starting at 0 */ def column: Int = source.column(point) diff --git a/tests/repl/errmsgs.check b/tests/repl/errmsgs.check index b8cff5ba2..2a65fd949 100644 --- a/tests/repl/errmsgs.check +++ b/tests/repl/errmsgs.check @@ -2,46 +2,46 @@ scala> class Inv[T](x: T) defined class Inv scala> val x: List[String] = List(1) -- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- -3:val x: List[String] = List(1) - ^ - found: Int(1) - required: String - +4 |val x: List[String] = List(1) + | ^ + | found: Int(1) + | required: String + | scala> val y: List[List[String]] = List(List(1)) -- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- -3:val y: List[List[String]] = List(List(1)) - ^ - found: Int(1) - required: String - +4 |val y: List[List[String]] = List(List(1)) + | ^ + | found: Int(1) + | required: String + | scala> val z: (List[String], List[Int]) = (List(1), List("a")) -- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- -3:val z: (List[String], List[Int]) = (List(1), List("a")) - ^ - found: Int(1) - required: String - +4 |val z: (List[String], List[Int]) = (List(1), List("a")) + | ^ + | found: Int(1) + | required: String + | -- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- -3:val z: (List[String], List[Int]) = (List(1), List("a")) - ^^^ - found: String("a") - required: Int - +4 |val z: (List[String], List[Int]) = (List(1), List("a")) + | ^^^ + | found: String("a") + | required: Int + | scala> val a: Inv[String] = new Inv(new Inv(1)) -- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- -4:val a: Inv[String] = new Inv(new Inv(1)) - ^^^^^ - found: Inv[T] - required: String - - where: T is a type variable with constraint >: Int(1) +5 |val a: Inv[String] = new Inv(new Inv(1)) + | ^^^^^ + | found: Inv[T] + | required: String + | + | where: T is a type variable with constraint >: Int(1) scala> val b: Inv[String] = new Inv(1) -- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- -4:val b: Inv[String] = new Inv(1) - ^ - found: Int(1) - required: String - +5 |val b: Inv[String] = new Inv(1) + | ^ + | found: Int(1) + | required: String + | scala> abstract class C { type T val x: T @@ -58,19 +58,19 @@ scala> abstract class C { } } -- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- -8: var y: T = x - ^ - found: C.this.T(C.this.x) - required: T' - - where: T is a type in class C - T' is a type in the initalizer of value s which is an alias of String +9 | var y: T = x + | ^ + | found: C.this.T(C.this.x) + | required: T' + | + | where: T is a type in class C + | T' is a type in the initalizer of value s which is an alias of String -- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- -12: val z: T = y - ^ - found: T(y) - required: T' - - where: T is a type in the initalizer of value s which is an alias of String - T' is a type in method f which is an alias of Int +13 | val z: T = y + | ^ + | found: T(y) + | required: T' + | + | where: T is a type in the initalizer of value s which is an alias of String + | T' is a type in method f which is an alias of Int scala> :quit diff --git a/tests/repl/imports.check b/tests/repl/imports.check index 2e8d5dcf9..9743d2b94 100644 --- a/tests/repl/imports.check +++ b/tests/repl/imports.check @@ -8,17 +8,11 @@ scala> import o._ import o._ scala> buf += xs -- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- -10:buf += xs - ^^ - found: scala.collection.immutable.List[Int](o.xs) - required: String - --- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- -10:buf += xs - ^^^^^^^^^ - found: String - required: scala.collection.mutable.ListBuffer[Int] - +11 |buf += xs + | ^^ + | found: scala.collection.immutable.List[Int](o.xs) + | required: String + | scala> buf ++= xs res1: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3) scala> :quit -- cgit v1.2.3