diff --git a/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala b/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala index a62f2356d..5ed82ff1d 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala @@ -180,8 +180,7 @@ final class BuildServerReporterImpl( } } - private def toDiagnostic(problem: Problem): Diagnostic = { - val pos = problem.position + private def toRange(pos: XPosition): Range = { val startLineOpt = pos.startLine.toOption.map(_.toLong - 1) val startColumnOpt = pos.startColumn.toOption.map(_.toLong) 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 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( - range, - Option(toDiagnosticSeverity(problem.severity)), - problem.diagnosticCode().toOption.map(_.code), - Option("sbt"), - problem.message + range = toRange(problem.position), + severity = Option(toDiagnosticSeverity(problem.severity)), + code = problem.diagnosticCode().toOption.map(_.code), + source = Option("sbt"), + message = problem.message, + relatedInformation = Vector.empty, + dataKind = data.map { _ => + "scala" + }, + data = data, ) } diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/Diagnostic.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/Diagnostic.scala index a9e2dd10f..da46048cb 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/Diagnostic.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/Diagnostic.scala @@ -14,28 +14,37 @@ package sbt.internal.bsp * @param source A human-readable string describing the source of this diagnostic, e.g. 'typescript' or 'super lint'. * @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 ( val range: sbt.internal.bsp.Range, val severity: Option[Long], val code: 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 { - 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 }) 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 = { - "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 = { - new Diagnostic(range, severity, code, source, message) + 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, relatedInformation, dataKind, data) } def withRange(range: sbt.internal.bsp.Range): Diagnostic = { copy(range = range) @@ -61,9 +70,28 @@ final class Diagnostic private ( def withMessage(message: String): Diagnostic = { 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 { 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: 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)) } diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/DiagnosticRelatedInformation.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/DiagnosticRelatedInformation.scala new file mode 100644 index 000000000..c048fba0c --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/DiagnosticRelatedInformation.scala @@ -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) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/Location.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/Location.scala new file mode 100644 index 000000000..1ee36e2be --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/Location.scala @@ -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) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaAction.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaAction.scala new file mode 100644 index 000000000..f608dbba9 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaAction.scala @@ -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)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaDiagnostic.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaDiagnostic.scala new file mode 100644 index 000000000..8774922d7 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaDiagnostic.scala @@ -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) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaTextEdit.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaTextEdit.scala new file mode 100644 index 000000000..33f7be6a3 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaTextEdit.scala @@ -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) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaWorkspaceEdit.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaWorkspaceEdit.scala new file mode 100644 index 000000000..6c6f59328 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaWorkspaceEdit.scala @@ -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) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DiagnosticFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DiagnosticFormats.scala index 64a3a224b..0e0291d9f 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DiagnosticFormats.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DiagnosticFormats.scala @@ -5,7 +5,7 @@ // DO NOT EDIT MANUALLY package sbt.internal.bsp.codec 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] { override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.Diagnostic = { __jsOpt match { @@ -16,8 +16,11 @@ implicit lazy val DiagnosticFormat: JsonFormat[sbt.internal.bsp.Diagnostic] = ne val code = unbuilder.readField[Option[String]]("code") val source = unbuilder.readField[Option[String]]("source") 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() - sbt.internal.bsp.Diagnostic(range, severity, code, source, message) + sbt.internal.bsp.Diagnostic(range, severity, code, source, message, relatedInformation, dataKind, data) case 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("source", obj.source) builder.addField("message", obj.message) + builder.addField("relatedInformation", obj.relatedInformation) + builder.addField("dataKind", obj.dataKind) + builder.addField("data", obj.data) builder.endObject() } } diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DiagnosticRelatedInformationFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DiagnosticRelatedInformationFormats.scala new file mode 100644 index 000000000..7886ec851 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DiagnosticRelatedInformationFormats.scala @@ -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() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala index 5c087e4b4..3a3ff0906 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala @@ -15,6 +15,12 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol with sbt.internal.bsp.codec.TextDocumentIdentifierFormats with sbt.internal.bsp.codec.PositionFormats 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.BuildClientCapabilitiesFormats with sbt.internal.bsp.codec.InitializeBuildParamsFormats diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/LocationFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/LocationFormats.scala new file mode 100644 index 000000000..54da58361 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/LocationFormats.scala @@ -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() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaActionFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaActionFormats.scala new file mode 100644 index 000000000..6df072a38 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaActionFormats.scala @@ -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() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaDiagnosticFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaDiagnosticFormats.scala new file mode 100644 index 000000000..081333352 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaDiagnosticFormats.scala @@ -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() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaTextEditFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaTextEditFormats.scala new file mode 100644 index 000000000..320ff8a55 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaTextEditFormats.scala @@ -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() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaWorkspaceEditFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaWorkspaceEditFormats.scala new file mode 100644 index 000000000..6e09a05af --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaWorkspaceEditFormats.scala @@ -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() + } +} +} diff --git a/protocol/src/main/contraband/bsp.contra b/protocol/src/main/contraband/bsp.contra index d5f0beec5..e0f2fd36f 100644 --- a/protocol/src/main/contraband/bsp.contra +++ b/protocol/src/main/contraband/bsp.contra @@ -113,6 +113,12 @@ type Range { 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. ## Diagnostic objects are only valid in the scope of a resource. type Diagnostic { @@ -132,6 +138,67 @@ type Diagnostic { ## The diagnostic's message. 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