Forward ScalaDiagnostic

**Problem**
Zinc added actions in Problem, but it's not yet forwarded to BSP
clients.

**Solution**
As discussed in
https://contributors.scala-lang.org/t/roadmap-for-actionable-diagnostics/6172,
the plan seems to be to use the `data` field with `actions` inside it,
so this implements that.
This commit is contained in:
Eugene Yokota 2023-05-22 00:33:46 -04:00
parent b5c3c4836f
commit 93bd66b673
17 changed files with 576 additions and 17 deletions

View File

@ -180,8 +180,7 @@ final class BuildServerReporterImpl(
} }
} }
private def toDiagnostic(problem: Problem): Diagnostic = { private def toRange(pos: XPosition): Range = {
val pos = problem.position
val startLineOpt = pos.startLine.toOption.map(_.toLong - 1) val startLineOpt = pos.startLine.toOption.map(_.toLong - 1)
val startColumnOpt = pos.startColumn.toOption.map(_.toLong) val startColumnOpt = pos.startColumn.toOption.map(_.toLong)
val endLineOpt = pos.endLine.toOption.map(_.toLong - 1) val endLineOpt = pos.endLine.toOption.map(_.toLong - 1)
@ -192,14 +191,45 @@ final class BuildServerReporterImpl(
val startPos = toPosition(startLineOpt, startColumnOpt).getOrElse(Position(0L, 0L)) val startPos = toPosition(startLineOpt, startColumnOpt).getOrElse(Position(0L, 0L))
val endPosOpt = toPosition(endLineOpt, endColumnOpt) val endPosOpt = toPosition(endLineOpt, endColumnOpt)
val range = Range(startPos, endPosOpt.getOrElse(startPos)) Range(startPos, endPosOpt.getOrElse(startPos))
}
private def toDiagnostic(problem: Problem): Diagnostic = {
val actions0 = problem.actions().asScala.toVector
val data =
if (actions0.isEmpty) None
else
Some(
ScalaDiagnostic(
actions = actions0.map { a =>
ScalaAction(
title = a.title,
description = a.description.toOption,
edit = Some(
ScalaWorkspaceEdit(
changes = a.edit.changes().asScala.toVector.map { edit =>
ScalaTextEdit(
range = toRange(edit.position),
newText = edit.newText,
)
}
)
),
)
}
)
)
Diagnostic( Diagnostic(
range, range = toRange(problem.position),
Option(toDiagnosticSeverity(problem.severity)), severity = Option(toDiagnosticSeverity(problem.severity)),
problem.diagnosticCode().toOption.map(_.code), code = problem.diagnosticCode().toOption.map(_.code),
Option("sbt"), source = Option("sbt"),
problem.message message = problem.message,
relatedInformation = Vector.empty,
dataKind = data.map { _ =>
"scala"
},
data = data,
) )
} }

View File

@ -14,28 +14,37 @@ package sbt.internal.bsp
* @param source A human-readable string describing the source of this * @param source A human-readable string describing the source of this
diagnostic, e.g. 'typescript' or 'super lint'. diagnostic, e.g. 'typescript' or 'super lint'.
* @param message The diagnostic's message. * @param message The diagnostic's message.
* @param relatedInformation A list of related diagnostic information, e.g. when symbol-names within
a scope collide all definitions can be marked via this property.
* @param dataKind Kind of data to expect in the `data` field. If this field is not set,
the kind of data is not specified.
* @param data A data entry field.
*/ */
final class Diagnostic private ( final class Diagnostic private (
val range: sbt.internal.bsp.Range, val range: sbt.internal.bsp.Range,
val severity: Option[Long], val severity: Option[Long],
val code: Option[String], val code: Option[String],
val source: Option[String], val source: Option[String],
val message: String) extends Serializable { val message: String,
val relatedInformation: Vector[sbt.internal.bsp.DiagnosticRelatedInformation],
val dataKind: Option[String],
val data: Option[sbt.internal.bsp.ScalaDiagnostic]) extends Serializable {
private def this(range: sbt.internal.bsp.Range, severity: Option[Long], code: Option[String], source: Option[String], message: String) = this(range, severity, code, source, message, Vector(), None, None)
private def this(range: sbt.internal.bsp.Range, severity: Option[Long], code: Option[String], source: Option[String], message: String, relatedInformation: Vector[sbt.internal.bsp.DiagnosticRelatedInformation]) = this(range, severity, code, source, message, relatedInformation, None, None)
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: Diagnostic => (this.range == x.range) && (this.severity == x.severity) && (this.code == x.code) && (this.source == x.source) && (this.message == x.message) case x: Diagnostic => (this.range == x.range) && (this.severity == x.severity) && (this.code == x.code) && (this.source == x.source) && (this.message == x.message) && (this.relatedInformation == x.relatedInformation) && (this.dataKind == x.dataKind) && (this.data == x.data)
case _ => false case _ => false
}) })
override def hashCode: Int = { override def hashCode: Int = {
37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.Diagnostic".##) + range.##) + severity.##) + code.##) + source.##) + message.##) 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.Diagnostic".##) + range.##) + severity.##) + code.##) + source.##) + message.##) + relatedInformation.##) + dataKind.##) + data.##)
} }
override def toString: String = { override def toString: String = {
"Diagnostic(" + range + ", " + severity + ", " + code + ", " + source + ", " + message + ")" "Diagnostic(" + range + ", " + severity + ", " + code + ", " + source + ", " + message + ", " + relatedInformation + ", " + dataKind + ", " + data + ")"
} }
private[this] def copy(range: sbt.internal.bsp.Range = range, severity: Option[Long] = severity, code: Option[String] = code, source: Option[String] = source, message: String = message): Diagnostic = { private[this] def copy(range: sbt.internal.bsp.Range = range, severity: Option[Long] = severity, code: Option[String] = code, source: Option[String] = source, message: String = message, relatedInformation: Vector[sbt.internal.bsp.DiagnosticRelatedInformation] = relatedInformation, dataKind: Option[String] = dataKind, data: Option[sbt.internal.bsp.ScalaDiagnostic] = data): Diagnostic = {
new Diagnostic(range, severity, code, source, message) new Diagnostic(range, severity, code, source, message, relatedInformation, dataKind, data)
} }
def withRange(range: sbt.internal.bsp.Range): Diagnostic = { def withRange(range: sbt.internal.bsp.Range): Diagnostic = {
copy(range = range) copy(range = range)
@ -61,9 +70,28 @@ final class Diagnostic private (
def withMessage(message: String): Diagnostic = { def withMessage(message: String): Diagnostic = {
copy(message = message) copy(message = message)
} }
def withRelatedInformation(relatedInformation: Vector[sbt.internal.bsp.DiagnosticRelatedInformation]): Diagnostic = {
copy(relatedInformation = relatedInformation)
}
def withDataKind(dataKind: Option[String]): Diagnostic = {
copy(dataKind = dataKind)
}
def withDataKind(dataKind: String): Diagnostic = {
copy(dataKind = Option(dataKind))
}
def withData(data: Option[sbt.internal.bsp.ScalaDiagnostic]): Diagnostic = {
copy(data = data)
}
def withData(data: sbt.internal.bsp.ScalaDiagnostic): Diagnostic = {
copy(data = Option(data))
}
} }
object Diagnostic { object Diagnostic {
def apply(range: sbt.internal.bsp.Range, severity: Option[Long], code: Option[String], source: Option[String], message: String): Diagnostic = new Diagnostic(range, severity, code, source, message) def apply(range: sbt.internal.bsp.Range, severity: Option[Long], code: Option[String], source: Option[String], message: String): Diagnostic = new Diagnostic(range, severity, code, source, message)
def apply(range: sbt.internal.bsp.Range, severity: Long, code: String, source: String, message: String): Diagnostic = new Diagnostic(range, Option(severity), Option(code), Option(source), message) def apply(range: sbt.internal.bsp.Range, severity: Long, code: String, source: String, message: String): Diagnostic = new Diagnostic(range, Option(severity), Option(code), Option(source), message)
def apply(range: sbt.internal.bsp.Range, severity: Option[Long], code: Option[String], source: Option[String], message: String, relatedInformation: Vector[sbt.internal.bsp.DiagnosticRelatedInformation]): Diagnostic = new Diagnostic(range, severity, code, source, message, relatedInformation)
def apply(range: sbt.internal.bsp.Range, severity: Long, code: String, source: String, message: String, relatedInformation: Vector[sbt.internal.bsp.DiagnosticRelatedInformation]): Diagnostic = new Diagnostic(range, Option(severity), Option(code), Option(source), message, relatedInformation)
def apply(range: sbt.internal.bsp.Range, severity: Option[Long], code: Option[String], source: Option[String], message: String, relatedInformation: Vector[sbt.internal.bsp.DiagnosticRelatedInformation], dataKind: Option[String], data: Option[sbt.internal.bsp.ScalaDiagnostic]): Diagnostic = new Diagnostic(range, severity, code, source, message, relatedInformation, dataKind, data)
def apply(range: sbt.internal.bsp.Range, severity: Long, code: String, source: String, message: String, relatedInformation: Vector[sbt.internal.bsp.DiagnosticRelatedInformation], dataKind: String, data: sbt.internal.bsp.ScalaDiagnostic): Diagnostic = new Diagnostic(range, Option(severity), Option(code), Option(source), message, relatedInformation, Option(dataKind), Option(data))
} }

View File

@ -0,0 +1,43 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* Represents a related message and source code location for a diagnostic.
* This should be used to point to code locations that cause or are related to
* a diagnostics, e.g when duplicating a symbol in a scope.
* @param location The location of this related diagnostic information.
* @param message The message of this related diagnostic information.
*/
final class DiagnosticRelatedInformation private (
val location: sbt.internal.bsp.Location,
val message: String) extends Serializable {
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: DiagnosticRelatedInformation => (this.location == x.location) && (this.message == x.message)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (37 * (17 + "sbt.internal.bsp.DiagnosticRelatedInformation".##) + location.##) + message.##)
}
override def toString: String = {
"DiagnosticRelatedInformation(" + location + ", " + message + ")"
}
private[this] def copy(location: sbt.internal.bsp.Location = location, message: String = message): DiagnosticRelatedInformation = {
new DiagnosticRelatedInformation(location, message)
}
def withLocation(location: sbt.internal.bsp.Location): DiagnosticRelatedInformation = {
copy(location = location)
}
def withMessage(message: String): DiagnosticRelatedInformation = {
copy(message = message)
}
}
object DiagnosticRelatedInformation {
def apply(location: sbt.internal.bsp.Location, message: String): DiagnosticRelatedInformation = new DiagnosticRelatedInformation(location, message)
}

View File

@ -0,0 +1,37 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/** Represents a location inside a resource, such as a line inside a text file. */
final class Location private (
val uri: String,
val range: sbt.internal.bsp.Range) extends Serializable {
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: Location => (this.uri == x.uri) && (this.range == x.range)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (37 * (17 + "sbt.internal.bsp.Location".##) + uri.##) + range.##)
}
override def toString: String = {
"Location(" + uri + ", " + range + ")"
}
private[this] def copy(uri: String = uri, range: sbt.internal.bsp.Range = range): Location = {
new Location(uri, range)
}
def withUri(uri: String): Location = {
copy(uri = uri)
}
def withRange(range: sbt.internal.bsp.Range): Location = {
copy(range = range)
}
}
object Location {
def apply(uri: String, range: sbt.internal.bsp.Range): Location = new Location(uri, range)
}

View File

@ -0,0 +1,54 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* A Scala action represents a change that can be performed in code.
* See also LSP: Code Action Request (https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_codeAction).
* @param title A short, human-readable, title for this code action.
* @param description A description that may be shown to the user client side to explain the action.
* @param edit The workspace edit this code action performs.
*/
final class ScalaAction private (
val title: String,
val description: Option[String],
val edit: Option[sbt.internal.bsp.ScalaWorkspaceEdit]) extends Serializable {
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: ScalaAction => (this.title == x.title) && (this.description == x.description) && (this.edit == x.edit)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.ScalaAction".##) + title.##) + description.##) + edit.##)
}
override def toString: String = {
"ScalaAction(" + title + ", " + description + ", " + edit + ")"
}
private[this] def copy(title: String = title, description: Option[String] = description, edit: Option[sbt.internal.bsp.ScalaWorkspaceEdit] = edit): ScalaAction = {
new ScalaAction(title, description, edit)
}
def withTitle(title: String): ScalaAction = {
copy(title = title)
}
def withDescription(description: Option[String]): ScalaAction = {
copy(description = description)
}
def withDescription(description: String): ScalaAction = {
copy(description = Option(description))
}
def withEdit(edit: Option[sbt.internal.bsp.ScalaWorkspaceEdit]): ScalaAction = {
copy(edit = edit)
}
def withEdit(edit: sbt.internal.bsp.ScalaWorkspaceEdit): ScalaAction = {
copy(edit = Option(edit))
}
}
object ScalaAction {
def apply(title: String, description: Option[String], edit: Option[sbt.internal.bsp.ScalaWorkspaceEdit]): ScalaAction = new ScalaAction(title, description, edit)
def apply(title: String, description: String, edit: sbt.internal.bsp.ScalaWorkspaceEdit): ScalaAction = new ScalaAction(title, Option(description), Option(edit))
}

View File

@ -0,0 +1,40 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* ScalaDiagnostic is a data structure that contains Scala-specific
* metadata generated by Scala compilation. This metadata is
* embedded in the `data: Option[Json]` field of the Diagnostic definition, when
* the dataKind field contains "scala".
* @param actions Actions (also known as quick fixes) that are able to either fix or address
the issue that is causing this diagnostic.
*/
final class ScalaDiagnostic private (
val actions: Vector[sbt.internal.bsp.ScalaAction]) extends Serializable {
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: ScalaDiagnostic => (this.actions == x.actions)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (17 + "sbt.internal.bsp.ScalaDiagnostic".##) + actions.##)
}
override def toString: String = {
"ScalaDiagnostic(" + actions + ")"
}
private[this] def copy(actions: Vector[sbt.internal.bsp.ScalaAction] = actions): ScalaDiagnostic = {
new ScalaDiagnostic(actions)
}
def withActions(actions: Vector[sbt.internal.bsp.ScalaAction]): ScalaDiagnostic = {
copy(actions = actions)
}
}
object ScalaDiagnostic {
def apply(actions: Vector[sbt.internal.bsp.ScalaAction]): ScalaDiagnostic = new ScalaDiagnostic(actions)
}

View File

@ -0,0 +1,43 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* A textual edit applicable to a text document.
* @param range The range of the text document to be manipulated. To insert
text into a document create a range where start === end.
* @param newText The string to be inserted. For delete operations use an
empty string.
*/
final class ScalaTextEdit private (
val range: sbt.internal.bsp.Range,
val newText: String) extends Serializable {
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: ScalaTextEdit => (this.range == x.range) && (this.newText == x.newText)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (37 * (17 + "sbt.internal.bsp.ScalaTextEdit".##) + range.##) + newText.##)
}
override def toString: String = {
"ScalaTextEdit(" + range + ", " + newText + ")"
}
private[this] def copy(range: sbt.internal.bsp.Range = range, newText: String = newText): ScalaTextEdit = {
new ScalaTextEdit(range, newText)
}
def withRange(range: sbt.internal.bsp.Range): ScalaTextEdit = {
copy(range = range)
}
def withNewText(newText: String): ScalaTextEdit = {
copy(newText = newText)
}
}
object ScalaTextEdit {
def apply(range: sbt.internal.bsp.Range, newText: String): ScalaTextEdit = new ScalaTextEdit(range, newText)
}

View File

@ -0,0 +1,33 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/** A workspace edit represents changes to many resources managed in the workspace. */
final class ScalaWorkspaceEdit private (
val changes: Vector[sbt.internal.bsp.ScalaTextEdit]) extends Serializable {
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: ScalaWorkspaceEdit => (this.changes == x.changes)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (17 + "sbt.internal.bsp.ScalaWorkspaceEdit".##) + changes.##)
}
override def toString: String = {
"ScalaWorkspaceEdit(" + changes + ")"
}
private[this] def copy(changes: Vector[sbt.internal.bsp.ScalaTextEdit] = changes): ScalaWorkspaceEdit = {
new ScalaWorkspaceEdit(changes)
}
def withChanges(changes: Vector[sbt.internal.bsp.ScalaTextEdit]): ScalaWorkspaceEdit = {
copy(changes = changes)
}
}
object ScalaWorkspaceEdit {
def apply(changes: Vector[sbt.internal.bsp.ScalaTextEdit]): ScalaWorkspaceEdit = new ScalaWorkspaceEdit(changes)
}

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY // DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait DiagnosticFormats { self: sbt.internal.bsp.codec.RangeFormats with sjsonnew.BasicJsonProtocol => trait DiagnosticFormats { self: sbt.internal.bsp.codec.RangeFormats with sbt.internal.bsp.codec.DiagnosticRelatedInformationFormats with sbt.internal.bsp.codec.ScalaDiagnosticFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val DiagnosticFormat: JsonFormat[sbt.internal.bsp.Diagnostic] = new JsonFormat[sbt.internal.bsp.Diagnostic] { implicit lazy val DiagnosticFormat: JsonFormat[sbt.internal.bsp.Diagnostic] = new JsonFormat[sbt.internal.bsp.Diagnostic] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.Diagnostic = { override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.Diagnostic = {
__jsOpt match { __jsOpt match {
@ -16,8 +16,11 @@ implicit lazy val DiagnosticFormat: JsonFormat[sbt.internal.bsp.Diagnostic] = ne
val code = unbuilder.readField[Option[String]]("code") val code = unbuilder.readField[Option[String]]("code")
val source = unbuilder.readField[Option[String]]("source") val source = unbuilder.readField[Option[String]]("source")
val message = unbuilder.readField[String]("message") val message = unbuilder.readField[String]("message")
val relatedInformation = unbuilder.readField[Vector[sbt.internal.bsp.DiagnosticRelatedInformation]]("relatedInformation")
val dataKind = unbuilder.readField[Option[String]]("dataKind")
val data = unbuilder.readField[Option[sbt.internal.bsp.ScalaDiagnostic]]("data")
unbuilder.endObject() unbuilder.endObject()
sbt.internal.bsp.Diagnostic(range, severity, code, source, message) sbt.internal.bsp.Diagnostic(range, severity, code, source, message, relatedInformation, dataKind, data)
case None => case None =>
deserializationError("Expected JsObject but found None") deserializationError("Expected JsObject but found None")
} }
@ -29,6 +32,9 @@ implicit lazy val DiagnosticFormat: JsonFormat[sbt.internal.bsp.Diagnostic] = ne
builder.addField("code", obj.code) builder.addField("code", obj.code)
builder.addField("source", obj.source) builder.addField("source", obj.source)
builder.addField("message", obj.message) builder.addField("message", obj.message)
builder.addField("relatedInformation", obj.relatedInformation)
builder.addField("dataKind", obj.dataKind)
builder.addField("data", obj.data)
builder.endObject() builder.endObject()
} }
} }

View File

@ -0,0 +1,29 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait DiagnosticRelatedInformationFormats { self: sbt.internal.bsp.codec.LocationFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val DiagnosticRelatedInformationFormat: JsonFormat[sbt.internal.bsp.DiagnosticRelatedInformation] = new JsonFormat[sbt.internal.bsp.DiagnosticRelatedInformation] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.DiagnosticRelatedInformation = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val location = unbuilder.readField[sbt.internal.bsp.Location]("location")
val message = unbuilder.readField[String]("message")
unbuilder.endObject()
sbt.internal.bsp.DiagnosticRelatedInformation(location, message)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.DiagnosticRelatedInformation, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("location", obj.location)
builder.addField("message", obj.message)
builder.endObject()
}
}
}

View File

@ -15,6 +15,12 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol
with sbt.internal.bsp.codec.TextDocumentIdentifierFormats with sbt.internal.bsp.codec.TextDocumentIdentifierFormats
with sbt.internal.bsp.codec.PositionFormats with sbt.internal.bsp.codec.PositionFormats
with sbt.internal.bsp.codec.RangeFormats with sbt.internal.bsp.codec.RangeFormats
with sbt.internal.bsp.codec.LocationFormats
with sbt.internal.bsp.codec.DiagnosticRelatedInformationFormats
with sbt.internal.bsp.codec.ScalaTextEditFormats
with sbt.internal.bsp.codec.ScalaWorkspaceEditFormats
with sbt.internal.bsp.codec.ScalaActionFormats
with sbt.internal.bsp.codec.ScalaDiagnosticFormats
with sbt.internal.bsp.codec.DiagnosticFormats with sbt.internal.bsp.codec.DiagnosticFormats
with sbt.internal.bsp.codec.BuildClientCapabilitiesFormats with sbt.internal.bsp.codec.BuildClientCapabilitiesFormats
with sbt.internal.bsp.codec.InitializeBuildParamsFormats with sbt.internal.bsp.codec.InitializeBuildParamsFormats

