implements PLN-0067
This commit is contained in:
parent
18dc64e36c
commit
f6774ef568
@ -1,5 +1,5 @@
|
|||||||
{"type":"meta","next_id":{"DSC":33,"AGD":36,"DEC":33,"PLN":68,"LSN":47,"CLSN":1}}
|
{"type":"meta","next_id":{"DSC":33,"AGD":36,"DEC":33,"PLN":68,"LSN":47,"CLSN":1}}
|
||||||
{"type":"discussion","id":"DSC-0032","status":"in_progress","ticket":"studio-new-lsp-api-and-v1-boundary","title":"Novo boundary entre lsp-api, lsp-v1 e a extensao VS Code","created_at":"2026-05-05","updated_at":"2026-05-05","tags":["studio","lsp","vscode","protocol","api","boundary"],"agendas":[{"id":"AGD-0035","file":"AGD-0035-studio-new-lsp-api-and-v1-boundary.md","status":"accepted","created_at":"2026-05-05","updated_at":"2026-05-05"}],"decisions":[{"id":"DEC-0032","file":"DEC-0032-studio-new-lsp-api-and-v1-boundary.md","status":"accepted","created_at":"2026-05-05","updated_at":"2026-05-05","ref_agenda":"AGD-0035"}],"plans":[{"id":"PLN-0065","file":"PLN-0065-lsp-boundary-and-module-scaffolding.md","status":"done","created_at":"2026-05-05","updated_at":"2026-05-05","ref_decisions":["DEC-0032"]},{"id":"PLN-0066","file":"PLN-0066-project-scoped-lsp-server-lifecycle-in-studio.md","status":"done","created_at":"2026-05-05","updated_at":"2026-05-05","ref_decisions":["DEC-0032"]},{"id":"PLN-0067","file":"PLN-0067-compiler-backed-dumb-lsp-server-baseline.md","status":"open","created_at":"2026-05-05","updated_at":"2026-05-05","ref_decisions":["DEC-0032"]}],"lessons":[]}
|
{"type":"discussion","id":"DSC-0032","status":"in_progress","ticket":"studio-new-lsp-api-and-v1-boundary","title":"Novo boundary entre lsp-api, lsp-v1 e a extensao VS Code","created_at":"2026-05-05","updated_at":"2026-05-05","tags":["studio","lsp","vscode","protocol","api","boundary"],"agendas":[{"id":"AGD-0035","file":"AGD-0035-studio-new-lsp-api-and-v1-boundary.md","status":"accepted","created_at":"2026-05-05","updated_at":"2026-05-05"}],"decisions":[{"id":"DEC-0032","file":"DEC-0032-studio-new-lsp-api-and-v1-boundary.md","status":"accepted","created_at":"2026-05-05","updated_at":"2026-05-05","ref_agenda":"AGD-0035"}],"plans":[{"id":"PLN-0065","file":"PLN-0065-lsp-boundary-and-module-scaffolding.md","status":"done","created_at":"2026-05-05","updated_at":"2026-05-05","ref_decisions":["DEC-0032"]},{"id":"PLN-0066","file":"PLN-0066-project-scoped-lsp-server-lifecycle-in-studio.md","status":"done","created_at":"2026-05-05","updated_at":"2026-05-05","ref_decisions":["DEC-0032"]},{"id":"PLN-0067","file":"PLN-0067-compiler-backed-dumb-lsp-server-baseline.md","status":"done","created_at":"2026-05-05","updated_at":"2026-05-05","ref_decisions":["DEC-0032"]}],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0031","status":"in_progress","ticket":"studio-editor-workspace-cleanup","title":"Limpeza completa do Workspace Editor do Studio e remoção dos acoplamentos legados","created_at":"2026-05-05","updated_at":"2026-05-05","tags":["studio","editor","cleanup","vfs","lsp","migration"],"agendas":[{"id":"AGD-0034","file":"AGD-0034-vscode-editor-migration-feasibility.md","status":"accepted","created_at":"2026-05-05","updated_at":"2026-05-05"}],"decisions":[{"id":"DEC-0031","file":"DEC-0031-studio-editor-workspace-cleanup.md","status":"in_progress","created_at":"2026-05-05","updated_at":"2026-05-05","ref_agenda":"AGD-0034"}],"plans":[{"id":"PLN-0062","file":"PLN-0062-shell-session-and-state-cleanup-after-editor-removal.md","status":"done","created_at":"2026-05-05","updated_at":"2026-05-05","ref_decisions":["DEC-0031"]},{"id":"PLN-0063","file":"PLN-0063-legacy-lsp-and-vfs-module-removal-with-runtime-preservation.md","status":"done","created_at":"2026-05-05","updated_at":"2026-05-05","ref_decisions":["DEC-0031"]},{"id":"PLN-0064","file":"PLN-0064-normative-test-and-lesson-cleanup-for-editor-stack-removal.md","status":"done","created_at":"2026-05-05","updated_at":"2026-05-05","ref_decisions":["DEC-0031"]}],"lessons":[]}
|
{"type":"discussion","id":"DSC-0031","status":"in_progress","ticket":"studio-editor-workspace-cleanup","title":"Limpeza completa do Workspace Editor do Studio e remoção dos acoplamentos legados","created_at":"2026-05-05","updated_at":"2026-05-05","tags":["studio","editor","cleanup","vfs","lsp","migration"],"agendas":[{"id":"AGD-0034","file":"AGD-0034-vscode-editor-migration-feasibility.md","status":"accepted","created_at":"2026-05-05","updated_at":"2026-05-05"}],"decisions":[{"id":"DEC-0031","file":"DEC-0031-studio-editor-workspace-cleanup.md","status":"in_progress","created_at":"2026-05-05","updated_at":"2026-05-05","ref_agenda":"AGD-0034"}],"plans":[{"id":"PLN-0062","file":"PLN-0062-shell-session-and-state-cleanup-after-editor-removal.md","status":"done","created_at":"2026-05-05","updated_at":"2026-05-05","ref_decisions":["DEC-0031"]},{"id":"PLN-0063","file":"PLN-0063-legacy-lsp-and-vfs-module-removal-with-runtime-preservation.md","status":"done","created_at":"2026-05-05","updated_at":"2026-05-05","ref_decisions":["DEC-0031"]},{"id":"PLN-0064","file":"PLN-0064-normative-test-and-lesson-cleanup-for-editor-stack-removal.md","status":"done","created_at":"2026-05-05","updated_at":"2026-05-05","ref_decisions":["DEC-0031"]}],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0030","status":"done","ticket":"studio-scene-pack-runtime-binary-contract","title":"Studio scene pack contract for runtime SCENE binary payload","created_at":"2026-04-24","updated_at":"2026-05-01","tags":["studio","packer","runtime","scene","asset-pack","binary-format","tiled"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0046","file":"discussion/lessons/DSC-0030-studio-scene-pack-runtime-binary-contract/LSN-0046-canonical-scene-owns-editorial-truth-while-pack-stays-request-driven.md","status":"done","created_at":"2026-05-01","updated_at":"2026-05-01"}]}
|
{"type":"discussion","id":"DSC-0030","status":"done","ticket":"studio-scene-pack-runtime-binary-contract","title":"Studio scene pack contract for runtime SCENE binary payload","created_at":"2026-04-24","updated_at":"2026-05-01","tags":["studio","packer","runtime","scene","asset-pack","binary-format","tiled"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0046","file":"discussion/lessons/DSC-0030-studio-scene-pack-runtime-binary-contract/LSN-0046-canonical-scene-owns-editorial-truth-while-pack-stays-request-driven.md","status":"done","created_at":"2026-05-01","updated_at":"2026-05-01"}]}
|
||||||
{"type":"discussion","id":"DSC-0029","status":"done","ticket":"studio-frame-composer-syscall-and-sprite-alignment","title":"Studio Alignment with Runtime FrameComposer Syscalls and Sprite Composition","created_at":"2026-04-18","updated_at":"2026-04-18","tags":["studio","compiler","pbs","stdlib","runtime-alignment","abi","syscall","frame-composer","sprites"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0041","file":"discussion/lessons/DSC-0029-studio-frame-composer-syscall-and-sprite-alignment/LSN-0041-composer-must-own-public-sprite-composition.md","status":"done","created_at":"2026-04-18","updated_at":"2026-04-18"}]}
|
{"type":"discussion","id":"DSC-0029","status":"done","ticket":"studio-frame-composer-syscall-and-sprite-alignment","title":"Studio Alignment with Runtime FrameComposer Syscalls and Sprite Composition","created_at":"2026-04-18","updated_at":"2026-04-18","tags":["studio","compiler","pbs","stdlib","runtime-alignment","abi","syscall","frame-composer","sprites"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0041","file":"discussion/lessons/DSC-0029-studio-frame-composer-syscall-and-sprite-alignment/LSN-0041-composer-must-own-public-sprite-composition.md","status":"done","created_at":"2026-04-18","updated_at":"2026-04-18"}]}
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
id: PLN-0067
|
id: PLN-0067
|
||||||
ticket: studio-new-lsp-api-and-v1-boundary
|
ticket: studio-new-lsp-api-and-v1-boundary
|
||||||
title: Compiler-Backed Dumb LSP Server Baseline
|
title: Compiler-Backed Dumb LSP Server Baseline
|
||||||
status: open
|
status: done
|
||||||
created: 2026-05-05
|
created: 2026-05-05
|
||||||
completed:
|
completed: 2026-05-05
|
||||||
tags: [studio, lsp, compiler, baseline, protocol, vscode]
|
tags: [studio, lsp, compiler, baseline, protocol, vscode]
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -81,11 +81,11 @@ Establish a maintainable, compiler-backed baseline inside `lsp-v1` that keeps th
|
|||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
- [ ] `lsp-v1` talks to `compiler` through explicit bridge services.
|
- [x] `lsp-v1` talks to `compiler` through explicit bridge services.
|
||||||
- [ ] The baseline server behavior remains intentionally simple but structurally clean.
|
- [x] The baseline server behavior remains intentionally simple but structurally clean.
|
||||||
- [ ] At least one minimal end-to-end capability slice proves the final layering.
|
- [x] At least one minimal end-to-end capability slice proves the final layering.
|
||||||
- [ ] The extension can still connect over TCP without protocol regressions.
|
- [x] The extension can still connect over TCP without protocol regressions.
|
||||||
- [ ] Temporary semantic limits are explicit in tests and code structure.
|
- [x] Temporary semantic limits are explicit in tests and code structure.
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
package p.studio.lsp.v1.compiler;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public record BaselineDocumentAnalysis(
|
||||||
|
List<BaselineDocumentIssue> issues) {
|
||||||
|
|
||||||
|
public BaselineDocumentAnalysis {
|
||||||
|
issues = List.copyOf(Objects.requireNonNull(issues, "issues"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package p.studio.lsp.v1.compiler;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public record BaselineDocumentIssue(
|
||||||
|
int startLine,
|
||||||
|
int startCharacter,
|
||||||
|
int endLine,
|
||||||
|
int endCharacter,
|
||||||
|
BaselineIssueSeverity severity,
|
||||||
|
String source,
|
||||||
|
String message) {
|
||||||
|
|
||||||
|
public BaselineDocumentIssue {
|
||||||
|
severity = Objects.requireNonNull(severity, "severity");
|
||||||
|
source = requireText(source, "source");
|
||||||
|
message = requireText(message, "message");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String requireText(
|
||||||
|
final String value,
|
||||||
|
final String field) {
|
||||||
|
final String candidate = Objects.requireNonNull(value, field).trim();
|
||||||
|
if (candidate.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException(field + " must not be blank");
|
||||||
|
}
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package p.studio.lsp.v1.compiler;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public record BaselineHover(
|
||||||
|
String markdown) {
|
||||||
|
|
||||||
|
public BaselineHover {
|
||||||
|
final String candidate = Objects.requireNonNull(markdown, "markdown").trim();
|
||||||
|
if (candidate.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("markdown must not be blank");
|
||||||
|
}
|
||||||
|
markdown = candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package p.studio.lsp.v1.compiler;
|
||||||
|
|
||||||
|
public enum BaselineIssueSeverity {
|
||||||
|
INFORMATION,
|
||||||
|
WARNING,
|
||||||
|
ERROR
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package p.studio.lsp.v1.compiler;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public record BaselineServerDescription(
|
||||||
|
String name,
|
||||||
|
String version,
|
||||||
|
boolean hoverSupported) {
|
||||||
|
|
||||||
|
public BaselineServerDescription {
|
||||||
|
name = requireText(name, "name");
|
||||||
|
version = requireText(version, "version");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String requireText(
|
||||||
|
final String value,
|
||||||
|
final String field) {
|
||||||
|
final String candidate = Objects.requireNonNull(value, field).trim();
|
||||||
|
if (candidate.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException(field + " must not be blank");
|
||||||
|
}
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,11 @@
|
|||||||
package p.studio.lsp.v1.compiler;
|
package p.studio.lsp.v1.compiler;
|
||||||
|
|
||||||
import p.studio.compiler.workspaces.BuilderPipelineService;
|
import p.studio.compiler.workspaces.BuilderPipelineService;
|
||||||
|
import p.studio.lsp.api.LspProjectContext;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public final class CompilerLanguageServiceBridge {
|
public final class CompilerLanguageServiceBridge implements LanguageServiceBridge {
|
||||||
private final BuilderPipelineService builderPipelineService;
|
private final BuilderPipelineService builderPipelineService;
|
||||||
|
|
||||||
public CompilerLanguageServiceBridge() {
|
public CompilerLanguageServiceBridge() {
|
||||||
@ -18,4 +19,63 @@ public final class CompilerLanguageServiceBridge {
|
|||||||
public BuilderPipelineService builderPipelineService() {
|
public BuilderPipelineService builderPipelineService() {
|
||||||
return builderPipelineService;
|
return builderPipelineService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaselineServerDescription describeServer(final LspProjectContext project) {
|
||||||
|
Objects.requireNonNull(project, "project");
|
||||||
|
return new BaselineServerDescription(
|
||||||
|
"Prometeu Studio LSP",
|
||||||
|
"0.1.0",
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaselineDocumentAnalysis analyzeDocument(
|
||||||
|
final LspProjectContext project,
|
||||||
|
final String documentUri,
|
||||||
|
final String text) {
|
||||||
|
Objects.requireNonNull(project, "project");
|
||||||
|
// Wave 1 keeps responses intentionally synthetic while hardening the bridge boundary.
|
||||||
|
final String message = "Compiler-backed baseline via " + builderPipelineService.getClass().getSimpleName();
|
||||||
|
return new BaselineDocumentAnalysis(java.util.List.of(new BaselineDocumentIssue(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
Math.max(1, firstLineLength(text)),
|
||||||
|
BaselineIssueSeverity.INFORMATION,
|
||||||
|
"Prometeu Studio",
|
||||||
|
message)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaselineHover hover(
|
||||||
|
final LspProjectContext project,
|
||||||
|
final String documentUri,
|
||||||
|
final int line,
|
||||||
|
final int character) {
|
||||||
|
Objects.requireNonNull(project, "project");
|
||||||
|
return new BaselineHover("""
|
||||||
|
**Prometeu Studio LSP**
|
||||||
|
|
||||||
|
Compiler-backed baseline.
|
||||||
|
|
||||||
|
Semantic enrichment will be layered later.
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String onSave(
|
||||||
|
final LspProjectContext project,
|
||||||
|
final String documentUri) {
|
||||||
|
Objects.requireNonNull(project, "project");
|
||||||
|
return "Prometeu Studio saw save: " + documentUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int firstLineLength(final String text) {
|
||||||
|
if (text == null || text.isEmpty()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
final int newline = text.indexOf('\n');
|
||||||
|
return newline < 0 ? text.length() : newline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
package p.studio.lsp.v1.compiler;
|
||||||
|
|
||||||
|
import p.studio.lsp.api.LspProjectContext;
|
||||||
|
|
||||||
|
public interface LanguageServiceBridge {
|
||||||
|
BaselineServerDescription describeServer(LspProjectContext project);
|
||||||
|
|
||||||
|
BaselineDocumentAnalysis analyzeDocument(LspProjectContext project, String documentUri, String text);
|
||||||
|
|
||||||
|
BaselineHover hover(LspProjectContext project, String documentUri, int line, int character);
|
||||||
|
|
||||||
|
String onSave(LspProjectContext project, String documentUri);
|
||||||
|
}
|
||||||
@ -8,16 +8,17 @@ import org.eclipse.lsp4j.services.TextDocumentService;
|
|||||||
import org.eclipse.lsp4j.services.WorkspaceService;
|
import org.eclipse.lsp4j.services.WorkspaceService;
|
||||||
import p.studio.lsp.api.LspProjectContext;
|
import p.studio.lsp.api.LspProjectContext;
|
||||||
import p.studio.lsp.v1.compiler.CompilerLanguageServiceBridge;
|
import p.studio.lsp.v1.compiler.CompilerLanguageServiceBridge;
|
||||||
import p.studio.lsp.v1.protocol.mapping.ProtocolServerProfile;
|
import p.studio.lsp.v1.compiler.LanguageServiceBridge;
|
||||||
import p.studio.lsp.v1.protocol.mapping.ServerCapabilitiesMapper;
|
import p.studio.lsp.v1.protocol.mapping.Lsp4jProtocolMessageMapper;
|
||||||
|
import p.studio.lsp.v1.protocol.mapping.ProtocolMessageMapper;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public final class PrometeuLanguageServer implements LanguageServer, LanguageClientAware {
|
public final class PrometeuLanguageServer implements LanguageServer, LanguageClientAware {
|
||||||
private final LspProjectContext project;
|
private final LspProjectContext project;
|
||||||
private final CompilerLanguageServiceBridge compilerBridge;
|
private final LanguageServiceBridge languageServiceBridge;
|
||||||
private final ServerCapabilitiesMapper capabilitiesMapper;
|
private final ProtocolMessageMapper protocolMessageMapper;
|
||||||
private final TextDocumentService textDocumentService;
|
private final TextDocumentService textDocumentService;
|
||||||
private final WorkspaceService workspaceService;
|
private final WorkspaceService workspaceService;
|
||||||
private volatile LanguageClient client;
|
private volatile LanguageClient client;
|
||||||
@ -28,21 +29,23 @@ public final class PrometeuLanguageServer implements LanguageServer, LanguageCli
|
|||||||
final CompilerLanguageServiceBridge compilerBridge) {
|
final CompilerLanguageServiceBridge compilerBridge) {
|
||||||
this(project,
|
this(project,
|
||||||
compilerBridge,
|
compilerBridge,
|
||||||
new ServerCapabilitiesMapper(),
|
new Lsp4jProtocolMessageMapper(),
|
||||||
new PrometeuTextDocumentService(),
|
null,
|
||||||
new PrometeuWorkspaceService());
|
new PrometeuWorkspaceService());
|
||||||
}
|
}
|
||||||
|
|
||||||
PrometeuLanguageServer(
|
PrometeuLanguageServer(
|
||||||
final LspProjectContext project,
|
final LspProjectContext project,
|
||||||
final CompilerLanguageServiceBridge compilerBridge,
|
final LanguageServiceBridge languageServiceBridge,
|
||||||
final ServerCapabilitiesMapper capabilitiesMapper,
|
final ProtocolMessageMapper protocolMessageMapper,
|
||||||
final TextDocumentService textDocumentService,
|
final TextDocumentService textDocumentService,
|
||||||
final WorkspaceService workspaceService) {
|
final WorkspaceService workspaceService) {
|
||||||
this.project = Objects.requireNonNull(project, "project");
|
this.project = Objects.requireNonNull(project, "project");
|
||||||
this.compilerBridge = Objects.requireNonNull(compilerBridge, "compilerBridge");
|
this.languageServiceBridge = Objects.requireNonNull(languageServiceBridge, "languageServiceBridge");
|
||||||
this.capabilitiesMapper = Objects.requireNonNull(capabilitiesMapper, "capabilitiesMapper");
|
this.protocolMessageMapper = Objects.requireNonNull(protocolMessageMapper, "protocolMessageMapper");
|
||||||
this.textDocumentService = Objects.requireNonNull(textDocumentService, "textDocumentService");
|
this.textDocumentService = textDocumentService != null
|
||||||
|
? textDocumentService
|
||||||
|
: new PrometeuTextDocumentService(project, languageServiceBridge, protocolMessageMapper);
|
||||||
this.workspaceService = Objects.requireNonNull(workspaceService, "workspaceService");
|
this.workspaceService = Objects.requireNonNull(workspaceService, "workspaceService");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,8 +59,8 @@ public final class PrometeuLanguageServer implements LanguageServer, LanguageCli
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<InitializeResult> initialize(final InitializeParams params) {
|
public CompletableFuture<InitializeResult> initialize(final InitializeParams params) {
|
||||||
final ProtocolServerProfile profile = ProtocolServerProfile.defaults();
|
return CompletableFuture.completedFuture(protocolMessageMapper.mapInitializeResult(
|
||||||
return CompletableFuture.completedFuture(capabilitiesMapper.map(profile));
|
languageServiceBridge.describeServer(project)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -66,8 +69,7 @@ public final class PrometeuLanguageServer implements LanguageServer, LanguageCli
|
|||||||
if (currentClient == null) {
|
if (currentClient == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentClient.logMessage(new MessageParams(
|
currentClient.logMessage(protocolMessageMapper.mapInfoMessage(
|
||||||
MessageType.Info,
|
|
||||||
"Prometeu Studio LSP connected for project " + project.projectKey()));
|
"Prometeu Studio LSP connected for project " + project.projectKey()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,8 +84,7 @@ public final class PrometeuLanguageServer implements LanguageServer, LanguageCli
|
|||||||
if (!shutdownRequested) {
|
if (!shutdownRequested) {
|
||||||
final LanguageClient currentClient = client;
|
final LanguageClient currentClient = client;
|
||||||
if (currentClient != null) {
|
if (currentClient != null) {
|
||||||
currentClient.logMessage(new MessageParams(
|
currentClient.logMessage(new MessageParams(MessageType.Warning,
|
||||||
MessageType.Warning,
|
|
||||||
"Prometeu Studio LSP received exit before shutdown"));
|
"Prometeu Studio LSP received exit before shutdown"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,20 +3,35 @@ package p.studio.lsp.v1.protocol;
|
|||||||
import org.eclipse.lsp4j.*;
|
import org.eclipse.lsp4j.*;
|
||||||
import org.eclipse.lsp4j.services.LanguageClient;
|
import org.eclipse.lsp4j.services.LanguageClient;
|
||||||
import org.eclipse.lsp4j.services.TextDocumentService;
|
import org.eclipse.lsp4j.services.TextDocumentService;
|
||||||
|
import p.studio.lsp.api.LspProjectContext;
|
||||||
|
import p.studio.lsp.v1.compiler.LanguageServiceBridge;
|
||||||
|
import p.studio.lsp.v1.protocol.mapping.ProtocolMessageMapper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public final class PrometeuTextDocumentService implements TextDocumentService {
|
public final class PrometeuTextDocumentService implements TextDocumentService {
|
||||||
|
private final LspProjectContext project;
|
||||||
|
private final LanguageServiceBridge languageServiceBridge;
|
||||||
|
private final ProtocolMessageMapper protocolMessageMapper;
|
||||||
private volatile LanguageClient client;
|
private volatile LanguageClient client;
|
||||||
|
|
||||||
|
public PrometeuTextDocumentService(
|
||||||
|
final LspProjectContext project,
|
||||||
|
final LanguageServiceBridge languageServiceBridge,
|
||||||
|
final ProtocolMessageMapper protocolMessageMapper) {
|
||||||
|
this.project = Objects.requireNonNull(project, "project");
|
||||||
|
this.languageServiceBridge = Objects.requireNonNull(languageServiceBridge, "languageServiceBridge");
|
||||||
|
this.protocolMessageMapper = Objects.requireNonNull(protocolMessageMapper, "protocolMessageMapper");
|
||||||
|
}
|
||||||
|
|
||||||
void connect(final LanguageClient client) {
|
void connect(final LanguageClient client) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void didOpen(final DidOpenTextDocumentParams params) {
|
public void didOpen(final DidOpenTextDocumentParams params) {
|
||||||
publishHelloDiagnostic(params.getTextDocument().getUri(), params.getTextDocument().getText());
|
publishAnalysis(params.getTextDocument().getUri(), params.getTextDocument().getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -24,7 +39,7 @@ public final class PrometeuTextDocumentService implements TextDocumentService {
|
|||||||
final String text = params.getContentChanges().isEmpty()
|
final String text = params.getContentChanges().isEmpty()
|
||||||
? ""
|
? ""
|
||||||
: params.getContentChanges().getFirst().getText();
|
: params.getContentChanges().getFirst().getText();
|
||||||
publishHelloDiagnostic(params.getTextDocument().getUri(), text);
|
publishAnalysis(params.getTextDocument().getUri(), text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -33,7 +48,7 @@ public final class PrometeuTextDocumentService implements TextDocumentService {
|
|||||||
if (currentClient == null) {
|
if (currentClient == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentClient.publishDiagnostics(new PublishDiagnosticsParams(params.getTextDocument().getUri(), List.of()));
|
currentClient.publishDiagnostics(protocolMessageMapper.emptyDiagnostics(params.getTextDocument().getUri()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -42,52 +57,28 @@ public final class PrometeuTextDocumentService implements TextDocumentService {
|
|||||||
if (currentClient == null) {
|
if (currentClient == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentClient.logMessage(new MessageParams(
|
currentClient.logMessage(protocolMessageMapper.mapInfoMessage(
|
||||||
MessageType.Info,
|
languageServiceBridge.onSave(project, params.getTextDocument().getUri())));
|
||||||
"Prometeu Studio saw save: " + params.getTextDocument().getUri()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Hover> hover(final HoverParams params) {
|
public CompletableFuture<Hover> hover(final HoverParams params) {
|
||||||
final MarkupContent content = new MarkupContent();
|
return CompletableFuture.completedFuture(protocolMessageMapper.mapHover(languageServiceBridge.hover(
|
||||||
content.setKind(MarkupKind.MARKDOWN);
|
project,
|
||||||
content.setValue("""
|
params.getTextDocument().getUri(),
|
||||||
**Prometeu Studio LSP**
|
params.getPosition().getLine(),
|
||||||
|
params.getPosition().getCharacter())));
|
||||||
Structured baseline server.
|
|
||||||
|
|
||||||
Semantic enrichment will be layered later.
|
|
||||||
""");
|
|
||||||
|
|
||||||
final Hover hover = new Hover();
|
|
||||||
hover.setContents(content);
|
|
||||||
return CompletableFuture.completedFuture(hover);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void publishHelloDiagnostic(
|
private void publishAnalysis(
|
||||||
final String uri,
|
final String uri,
|
||||||
final String text) {
|
final String text) {
|
||||||
final LanguageClient currentClient = client;
|
final LanguageClient currentClient = client;
|
||||||
if (currentClient == null) {
|
if (currentClient == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
currentClient.publishDiagnostics(protocolMessageMapper.mapDiagnostics(
|
||||||
final Diagnostic diagnostic = new Diagnostic();
|
uri,
|
||||||
diagnostic.setRange(new Range(
|
languageServiceBridge.analyzeDocument(project, uri, text)));
|
||||||
new Position(0, 0),
|
|
||||||
new Position(0, Math.max(1, firstLineLength(text)))));
|
|
||||||
diagnostic.setSeverity(DiagnosticSeverity.Information);
|
|
||||||
diagnostic.setSource("Prometeu Studio");
|
|
||||||
diagnostic.setMessage("Structured baseline LSP response");
|
|
||||||
|
|
||||||
currentClient.publishDiagnostics(new PublishDiagnosticsParams(uri, List.of(diagnostic)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private int firstLineLength(final String text) {
|
|
||||||
if (text == null || text.isEmpty()) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
final int newline = text.indexOf('\n');
|
|
||||||
return newline < 0 ? text.length() : newline;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,78 @@
|
|||||||
|
package p.studio.lsp.v1.protocol.mapping;
|
||||||
|
|
||||||
|
import org.eclipse.lsp4j.*;
|
||||||
|
import p.studio.lsp.v1.compiler.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public final class Lsp4jProtocolMessageMapper implements ProtocolMessageMapper {
|
||||||
|
@Override
|
||||||
|
public InitializeResult mapInitializeResult(final BaselineServerDescription description) {
|
||||||
|
final ServerCapabilities capabilities = new ServerCapabilities();
|
||||||
|
|
||||||
|
final TextDocumentSyncOptions syncOptions = new TextDocumentSyncOptions();
|
||||||
|
syncOptions.setOpenClose(true);
|
||||||
|
syncOptions.setChange(TextDocumentSyncKind.Full);
|
||||||
|
|
||||||
|
final SaveOptions saveOptions = new SaveOptions();
|
||||||
|
saveOptions.setIncludeText(true);
|
||||||
|
syncOptions.setSave(saveOptions);
|
||||||
|
|
||||||
|
capabilities.setTextDocumentSync(syncOptions);
|
||||||
|
capabilities.setHoverProvider(description.hoverSupported());
|
||||||
|
|
||||||
|
final InitializeResult result = new InitializeResult(capabilities);
|
||||||
|
final ServerInfo serverInfo = new ServerInfo();
|
||||||
|
serverInfo.setName(description.name());
|
||||||
|
serverInfo.setVersion(description.version());
|
||||||
|
result.setServerInfo(serverInfo);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PublishDiagnosticsParams mapDiagnostics(
|
||||||
|
final String uri,
|
||||||
|
final BaselineDocumentAnalysis analysis) {
|
||||||
|
return new PublishDiagnosticsParams(uri, analysis.issues().stream().map(this::mapDiagnostic).toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PublishDiagnosticsParams emptyDiagnostics(final String uri) {
|
||||||
|
return new PublishDiagnosticsParams(uri, List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Hover mapHover(final BaselineHover hover) {
|
||||||
|
final MarkupContent content = new MarkupContent();
|
||||||
|
content.setKind(MarkupKind.MARKDOWN);
|
||||||
|
content.setValue(hover.markdown());
|
||||||
|
|
||||||
|
final Hover result = new Hover();
|
||||||
|
result.setContents(content);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MessageParams mapInfoMessage(final String message) {
|
||||||
|
return new MessageParams(MessageType.Info, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Diagnostic mapDiagnostic(final BaselineDocumentIssue issue) {
|
||||||
|
final Diagnostic diagnostic = new Diagnostic();
|
||||||
|
diagnostic.setRange(new Range(
|
||||||
|
new Position(issue.startLine(), issue.startCharacter()),
|
||||||
|
new Position(issue.endLine(), issue.endCharacter())));
|
||||||
|
diagnostic.setSeverity(mapSeverity(issue.severity()));
|
||||||
|
diagnostic.setSource(issue.source());
|
||||||
|
diagnostic.setMessage(issue.message());
|
||||||
|
return diagnostic;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DiagnosticSeverity mapSeverity(final BaselineIssueSeverity severity) {
|
||||||
|
return switch (severity) {
|
||||||
|
case INFORMATION -> DiagnosticSeverity.Information;
|
||||||
|
case WARNING -> DiagnosticSeverity.Warning;
|
||||||
|
case ERROR -> DiagnosticSeverity.Error;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package p.studio.lsp.v1.protocol.mapping;
|
||||||
|
|
||||||
|
import org.eclipse.lsp4j.Hover;
|
||||||
|
import org.eclipse.lsp4j.InitializeResult;
|
||||||
|
import org.eclipse.lsp4j.MessageParams;
|
||||||
|
import org.eclipse.lsp4j.PublishDiagnosticsParams;
|
||||||
|
import p.studio.lsp.v1.compiler.BaselineDocumentAnalysis;
|
||||||
|
import p.studio.lsp.v1.compiler.BaselineHover;
|
||||||
|
import p.studio.lsp.v1.compiler.BaselineServerDescription;
|
||||||
|
|
||||||
|
public interface ProtocolMessageMapper {
|
||||||
|
InitializeResult mapInitializeResult(BaselineServerDescription description);
|
||||||
|
|
||||||
|
PublishDiagnosticsParams mapDiagnostics(String uri, BaselineDocumentAnalysis analysis);
|
||||||
|
|
||||||
|
PublishDiagnosticsParams emptyDiagnostics(String uri);
|
||||||
|
|
||||||
|
Hover mapHover(BaselineHover hover);
|
||||||
|
|
||||||
|
MessageParams mapInfoMessage(String message);
|
||||||
|
}
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package p.studio.lsp.v1.protocol.mapping;
|
|
||||||
|
|
||||||
public record ProtocolServerProfile(
|
|
||||||
String name,
|
|
||||||
String version,
|
|
||||||
boolean hoverSupported) {
|
|
||||||
|
|
||||||
public static ProtocolServerProfile defaults() {
|
|
||||||
return new ProtocolServerProfile("Prometeu Studio LSP", "0.1.0", true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
package p.studio.lsp.v1.protocol.mapping;
|
|
||||||
|
|
||||||
import org.eclipse.lsp4j.*;
|
|
||||||
|
|
||||||
public final class ServerCapabilitiesMapper {
|
|
||||||
public InitializeResult map(final ProtocolServerProfile profile) {
|
|
||||||
final ServerCapabilities capabilities = new ServerCapabilities();
|
|
||||||
|
|
||||||
final TextDocumentSyncOptions syncOptions = new TextDocumentSyncOptions();
|
|
||||||
syncOptions.setOpenClose(true);
|
|
||||||
syncOptions.setChange(TextDocumentSyncKind.Full);
|
|
||||||
|
|
||||||
final SaveOptions saveOptions = new SaveOptions();
|
|
||||||
saveOptions.setIncludeText(true);
|
|
||||||
syncOptions.setSave(saveOptions);
|
|
||||||
|
|
||||||
capabilities.setTextDocumentSync(syncOptions);
|
|
||||||
capabilities.setHoverProvider(profile.hoverSupported());
|
|
||||||
|
|
||||||
final InitializeResult result = new InitializeResult(capabilities);
|
|
||||||
final ServerInfo serverInfo = new ServerInfo();
|
|
||||||
serverInfo.setName(profile.name());
|
|
||||||
serverInfo.setVersion(profile.version());
|
|
||||||
result.setServerInfo(serverInfo);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package p.studio.lsp.v1.compiler;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import p.studio.lsp.api.LspProjectContext;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class CompilerLanguageServiceBridgeTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void bridgeProvidesStableBaselineResponses() {
|
||||||
|
final CompilerLanguageServiceBridge bridge = new CompilerLanguageServiceBridge();
|
||||||
|
final LspProjectContext project = new LspProjectContext("demo", "pbs", Path.of("."));
|
||||||
|
|
||||||
|
final BaselineServerDescription server = bridge.describeServer(project);
|
||||||
|
final BaselineDocumentAnalysis analysis = bridge.analyzeDocument(project, "file:///demo.pbs", "let x = 1");
|
||||||
|
final BaselineHover hover = bridge.hover(project, "file:///demo.pbs", 0, 0);
|
||||||
|
|
||||||
|
assertEquals("Prometeu Studio LSP", server.name());
|
||||||
|
assertTrue(server.hoverSupported());
|
||||||
|
assertFalse(analysis.issues().isEmpty());
|
||||||
|
assertTrue(analysis.issues().getFirst().message().contains("BuilderPipelineService"));
|
||||||
|
assertTrue(hover.markdown().contains("Compiler-backed baseline"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,116 @@
|
|||||||
|
package p.studio.lsp.v1.protocol;
|
||||||
|
|
||||||
|
import org.eclipse.lsp4j.InitializeParams;
|
||||||
|
import org.eclipse.lsp4j.InitializeResult;
|
||||||
|
import org.eclipse.lsp4j.PublishDiagnosticsParams;
|
||||||
|
import org.eclipse.lsp4j.services.TextDocumentService;
|
||||||
|
import org.eclipse.lsp4j.services.WorkspaceService;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import p.studio.lsp.api.LspProjectContext;
|
||||||
|
import p.studio.lsp.v1.compiler.*;
|
||||||
|
import p.studio.lsp.v1.protocol.mapping.ProtocolMessageMapper;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
|
|
||||||
|
class PrometeuLanguageServerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void initializeDelegatesThroughBridgeAndMapper() {
|
||||||
|
final RecordingBridge bridge = new RecordingBridge();
|
||||||
|
final RecordingMapper mapper = new RecordingMapper();
|
||||||
|
final InitializeResult expected = new InitializeResult();
|
||||||
|
mapper.initializeResult = expected;
|
||||||
|
|
||||||
|
final PrometeuLanguageServer server = new PrometeuLanguageServer(
|
||||||
|
new LspProjectContext("demo", "pbs", Path.of(".")),
|
||||||
|
bridge,
|
||||||
|
mapper,
|
||||||
|
new NoopTextDocumentService(),
|
||||||
|
new PrometeuWorkspaceService());
|
||||||
|
|
||||||
|
final InitializeResult result = server.initialize(new InitializeParams()).join();
|
||||||
|
|
||||||
|
assertSame(expected, result);
|
||||||
|
assertEquals(1, bridge.describeServerCalls);
|
||||||
|
assertSame(bridge.serverDescription, mapper.lastServerDescription);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class RecordingBridge implements LanguageServiceBridge {
|
||||||
|
private int describeServerCalls;
|
||||||
|
private final BaselineServerDescription serverDescription = new BaselineServerDescription("demo", "1", true);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaselineServerDescription describeServer(final LspProjectContext project) {
|
||||||
|
describeServerCalls++;
|
||||||
|
return serverDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaselineDocumentAnalysis analyzeDocument(final LspProjectContext project, final String documentUri, final String text) {
|
||||||
|
return new BaselineDocumentAnalysis(List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaselineHover hover(final LspProjectContext project, final String documentUri, final int line, final int character) {
|
||||||
|
return new BaselineHover("hover");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String onSave(final LspProjectContext project, final String documentUri) {
|
||||||
|
return "saved";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class RecordingMapper implements ProtocolMessageMapper {
|
||||||
|
private InitializeResult initializeResult;
|
||||||
|
private BaselineServerDescription lastServerDescription;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InitializeResult mapInitializeResult(final BaselineServerDescription description) {
|
||||||
|
lastServerDescription = description;
|
||||||
|
return initializeResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PublishDiagnosticsParams mapDiagnostics(final String uri, final BaselineDocumentAnalysis analysis) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PublishDiagnosticsParams emptyDiagnostics(final String uri) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public org.eclipse.lsp4j.Hover mapHover(final BaselineHover hover) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public org.eclipse.lsp4j.MessageParams mapInfoMessage(final String message) {
|
||||||
|
return new org.eclipse.lsp4j.MessageParams();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class NoopTextDocumentService implements TextDocumentService {
|
||||||
|
@Override
|
||||||
|
public void didOpen(final org.eclipse.lsp4j.DidOpenTextDocumentParams params) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void didChange(final org.eclipse.lsp4j.DidChangeTextDocumentParams params) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void didClose(final org.eclipse.lsp4j.DidCloseTextDocumentParams params) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void didSave(final org.eclipse.lsp4j.DidSaveTextDocumentParams params) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
package p.studio.lsp.v1.protocol;
|
||||||
|
|
||||||
|
import org.eclipse.lsp4j.*;
|
||||||
|
import org.eclipse.lsp4j.services.LanguageClient;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import p.studio.lsp.api.LspProjectContext;
|
||||||
|
import p.studio.lsp.v1.compiler.*;
|
||||||
|
import p.studio.lsp.v1.protocol.mapping.ProtocolMessageMapper;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
|
|
||||||
|
class PrometeuTextDocumentServiceTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void documentEventsDelegateToBridgeAndMapper() {
|
||||||
|
final RecordingBridge bridge = new RecordingBridge();
|
||||||
|
final RecordingMapper mapper = new RecordingMapper();
|
||||||
|
final RecordingClient client = new RecordingClient();
|
||||||
|
final PrometeuTextDocumentService service = new PrometeuTextDocumentService(
|
||||||
|
new LspProjectContext("demo", "pbs", Path.of(".")),
|
||||||
|
bridge,
|
||||||
|
mapper);
|
||||||
|
service.connect(client);
|
||||||
|
|
||||||
|
service.didOpen(new DidOpenTextDocumentParams(new TextDocumentItem("file:///demo.pbs", "pbs", 1, "abc")));
|
||||||
|
service.didSave(new DidSaveTextDocumentParams(new TextDocumentIdentifier("file:///demo.pbs"), "abc"));
|
||||||
|
service.hover(new HoverParams(new TextDocumentIdentifier("file:///demo.pbs"), new Position(0, 0))).join();
|
||||||
|
|
||||||
|
assertEquals(1, bridge.analyzeCalls);
|
||||||
|
assertEquals(1, bridge.saveCalls);
|
||||||
|
assertEquals(1, bridge.hoverCalls);
|
||||||
|
assertSame(bridge.lastAnalysis, mapper.lastAnalysis);
|
||||||
|
assertSame(bridge.lastHover, mapper.lastHover);
|
||||||
|
assertSame(mapper.diagnostics, client.lastDiagnostics);
|
||||||
|
assertSame(mapper.infoMessage, client.lastLogMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class RecordingBridge implements LanguageServiceBridge {
|
||||||
|
private int analyzeCalls;
|
||||||
|
private int saveCalls;
|
||||||
|
private int hoverCalls;
|
||||||
|
private final BaselineDocumentAnalysis lastAnalysis = new BaselineDocumentAnalysis(List.of(
|
||||||
|
new BaselineDocumentIssue(0, 0, 0, 1, BaselineIssueSeverity.INFORMATION, "src", "msg")));
|
||||||
|
private final BaselineHover lastHover = new BaselineHover("hover");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaselineServerDescription describeServer(final LspProjectContext project) {
|
||||||
|
return new BaselineServerDescription("demo", "1", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaselineDocumentAnalysis analyzeDocument(final LspProjectContext project, final String documentUri, final String text) {
|
||||||
|
analyzeCalls++;
|
||||||
|
return lastAnalysis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaselineHover hover(final LspProjectContext project, final String documentUri, final int line, final int character) {
|
||||||
|
hoverCalls++;
|
||||||
|
return lastHover;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String onSave(final LspProjectContext project, final String documentUri) {
|
||||||
|
saveCalls++;
|
||||||
|
return "saved";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class RecordingMapper implements ProtocolMessageMapper {
|
||||||
|
private final PublishDiagnosticsParams diagnostics = new PublishDiagnosticsParams("file:///demo.pbs", List.of());
|
||||||
|
private final MessageParams infoMessage = new MessageParams(MessageType.Info, "saved");
|
||||||
|
private BaselineDocumentAnalysis lastAnalysis;
|
||||||
|
private BaselineHover lastHover;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InitializeResult mapInitializeResult(final BaselineServerDescription description) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PublishDiagnosticsParams mapDiagnostics(final String uri, final BaselineDocumentAnalysis analysis) {
|
||||||
|
lastAnalysis = analysis;
|
||||||
|
return diagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PublishDiagnosticsParams emptyDiagnostics(final String uri) {
|
||||||
|
return new PublishDiagnosticsParams(uri, List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Hover mapHover(final BaselineHover hover) {
|
||||||
|
lastHover = hover;
|
||||||
|
return new Hover();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MessageParams mapInfoMessage(final String message) {
|
||||||
|
return infoMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class RecordingClient implements LanguageClient {
|
||||||
|
private PublishDiagnosticsParams lastDiagnostics;
|
||||||
|
private MessageParams lastLogMessage;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void telemetryEvent(final Object object) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publishDiagnostics(final PublishDiagnosticsParams diagnostics) {
|
||||||
|
lastDiagnostics = diagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showMessage(final MessageParams messageParams) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<MessageActionItem> showMessageRequest(final ShowMessageRequestParams requestParams) {
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logMessage(final MessageParams message) {
|
||||||
|
lastLogMessage = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user