mirror of https://github.com/sbt/sbt.git
Add Problem#rendered to customize how problems are shown
Dotty has its own logic for displaying problems with the proper file path, position, and caret, but if we store this information in Problem#message we end up with duplicated information in the output since Zinc will prepend/append similar things (see sbt.internal.inc.ProblemStringFormats). So far, we worked around this in Dotty by using an empty position in the sbt bridge reporter, but this means that crucial semantic information that could be used by a Build Server Protocol implementation and other tools is lost. This commit allows us to avoid by adding an optional `rendered` field to `Problem`: when this field is set, its value controls what the user sees, otherwise we fallback to the default behavior (the logic to do this will be added to Zinc after this PR is merged and a new release of sbt-util is made).
This commit is contained in:
parent
e905b44a33
commit
15522a0cbe
|
|
@ -124,8 +124,9 @@ lazy val utilLogging = (project in internalPath / "util-logging")
|
|||
exclude[DirectMissingMethodProblem]("sbt.internal.util.SuccessEvent.copy*"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.internal.util.TraceEvent.copy*"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.internal.util.StringEvent.copy*"),
|
||||
// Private final class constructor changed
|
||||
// Private final class constructors changed
|
||||
exclude[DirectMissingMethodProblem]("sbt.util.InterfaceUtil#ConcretePosition.this"),
|
||||
exclude[DirectMissingMethodProblem]("sbt.util.InterfaceUtil#ConcreteProblem.this"),
|
||||
),
|
||||
)
|
||||
.configure(addSbtIO)
|
||||
|
|
|
|||
|
|
@ -3,10 +3,20 @@
|
|||
*/
|
||||
package xsbti;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface Problem
|
||||
{
|
||||
String category();
|
||||
Severity severity();
|
||||
String message();
|
||||
Position position();
|
||||
}
|
||||
|
||||
// Default value to avoid breaking binary compatibility
|
||||
/**
|
||||
* If present, the string shown to the user when displaying this Problem.
|
||||
* Otherwise, the Problem will be shown in an implementation-defined way
|
||||
* based on the values of its other fields.
|
||||
*/
|
||||
default Optional<String> rendered() { return Optional.empty(); }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,4 +29,5 @@ type Problem {
|
|||
severity: Severity!
|
||||
message: String!
|
||||
position: Position!
|
||||
rendered: String
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
package sbt.internal.util.codec
|
||||
|
||||
import xsbti.{ Problem, Severity, Position }
|
||||
import sbt.util.InterfaceUtil.problem
|
||||
import _root_.sjsonnew.{ deserializationError, Builder, JsonFormat, Unbuilder }
|
||||
import java.util.Optional
|
||||
|
||||
trait ProblemFormats { self: SeverityFormats with PositionFormats with sjsonnew.BasicJsonProtocol =>
|
||||
implicit lazy val ProblemFormat: JsonFormat[Problem] = new JsonFormat[Problem] {
|
||||
|
|
@ -13,12 +13,20 @@ trait ProblemFormats { self: SeverityFormats with PositionFormats with sjsonnew.
|
|||
jsOpt match {
|
||||
case Some(js) =>
|
||||
unbuilder.beginObject(js)
|
||||
val category = unbuilder.readField[String]("category")
|
||||
val severity = unbuilder.readField[Severity]("severity")
|
||||
val message = unbuilder.readField[String]("message")
|
||||
val position = unbuilder.readField[Position]("position")
|
||||
val category0 = unbuilder.readField[String]("category")
|
||||
val severity0 = unbuilder.readField[Severity]("severity")
|
||||
val message0 = unbuilder.readField[String]("message")
|
||||
val position0 = unbuilder.readField[Position]("position")
|
||||
val rendered0 = unbuilder.readField[Optional[String]]("rendered")
|
||||
|
||||
unbuilder.endObject()
|
||||
problem(category, position, message, severity)
|
||||
new Problem {
|
||||
override val category = category0
|
||||
override val position = position0
|
||||
override val message = message0
|
||||
override val severity = severity0
|
||||
override val rendered = rendered0
|
||||
}
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
|
|
@ -29,6 +37,7 @@ trait ProblemFormats { self: SeverityFormats with PositionFormats with sjsonnew.
|
|||
builder.addField("severity", obj.severity)
|
||||
builder.addField("message", obj.message)
|
||||
builder.addField("position", obj.position)
|
||||
builder.addField("rendered", obj.rendered)
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,8 +89,16 @@ object InterfaceUtil {
|
|||
endLine0,
|
||||
endColumn0)
|
||||
|
||||
@deprecated("Use the overload of this method with more arguments", "1.2.2")
|
||||
def problem(cat: String, pos: Position, msg: String, sev: Severity): Problem =
|
||||
new ConcreteProblem(cat, pos, msg, sev)
|
||||
problem(cat, pos, msg, sev, None)
|
||||
|
||||
def problem(cat: String,
|
||||
pos: Position,
|
||||
msg: String,
|
||||
sev: Severity,
|
||||
rendered: Option[String]): Problem =
|
||||
new ConcreteProblem(cat, pos, msg, sev, rendered)
|
||||
|
||||
private final class ConcreteT2[A1, A2](a1: A1, a2: A2) extends T2[A1, A2] {
|
||||
val get1: A1 = a1
|
||||
|
|
@ -144,12 +152,14 @@ object InterfaceUtil {
|
|||
cat: String,
|
||||
pos: Position,
|
||||
msg: String,
|
||||
sev: Severity
|
||||
sev: Severity,
|
||||
rendered0: Option[String]
|
||||
) extends Problem {
|
||||
val category = cat
|
||||
val position = pos
|
||||
val message = msg
|
||||
val severity = sev
|
||||
override val rendered = o2jo(rendered0)
|
||||
override def toString = s"[$severity] $pos: $message"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ object Logger {
|
|||
sourceFile0
|
||||
)
|
||||
|
||||
@deprecated("Use InterfaceUtil.problem", "1.2.2")
|
||||
def problem(cat: String, pos: Position, msg: String, sev: Severity): Problem =
|
||||
InterfaceUtil.problem(cat, pos, msg, sev)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue