Skip to content

Commit f1a3cf1

Browse files
PascalHoneggermjossdev
authored andcommitted
wip: show some diagnostics via LSP
1 parent 16ee92e commit f1a3cf1

File tree

3 files changed

+93
-9
lines changed

3 files changed

+93
-9
lines changed

common/src/main/kotlin/tools/samt/common/Diagnostics.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,6 @@ class DiagnosticMessageBuilder(
153153

154154
fun build(): DiagnosticMessage {
155155
requireNotNull(message)
156-
highlights.sortWith(compareBy({ it.location.start.row }, { it.location.start.col }))
157156
return DiagnosticMessage(severity, message!!, highlights, annotations)
158157
}
159158
}

language-server/src/main/kotlin/tools/samt/ls/SamtLanguageServer.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,17 @@ class SamtLanguageServer : LanguageServer, LanguageClientAware, Closeable {
1212
private val textDocumentService = SamtTextDocumentService()
1313
private val logger = Logger.getLogger("SamtLanguageServer")
1414

15-
override fun initialize(params: InitializeParams): CompletableFuture<InitializeResult> = CompletableFuture.supplyAsync {
16-
val capabilities = ServerCapabilities().apply {
17-
diagnosticProvider = DiagnosticRegistrationOptions(true, false)
15+
override fun initialize(params: InitializeParams): CompletableFuture<InitializeResult> =
16+
CompletableFuture.supplyAsync {
17+
val capabilities = ServerCapabilities().apply {
18+
// TODO support pull-based diagnostics? diagnosticProvider = DiagnosticRegistrationOptions(true, false)
19+
setTextDocumentSync(TextDocumentSyncKind.Full)
20+
}
21+
InitializeResult(capabilities)
1822
}
19-
InitializeResult(capabilities)
23+
24+
override fun setTrace(params: SetTraceParams?) {
25+
// TODO
2026
}
2127

2228
override fun shutdown(): CompletableFuture<Any> = CompletableFuture.completedFuture(null)

language-server/src/main/kotlin/tools/samt/ls/SamtTextDocumentService.kt

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,48 @@ import org.eclipse.lsp4j.*
44
import org.eclipse.lsp4j.services.LanguageClient
55
import org.eclipse.lsp4j.services.LanguageClientAware
66
import org.eclipse.lsp4j.services.TextDocumentService
7-
import java.util.concurrent.CompletableFuture
7+
import tools.samt.common.DiagnosticController
8+
import tools.samt.common.DiagnosticException
9+
import tools.samt.common.DiagnosticMessage
10+
import tools.samt.common.SourceFile
11+
import tools.samt.lexer.Lexer
12+
import tools.samt.parser.Parser
13+
import tools.samt.semantic.SemanticModelBuilder
814
import java.util.logging.Logger
15+
import kotlin.io.path.Path
16+
import kotlin.io.path.readText
17+
import tools.samt.common.DiagnosticSeverity as SamtSeverity
18+
import tools.samt.common.Location as SamtLocation
919

1020
class SamtTextDocumentService : TextDocumentService, LanguageClientAware {
1121
private lateinit var client: LanguageClient
1222
private val logger = Logger.getLogger("SamtTextDocumentService")
1323

1424
override fun didOpen(params: DidOpenTextDocumentParams) {
1525
logger.info("Opened document ${params.textDocument.uri}")
26+
27+
val uri = params.textDocument.uri.removePrefix("file://")
28+
val messages = compile(uri, Path(uri).readText())
29+
30+
client.publishDiagnostics(
31+
PublishDiagnosticsParams(
32+
params.textDocument.uri,
33+
messages.mapNotNull { it.toDiagnostic() })
34+
)
1635
}
1736

1837
override fun didChange(params: DidChangeTextDocumentParams) {
1938
logger.info("Changed document ${params.textDocument.uri}")
39+
40+
val uri = params.textDocument.uri.removePrefix("file://")
41+
val newText = params.contentChanges.firstOrNull()?.text ?: Path(uri).readText()
42+
val messages = compile(uri, newText)
43+
44+
client.publishDiagnostics(
45+
PublishDiagnosticsParams(
46+
params.textDocument.uri,
47+
messages.mapNotNull { it.toDiagnostic() })
48+
)
2049
}
2150

2251
override fun didClose(params: DidCloseTextDocumentParams) {
@@ -27,9 +56,59 @@ class SamtTextDocumentService : TextDocumentService, LanguageClientAware {
2756
logger.info("Saved document ${params.textDocument.uri}")
2857
}
2958

30-
override fun diagnostic(params: DocumentDiagnosticParams): CompletableFuture<DocumentDiagnosticReport> = CompletableFuture.supplyAsync {
31-
logger.info("Diagnostics for document ${params.textDocument.uri}")
32-
DocumentDiagnosticReport(RelatedFullDocumentDiagnosticReport())
59+
private fun SamtLocation.toRange(): Range {
60+
return Range(
61+
Position(start.row, start.col),
62+
Position(start.row, end.col)
63+
)
64+
}
65+
66+
private fun DiagnosticMessage.toDiagnostic(): Diagnostic? {
67+
val diagnostic = Diagnostic()
68+
val primaryHighlight = this.highlights.firstOrNull()
69+
if (primaryHighlight == null) {
70+
logger.warning("Diagnostic message without location, how do I convert this???")
71+
return null
72+
}
73+
// TODO consider highlightBeginningOnly
74+
diagnostic.range = primaryHighlight.location.toRange()
75+
diagnostic.severity = when (severity) {
76+
SamtSeverity.Error -> DiagnosticSeverity.Error
77+
SamtSeverity.Warning -> DiagnosticSeverity.Warning
78+
SamtSeverity.Info -> DiagnosticSeverity.Information
79+
}
80+
diagnostic.source = "samt"
81+
diagnostic.message = message
82+
diagnostic.relatedInformation = highlights.filter { it.message != null }.map {
83+
DiagnosticRelatedInformation(
84+
Location("file://${it.location.source.absolutePath}", it.location.toRange()),
85+
it.message
86+
)
87+
}
88+
return diagnostic
89+
}
90+
91+
private fun compile(uri: String, content: String): List<DiagnosticMessage> {
92+
val source = SourceFile(uri, content)
93+
val controller = DiagnosticController("todo")
94+
val context = controller.createContext(source)
95+
96+
val tokenStream = Lexer.scan(source.content.reader(), context)
97+
98+
if (context.hasErrors()) {
99+
return context.messages
100+
}
101+
102+
val fileNode = try {
103+
Parser.parse(source, tokenStream, context)
104+
} catch (e: DiagnosticException) {
105+
// error message is added to the diagnostic console, so it can be ignored here
106+
return context.messages
107+
}
108+
109+
SemanticModelBuilder.build(listOf(fileNode), controller)
110+
111+
return context.messages
33112
}
34113

35114
override fun connect(client: LanguageClient) {

0 commit comments

Comments
 (0)