View File

@ -0,0 +1,29 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait LocationFormats { self: sbt.internal.bsp.codec.RangeFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val LocationFormat: JsonFormat[sbt.internal.bsp.Location] = new JsonFormat[sbt.internal.bsp.Location] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.Location = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val uri = unbuilder.readField[String]("uri")
val range = unbuilder.readField[sbt.internal.bsp.Range]("range")
unbuilder.endObject()
sbt.internal.bsp.Location(uri, range)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.Location, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("uri", obj.uri)
builder.addField("range", obj.range)
builder.endObject()
}
}
}

View File

@ -0,0 +1,31 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ScalaActionFormats { self: sbt.internal.bsp.codec.ScalaWorkspaceEditFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val ScalaActionFormat: JsonFormat[sbt.internal.bsp.ScalaAction] = new JsonFormat[sbt.internal.bsp.ScalaAction] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.ScalaAction = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val title = unbuilder.readField[String]("title")
val description = unbuilder.readField[Option[String]]("description")
val edit = unbuilder.readField[Option[sbt.internal.bsp.ScalaWorkspaceEdit]]("edit")
unbuilder.endObject()
sbt.internal.bsp.ScalaAction(title, description, edit)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.ScalaAction, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("title", obj.title)
builder.addField("description", obj.description)
builder.addField("edit", obj.edit)
builder.endObject()
}
}
}

