Hi all!
My name is Martin Duhem, and I’m a software engineer working at the Scala Center since March 2017. These last months, I’ve been working on Scala Native, and I am starting to get involved (again) in sbt’s development. My next step will be focusing on usability improvements for sbt.
The first thing that I want to improve is the reporting of compilation errors inside sbt. Currently, I feel like the interesting bits of information coming from the errors are not sufficiently highlighted, and that a lot of time is wasted seeking those bits in the verbose error messages.
This is what error messages currently look like:
> compile
[info] Compiling 2 Scala sources to /Users/martin/Documents/Projects.nosync/Duhemm/sbt-errors-summary/target/scala-2.10/sbt-0.13/classes...
[warn] /Users/martin/Documents/Projects.nosync/Duhemm/sbt-errors-summary/src/main/scala/sbt/errorssummary/ConciseReporter.scala:22: @deprecated now takes two arguments; see the scaladoc.
[warn] @deprecated def oldStuff: Int = 2
[warn] ^
[error] /Users/martin/Documents/Projects.nosync/Duhemm/sbt-errors-summary/src/main/scala/sbt/errorssummary/ConciseReporter.scala:32: type mismatch;
[error] found : Unit
[error] required: Int
[error] override def bar(): Int = println("Hello")
[error] ^
[error] /Users/martin/Documents/Projects.nosync/Duhemm/sbt-errors-summary/src/main/scala/sbt/errorssummary/Plugin.scala:19: not found: value oops
[error] oops
[error] ^
[warn] /Users/martin/Documents/Projects.nosync/Duhemm/sbt-errors-summary/src/main/scala/sbt/errorssummary/Plugin.scala:11: implicit conversion method any2Unit should be enabled
[warn] by making the implicit value scala.language.implicitConversions visible.
[warn] This can be achieved by adding the import clause 'import scala.language.implicitConversions'
[warn] or by setting the compiler option -language:implicitConversions.
[warn] See the Scala docs for value scala.language.implicitConversions for a discussion
[warn] why the feature should be explicitly enabled.
[warn] implicit def any2Unit(any: Any): Unit = ()
[warn] ^
[warn] two warnings found
[error] two errors found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 0 s, completed Jun 23, 2017 2:21:15 PM
I find that this is suboptimal for several reasons:
- To me, the two most important things are the file name and the line number. They should be highlighted.
- It’s hard to tell where a message starts and where it ends.
- Errors are not grouped by file. That means that I may need to switch back and forth between files until I fixed all the errors.
- I don’t need to see the absolute path, only enough to uniquely identify the file from the root of my project.
- I consider the offset within the line to be of little use to the human reader (it’s not shown here, because this is Scala 2.10, but it is shown on 2.12)
- Displaying one error requires easily 5-6 lines. This means a lot of scrolling to get information about all the errors.
- The summary does not bring much to the table.
- When doing refactoring, you get hundreds of lines of error messages, and no way to quickly see all the things that are wrong in a single file.
To address those points, I wrote an sbt plugin that replaces sbt’s default error reporter by something more colourful and concise. The plugin can be found on Github: https://github.com/Duhemm/sbt-errors-summary.
Given that people who saw it generally liked it, I’m proposing to use it as the default for sbt 1.0. This is how the same errors are displayed using this plugin:
> compile
[info] Compiling 2 Scala sources to /Users/martin/Documents/Projects.nosync/Duhemm/sbt-errors-summary/target/scala-2.10/sbt-0.13/classes...
[warn] [0] /scala/sbt/errorssummary/ConciseReporter.scala:22: @deprecated now takes two arguments; see the scaladoc.
[warn] @deprecated def oldStuff: Int = 2
[warn] ^
[error] [1] /scala/sbt/errorssummary/ConciseReporter.scala:32: type mismatch;
[error] found : Unit
[error] required: Int
[error] override def bar(): Int = println("Hello")
[error] ^
[error] [2] /scala/sbt/errorssummary/Plugin.scala:19: not found: value oops
[error] oops
[error] ^
[warn] [3] /scala/sbt/errorssummary/Plugin.scala:11: implicit conversion method any2Unit should be enabled
[warn] by making the implicit value scala.language.implicitConversions visible.
[warn] This can be achieved by adding the import clause 'import scala.language.implicitConversions'
[warn] or by setting the compiler option -language:implicitConversions.
[warn] See the Scala docs for value scala.language.implicitConversions for a discussion
[warn] why the feature should be explicitly enabled.
[warn] implicit def any2Unit(any: Any): Unit = ()
[warn] ^
[error] /scala/sbt/errorssummary/Plugin.scala: 11 [3], 19 [2]
[error] /scala/sbt/errorssummary/ConciseReporter.scala: 22 [0], 32 [1]
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 1 s, completed Jun 23, 2017 2:58:50 PM
This plugin addresses my pain points about sbt’s error reporting. It shows me a nice, colourful summary telling me immediately that a given file contains a warning or an error at a given line. If I need, I can quickly jump to the corresponding error message, thanks to the identifier in [square brackets]
. I can completely ignore the top lines if I don’t need them. It saves a lot of screen space. I have short, readable paths.
Of course, this plugin is not optimal and would probably not make everyone happy, but I would like to hear your opinion about how errors should be reported in sbt, and how you would improve this plugin or the current situation. I would also like to improve the out of the box experience of sbt, which is why I would like to see this plugin, or anything else that would emerge from this discussion, become the default error reporter of sbt.
Thank you for your input!