View File

@ -0,0 +1,27 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ScalaDiagnosticFormats { self: sbt.internal.bsp.codec.ScalaActionFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val ScalaDiagnosticFormat: JsonFormat[sbt.internal.bsp.ScalaDiagnostic] = new JsonFormat[sbt.internal.bsp.ScalaDiagnostic] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.ScalaDiagnostic = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val actions = unbuilder.readField[Vector[sbt.internal.bsp.ScalaAction]]("actions")
unbuilder.endObject()
sbt.internal.bsp.ScalaDiagnostic(actions)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.ScalaDiagnostic, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("actions", obj.actions)
builder.endObject()
}
}
}

View File

@ -0,0 +1,29 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ScalaTextEditFormats { self: sbt.internal.bsp.codec.RangeFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val ScalaTextEditFormat: JsonFormat[sbt.internal.bsp.ScalaTextEdit] = new JsonFormat[sbt.internal.bsp.ScalaTextEdit] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.ScalaTextEdit = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val range = unbuilder.readField[sbt.internal.bsp.Range]("range")
val newText = unbuilder.readField[String]("newText")
unbuilder.endObject()
sbt.internal.bsp.ScalaTextEdit(range, newText)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.ScalaTextEdit, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("range", obj.range)
builder.addField("newText", obj.newText)
builder.endObject()
}
}
}

View File

@ -0,0 +1,27 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ScalaWorkspaceEditFormats { self: sbt.internal.bsp.codec.ScalaTextEditFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val ScalaWorkspaceEditFormat: JsonFormat[sbt.internal.bsp.ScalaWorkspaceEdit] = new JsonFormat[sbt.internal.bsp.ScalaWorkspaceEdit] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.ScalaWorkspaceEdit = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val changes = unbuilder.readField[Vector[sbt.internal.bsp.ScalaTextEdit]]("changes")
unbuilder.endObject()
sbt.internal.bsp.ScalaWorkspaceEdit(changes)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.ScalaWorkspaceEdit, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("changes", obj.changes)
builder.endObject()
}
}
}

View File

@ -113,6 +113,12 @@ type Range {
end: sbt.internal.bsp.Position! end: sbt.internal.bsp.Position!
} }
## Represents a location inside a resource, such as a line inside a text file.
type Location {
uri: String!
range: sbt.internal.bsp.Range!
}
## Represents a diagnostic, such as a compiler error or warning. ## Represents a diagnostic, such as a compiler error or warning.
## Diagnostic objects are only valid in the scope of a resource. ## Diagnostic objects are only valid in the scope of a resource.
type Diagnostic { type Diagnostic {
@ -132,6 +138,67 @@ type Diagnostic {
## The diagnostic's message. ## The diagnostic's message.
message: String! message: String!
## A list of related diagnostic information, e.g. when symbol-names within
## a scope collide all definitions can be marked via this property.
relatedInformation: [sbt.internal.bsp.DiagnosticRelatedInformation] @since("1.8.0")
## Kind of data to expect in the `data` field. If this field is not set,
## the kind of data is not specified.
dataKind: String @since("1.9.0")
## A data entry field.
data: sbt.internal.bsp.ScalaDiagnostic @since("1.9.0")
}
## Represents a related message and source code location for a diagnostic.
## This should be used to point to code locations that cause or are related to
## a diagnostics, e.g when duplicating a symbol in a scope.
type DiagnosticRelatedInformation {
## The location of this related diagnostic information.
location: sbt.internal.bsp.Location!
## The message of this related diagnostic information.
message: String!
}
## ScalaDiagnostic is a data structure that contains Scala-specific
## metadata generated by Scala compilation. This metadata is
## embedded in the `data: Option[Json]` field of the Diagnostic definition, when
## the dataKind field contains "scala".
type ScalaDiagnostic {
## Actions (also known as quick fixes) that are able to either fix or address
## the issue that is causing this diagnostic.
actions: [sbt.internal.bsp.ScalaAction]
}
## A Scala action represents a change that can be performed in code.
## See also LSP: Code Action Request (https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_codeAction).
type ScalaAction {
## A short, human-readable, title for this code action.
title: String!
## A description that may be shown to the user client side to explain the action.
description: String
## The workspace edit this code action performs.
edit: sbt.internal.bsp.ScalaWorkspaceEdit
}
## A workspace edit represents changes to many resources managed in the workspace.
type ScalaWorkspaceEdit {
changes: [sbt.internal.bsp.ScalaTextEdit]
}
## A textual edit applicable to a text document.
type ScalaTextEdit {
## The range of the text document to be manipulated. To insert
## text into a document create a range where start === end.
range: sbt.internal.bsp.Range!
## The string to be inserted. For delete operations use an
## empty string.
newText: String!
} }
## Initialize Build Request ## Initialize Build Request