refactor, rename and reducing complexity

This commit is contained in:
bQUARKz 2026-04-02 11:55:09 +01:00
parent b64be2a9a1
commit ba55b8e65f
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
120 changed files with 1134 additions and 1025 deletions

View File

@ -2,10 +2,10 @@ package p.studio;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import p.packer.Packer; import p.packer.Packer;
import p.lsp.PrometeuLspServiceFactory; import p.studio.lsp.LspServiceFactory;
import p.lsp.v1.PrometeuLspV1ServiceFactory; import p.studio.lsp.LspServiceFactoryImpl;
import p.studio.events.StudioEventBus; import p.studio.lsp.events.StudioEventBus;
import p.studio.events.StudioPackerEventAdapter; import p.studio.lsp.events.StudioPackerEventAdapter;
import p.studio.utilities.ThemeService; import p.studio.utilities.ThemeService;
import p.studio.utilities.i18n.I18nService; import p.studio.utilities.i18n.I18nService;
import p.studio.vfs.FilesystemProjectDocumentVfsFactory; import p.studio.vfs.FilesystemProjectDocumentVfsFactory;
@ -21,7 +21,7 @@ public final class AppContainer implements Container {
private final ThemeService themeService; private final ThemeService themeService;
private final StudioEventBus studioEventBus; private final StudioEventBus studioEventBus;
private final ObjectMapper mapper; private final ObjectMapper mapper;
private final PrometeuLspServiceFactory prometeuLspServiceFactory; private final LspServiceFactory lspServiceFactory;
private final ProjectDocumentVfsFactory projectDocumentVfsFactory; private final ProjectDocumentVfsFactory projectDocumentVfsFactory;
private final EmbeddedPacker embeddedPacker; private final EmbeddedPacker embeddedPacker;
private final StudioBackgroundTasks backgroundTasks; private final StudioBackgroundTasks backgroundTasks;
@ -31,7 +31,7 @@ public final class AppContainer implements Container {
this.themeService = new ThemeService(); this.themeService = new ThemeService();
this.studioEventBus = new StudioEventBus(); this.studioEventBus = new StudioEventBus();
this.mapper = new ObjectMapper(); this.mapper = new ObjectMapper();
this.prometeuLspServiceFactory = new PrometeuLspV1ServiceFactory(); this.lspServiceFactory = new LspServiceFactoryImpl();
this.projectDocumentVfsFactory = new FilesystemProjectDocumentVfsFactory(); this.projectDocumentVfsFactory = new FilesystemProjectDocumentVfsFactory();
final ExecutorService backgroundExecutor = Executors.newFixedThreadPool(2, new StudioWorkerThreadFactory()); final ExecutorService backgroundExecutor = Executors.newFixedThreadPool(2, new StudioWorkerThreadFactory());
this.backgroundTasks = new StudioBackgroundTasks(backgroundExecutor); this.backgroundTasks = new StudioBackgroundTasks(backgroundExecutor);
@ -60,8 +60,8 @@ public final class AppContainer implements Container {
} }
@Override @Override
public PrometeuLspServiceFactory getPrometeuLspServiceFactory() { public LspServiceFactory getPrometeuLspServiceFactory() {
return prometeuLspServiceFactory; return lspServiceFactory;
} }
@Override @Override

View File

@ -6,6 +6,7 @@ import p.studio.compiler.source.tables.FileTableReader;
import java.util.List; import java.util.List;
public record AnalysisSnapshot( public record AnalysisSnapshot(
FrontendSpec frontendSpec,
List<BuildingIssue> diagnostics, List<BuildingIssue> diagnostics,
ResolvedWorkspace resolvedWorkspace, ResolvedWorkspace resolvedWorkspace,
FileTableReader fileTable, FileTableReader fileTable,

View File

@ -59,6 +59,7 @@ public class BuilderPipelineService {
final LogAggregator logs) { final LogAggregator logs) {
final var diagnostics = run(ctx, logs, analyses, new ArrayList<>()); final var diagnostics = run(ctx, logs, analyses, new ArrayList<>());
return new AnalysisSnapshot( return new AnalysisSnapshot(
ctx.resolvedWorkspace.frontendSpec(),
diagnostics, diagnostics,
ctx.resolvedWorkspace, ctx.resolvedWorkspace,
ctx.fileTable, ctx.fileTable,

View File

@ -30,7 +30,7 @@ class BuilderPipelinePublicSurfaceTest {
@Test @Test
void analysisSnapshotMustExposeMinimumSharedContract() { void analysisSnapshotMustExposeMinimumSharedContract() {
assertEquals( assertEquals(
Set.of("diagnostics", "resolvedWorkspace", "fileTable", "irBackend"), Set.of("frontendSpec", "diagnostics", "resolvedWorkspace", "fileTable", "irBackend"),
recordComponentNames(AnalysisSnapshot.class), recordComponentNames(AnalysisSnapshot.class),
"analysis snapshot must expose the minimum shared contract"); "analysis snapshot must expose the minimum shared contract");
} }

View File

@ -1,24 +0,0 @@
package p.lsp;
import p.lsp.dtos.PrometeuLspSessionStateDTO;
import p.lsp.messages.PrometeuLspAnalyzeDocumentRequest;
import p.lsp.messages.PrometeuLspAnalyzeDocumentResult;
import p.lsp.messages.PrometeuLspDefinitionRequest;
import p.lsp.messages.PrometeuLspDefinitionResult;
import p.studio.vfs.ProjectDocumentVfs;
public interface PrometeuLspService extends AutoCloseable {
PrometeuLspProjectContext projectContext();
ProjectDocumentVfs projectDocumentVfs();
PrometeuLspSessionStateDTO snapshot();
PrometeuLspAnalyzeDocumentResult analyzeDocument(PrometeuLspAnalyzeDocumentRequest request);
PrometeuLspDefinitionResult definition(PrometeuLspDefinitionRequest request);
@Override
default void close() {
}
}

View File

@ -1,7 +0,0 @@
package p.lsp;
import p.studio.vfs.ProjectDocumentVfs;
public interface PrometeuLspServiceFactory {
PrometeuLspService open(PrometeuLspProjectContext projectContext, ProjectDocumentVfs projectDocumentVfs);
}

View File

@ -1,6 +0,0 @@
package p.lsp.dtos;
public enum PrometeuLspDiagnosticSeverityDTO {
ERROR,
WARNING
}

View File

@ -1,5 +0,0 @@
package p.lsp.events;
public enum PrometeuLspEventKind {
SESSION_READY
}

View File

@ -1,5 +0,0 @@
package p.lsp.events;
public interface PrometeuLspEventSink {
void publish(PrometeuLspEvent event);
}

View File

@ -1,25 +0,0 @@
package p.lsp.messages;
import p.lsp.dtos.PrometeuLspDiagnosticDTO;
import p.lsp.dtos.PrometeuLspHighlightSpanDTO;
import p.lsp.dtos.PrometeuLspSessionStateDTO;
import p.lsp.dtos.PrometeuLspSymbolDTO;
import java.util.List;
import java.util.Objects;
public record PrometeuLspAnalyzeDocumentResult(
PrometeuLspSessionStateDTO sessionState,
List<PrometeuLspDiagnosticDTO> diagnostics,
List<PrometeuLspHighlightSpanDTO> semanticHighlights,
List<PrometeuLspSymbolDTO> documentSymbols,
List<PrometeuLspSymbolDTO> workspaceSymbols) {
public PrometeuLspAnalyzeDocumentResult {
Objects.requireNonNull(sessionState, "sessionState");
diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics"));
semanticHighlights = List.copyOf(Objects.requireNonNull(semanticHighlights, "semanticHighlights"));
documentSymbols = List.copyOf(Objects.requireNonNull(documentSymbols, "documentSymbols"));
workspaceSymbols = List.copyOf(Objects.requireNonNull(workspaceSymbols, "workspaceSymbols"));
}
}

View File

@ -0,0 +1,21 @@
package p.studio.lsp;
import p.studio.lsp.dtos.LspSessionStateDTO;
import p.studio.lsp.messages.*;
import p.studio.vfs.VfsProjectDocument;
public interface LspService extends AutoCloseable {
LspProjectContext projectContext();
VfsProjectDocument projectDocumentVfs();
LspSessionStateDTO snapshot();
LspAnalyzeDocumentResult analyzeDocument(LspAnalyzeDocumentRequest request);
LspDefinitionResult definition(LspDefinitionRequest request);
@Override
default void close() {
}
}

View File

@ -0,0 +1,8 @@
package p.studio.lsp;
import p.studio.lsp.messages.LspProjectContext;
import p.studio.vfs.VfsProjectDocument;
public interface LspServiceFactory {
LspService open(LspProjectContext projectContext, VfsProjectDocument vfsProjectDocument);
}

View File

@ -1,14 +1,14 @@
package p.lsp.dtos; package p.studio.lsp.dtos;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Objects; import java.util.Objects;
public record PrometeuLspDefinitionTargetDTO( public record LspDefinitionTargetDTO(
String name, String name,
Path documentPath, Path documentPath,
PrometeuLspRangeDTO range) { LspRangeDTO range) {
public PrometeuLspDefinitionTargetDTO { public LspDefinitionTargetDTO {
name = Objects.requireNonNull(name, "name"); name = Objects.requireNonNull(name, "name");
documentPath = Objects.requireNonNull(documentPath, "documentPath").toAbsolutePath().normalize(); documentPath = Objects.requireNonNull(documentPath, "documentPath").toAbsolutePath().normalize();
range = Objects.requireNonNull(range, "range"); range = Objects.requireNonNull(range, "range");

View File

@ -1,17 +1,19 @@
package p.lsp.dtos; package p.studio.lsp.dtos;
import p.studio.lsp.messages.LspDiagnosticSeverity;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Objects; import java.util.Objects;
public record PrometeuLspDiagnosticDTO( public record LspDiagnosticDTO(
Path documentPath, Path documentPath,
PrometeuLspRangeDTO range, LspRangeDTO range,
PrometeuLspDiagnosticSeverityDTO severity, LspDiagnosticSeverity severity,
String phase, String phase,
String code, String code,
String message) { String message) {
public PrometeuLspDiagnosticDTO { public LspDiagnosticDTO {
documentPath = Objects.requireNonNull(documentPath, "documentPath").toAbsolutePath().normalize(); documentPath = Objects.requireNonNull(documentPath, "documentPath").toAbsolutePath().normalize();
range = Objects.requireNonNull(range, "range"); range = Objects.requireNonNull(range, "range");
severity = Objects.requireNonNull(severity, "severity"); severity = Objects.requireNonNull(severity, "severity");

View File

@ -1,12 +1,12 @@
package p.lsp.dtos; package p.studio.lsp.dtos;
import java.util.Objects; import java.util.Objects;
public record PrometeuLspHighlightSpanDTO( public record LspHighlightSpanDTO(
PrometeuLspRangeDTO range, LspRangeDTO range,
String semanticKey) { String semanticKey) {
public PrometeuLspHighlightSpanDTO { public LspHighlightSpanDTO {
range = Objects.requireNonNull(range, "range"); range = Objects.requireNonNull(range, "range");
semanticKey = Objects.requireNonNull(semanticKey, "semanticKey"); semanticKey = Objects.requireNonNull(semanticKey, "semanticKey");
} }

View File

@ -1,10 +1,10 @@
package p.lsp.dtos; package p.studio.lsp.dtos;
public record PrometeuLspRangeDTO( public record LspRangeDTO(
int startOffset, int startOffset,
int endOffset) { int endOffset) {
public PrometeuLspRangeDTO { public LspRangeDTO {
startOffset = Math.max(0, startOffset); startOffset = Math.max(0, startOffset);
endOffset = Math.max(startOffset, endOffset); endOffset = Math.max(startOffset, endOffset);
} }

View File

@ -1,13 +1,13 @@
package p.lsp.dtos; package p.studio.lsp.dtos;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
public record PrometeuLspSessionStateDTO( public record LspSessionStateDTO(
boolean semanticReadReady, boolean semanticReadReady,
List<String> declaredCapabilities) { List<String> declaredCapabilities) {
public PrometeuLspSessionStateDTO { public LspSessionStateDTO {
declaredCapabilities = List.copyOf(Objects.requireNonNull(declaredCapabilities, "declaredCapabilities")); declaredCapabilities = List.copyOf(Objects.requireNonNull(declaredCapabilities, "declaredCapabilities"));
} }
} }

View File

@ -1,17 +1,19 @@
package p.lsp.dtos; package p.studio.lsp.dtos;
import p.studio.lsp.messages.LspSymbolKind;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
public record PrometeuLspSymbolDTO( public record LspSymbolDTO(
String name, String name,
PrometeuLspSymbolKindDTO kind, LspSymbolKind kind,
Path documentPath, Path documentPath,
PrometeuLspRangeDTO range, LspRangeDTO range,
List<PrometeuLspSymbolDTO> children) { List<LspSymbolDTO> children) {
public PrometeuLspSymbolDTO { public LspSymbolDTO {
name = Objects.requireNonNull(name, "name"); name = Objects.requireNonNull(name, "name");
kind = Objects.requireNonNull(kind, "kind"); kind = Objects.requireNonNull(kind, "kind");
documentPath = Objects.requireNonNull(documentPath, "documentPath").toAbsolutePath().normalize(); documentPath = Objects.requireNonNull(documentPath, "documentPath").toAbsolutePath().normalize();

View File

@ -1,12 +1,12 @@
package p.lsp.events; package p.studio.lsp.events;
import java.util.Objects; import java.util.Objects;
public record PrometeuLspEvent( public record LspEvent(
PrometeuLspEventKind kind, LspEventKind kind,
String message) { String message) {
public PrometeuLspEvent { public LspEvent {
Objects.requireNonNull(kind, "kind"); Objects.requireNonNull(kind, "kind");
Objects.requireNonNull(message, "message"); Objects.requireNonNull(message, "message");
} }

View File

@ -0,0 +1,5 @@
package p.studio.lsp.events;
public enum LspEventKind {
SESSION_READY
}

View File

@ -0,0 +1,5 @@
package p.studio.lsp.events;
public interface LspEventSink {
void publish(LspEvent event);
}

View File

@ -1,12 +1,12 @@
package p.lsp.messages; package p.studio.lsp.messages;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Objects; import java.util.Objects;
public record PrometeuLspAnalyzeDocumentRequest( public record LspAnalyzeDocumentRequest(
Path documentPath) { Path documentPath) {
public PrometeuLspAnalyzeDocumentRequest { public LspAnalyzeDocumentRequest {
documentPath = Objects.requireNonNull(documentPath, "documentPath").toAbsolutePath().normalize(); documentPath = Objects.requireNonNull(documentPath, "documentPath").toAbsolutePath().normalize();
} }
} }

View File

@ -0,0 +1,25 @@
package p.studio.lsp.messages;
import p.studio.lsp.dtos.LspDiagnosticDTO;
import p.studio.lsp.dtos.LspHighlightSpanDTO;
import p.studio.lsp.dtos.LspSessionStateDTO;
import p.studio.lsp.dtos.LspSymbolDTO;
import java.util.List;
import java.util.Objects;
public record LspAnalyzeDocumentResult(
LspSessionStateDTO sessionState,
List<LspDiagnosticDTO> diagnostics,
List<LspHighlightSpanDTO> semanticHighlights,
List<LspSymbolDTO> documentSymbols,
List<LspSymbolDTO> workspaceSymbols) {
public LspAnalyzeDocumentResult {
Objects.requireNonNull(sessionState, "sessionState");
diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics"));
semanticHighlights = List.copyOf(Objects.requireNonNull(semanticHighlights, "semanticHighlights"));
documentSymbols = List.copyOf(Objects.requireNonNull(documentSymbols, "documentSymbols"));
workspaceSymbols = List.copyOf(Objects.requireNonNull(workspaceSymbols, "workspaceSymbols"));
}
}

View File

@ -1,13 +1,13 @@
package p.lsp.messages; package p.studio.lsp.messages;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Objects; import java.util.Objects;
public record PrometeuLspDefinitionRequest( public record LspDefinitionRequest(
Path documentPath, Path documentPath,
int offset) { int offset) {
public PrometeuLspDefinitionRequest { public LspDefinitionRequest {
documentPath = Objects.requireNonNull(documentPath, "documentPath").toAbsolutePath().normalize(); documentPath = Objects.requireNonNull(documentPath, "documentPath").toAbsolutePath().normalize();
offset = Math.max(0, offset); offset = Math.max(0, offset);
} }

View File

@ -1,17 +1,17 @@
package p.lsp.messages; package p.studio.lsp.messages;
import p.lsp.dtos.PrometeuLspDefinitionTargetDTO; import p.studio.lsp.dtos.LspDefinitionTargetDTO;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
public record PrometeuLspDefinitionResult( public record LspDefinitionResult(
Path documentPath, Path documentPath,
int offset, int offset,
List<PrometeuLspDefinitionTargetDTO> targets) { List<LspDefinitionTargetDTO> targets) {
public PrometeuLspDefinitionResult { public LspDefinitionResult {
documentPath = Objects.requireNonNull(documentPath, "documentPath").toAbsolutePath().normalize(); documentPath = Objects.requireNonNull(documentPath, "documentPath").toAbsolutePath().normalize();
offset = Math.max(0, offset); offset = Math.max(0, offset);
targets = List.copyOf(Objects.requireNonNull(targets, "targets")); targets = List.copyOf(Objects.requireNonNull(targets, "targets"));

View File

@ -0,0 +1,6 @@
package p.studio.lsp.messages;
public enum LspDiagnosticSeverity {
ERROR,
WARNING
}

View File

@ -1,14 +1,14 @@
package p.lsp; package p.studio.lsp.messages;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Objects; import java.util.Objects;
public record PrometeuLspProjectContext( public record LspProjectContext(
String projectName, String projectName,
String languageId, String languageId,
Path rootPath) { Path rootPath) {
public PrometeuLspProjectContext { public LspProjectContext {
Objects.requireNonNull(projectName, "projectName"); Objects.requireNonNull(projectName, "projectName");
Objects.requireNonNull(languageId, "languageId"); Objects.requireNonNull(languageId, "languageId");
rootPath = Objects.requireNonNull(rootPath, "rootPath").toAbsolutePath().normalize(); rootPath = Objects.requireNonNull(rootPath, "rootPath").toAbsolutePath().normalize();

View File

@ -1,6 +1,6 @@
package p.lsp.dtos; package p.studio.lsp.messages;
public enum PrometeuLspSymbolKindDTO { public enum LspSymbolKind {
FUNCTION, FUNCTION,
METHOD, METHOD,
CONSTRUCTOR, CONSTRUCTOR,

View File

@ -1,20 +0,0 @@
package p.lsp.v1;
import p.lsp.PrometeuLspProjectContext;
import p.lsp.PrometeuLspService;
import p.lsp.PrometeuLspServiceFactory;
import p.lsp.v1.internal.PrometeuLspV1Service;
import p.studio.vfs.ProjectDocumentVfs;
import java.util.Objects;
public final class PrometeuLspV1ServiceFactory implements PrometeuLspServiceFactory {
@Override
public PrometeuLspService open(
final PrometeuLspProjectContext projectContext,
final ProjectDocumentVfs projectDocumentVfs) {
return new PrometeuLspV1Service(
Objects.requireNonNull(projectContext, "projectContext"),
Objects.requireNonNull(projectDocumentVfs, "projectDocumentVfs"));
}
}

View File

@ -1,500 +0,0 @@
package p.lsp.v1.internal;
import p.lsp.PrometeuLspProjectContext;
import p.lsp.dtos.*;
import p.lsp.messages.PrometeuLspAnalyzeDocumentRequest;
import p.lsp.messages.PrometeuLspAnalyzeDocumentResult;
import p.lsp.messages.PrometeuLspDefinitionRequest;
import p.lsp.messages.PrometeuLspDefinitionResult;
import p.studio.compiler.FrontendRegistryService;
import p.studio.compiler.messages.BuildingIssue;
import p.studio.compiler.messages.BuildingIssueSink;
import p.studio.compiler.messages.BuilderPipelineConfig;
import p.studio.compiler.messages.FESurfaceContext;
import p.studio.compiler.messages.FrontendPhaseContext;
import p.studio.compiler.messages.HostAdmissionContext;
import p.studio.compiler.models.AnalysisSnapshot;
import p.studio.compiler.models.BuilderPipelineContext;
import p.studio.compiler.models.SourceHandle;
import p.studio.compiler.pbs.ast.PbsAst;
import p.studio.compiler.pbs.lexer.PbsLexer;
import p.studio.compiler.pbs.lexer.PbsToken;
import p.studio.compiler.pbs.lexer.PbsTokenKind;
import p.studio.compiler.pbs.parser.PbsParser;
import p.studio.compiler.source.Span;
import p.studio.compiler.source.diagnostics.Diagnostic;
import p.studio.compiler.source.diagnostics.DiagnosticSink;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.workspaces.AssetSurfaceContextLoader;
import p.studio.compiler.workspaces.PipelineStage;
import p.studio.compiler.workspaces.stages.LoadSourcesPipelineStage;
import p.studio.compiler.workspaces.stages.ResolveDepsPipelineStage;
import p.studio.utilities.logs.LogAggregator;
import p.studio.vfs.ProjectDocumentVfs;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
final class PrometeuLspSemanticReadPhase {
private PrometeuLspSemanticReadPhase() {
}
static PrometeuLspAnalyzeDocumentResult analyze(
final PrometeuLspProjectContext projectContext,
final ProjectDocumentVfs projectDocumentVfs,
final PrometeuLspAnalyzeDocumentRequest request) {
final SemanticSession session = buildSession(projectContext, projectDocumentVfs, request.documentPath());
final Path normalizedRequestedDocument = normalize(request.documentPath());
return new PrometeuLspAnalyzeDocumentResult(
new PrometeuLspSessionStateDTO(true, List.of("diagnostics", "symbols", "definition", "highlight")),
session.diagnosticsByDocument().getOrDefault(normalizedRequestedDocument, List.of()),
session.semanticHighlightsByDocument().getOrDefault(normalizedRequestedDocument, List.of()),
session.documentSymbolsByDocument().getOrDefault(normalizedRequestedDocument, List.of()),
session.workspaceSymbols());
}
static PrometeuLspDefinitionResult definition(
final PrometeuLspProjectContext projectContext,
final ProjectDocumentVfs projectDocumentVfs,
final PrometeuLspDefinitionRequest request) {
final SemanticSession session = buildSession(projectContext, projectDocumentVfs, request.documentPath());
final List<PrometeuLspDefinitionTargetDTO> targets = resolveDefinitionTargets(session, request);
return new PrometeuLspDefinitionResult(request.documentPath(), request.offset(), targets);
}
private static SemanticSession buildSession(
final PrometeuLspProjectContext projectContext,
final ProjectDocumentVfs projectDocumentVfs,
final Path requestedDocumentPath) {
final BuilderPipelineConfig config = new BuilderPipelineConfig(
false,
projectContext.rootPath().toString(),
"core-v1",
new PrometeuLspVfsOverlaySourceProviderFactory(projectDocumentVfs, requestedDocumentPath));
final BuilderPipelineContext context = BuilderPipelineContext.fromConfig(config);
final AnalysisRuntimeSnapshot snapshot = runAnalysisStages(context);
return index(snapshot, requestedDocumentPath);
}
private static AnalysisRuntimeSnapshot runAnalysisStages(final BuilderPipelineContext context) {
final LogAggregator logs = LogAggregator.empty();
final List<BuildingIssue> diagnostics = new ArrayList<>();
final List<PipelineStage> stages = List.of(
new ResolveDepsPipelineStage(),
new LoadSourcesPipelineStage());
for (final PipelineStage stage : stages) {
final BuildingIssueSink stageIssues = stage.run(context, logs);
diagnostics.addAll(stageIssues.asCollection());
if (stageIssues.hasErrors()) {
break;
}
}
final DiagnosticSink frontendDiagnostics = DiagnosticSink.empty();
if (context.resolvedWorkspace != null && context.fileTable != null) {
final BuildingIssueSink frontendIssues = runFrontendPhase(context, logs, frontendDiagnostics);
diagnostics.addAll(frontendIssues.asCollection());
}
return new AnalysisRuntimeSnapshot(
new AnalysisSnapshot(
diagnostics,
context.resolvedWorkspace,
context.fileTable,
context.irBackend),
List.copyOf(frontendDiagnostics.asCollection()));
}
private static BuildingIssueSink runFrontendPhase(
final BuilderPipelineContext context,
final LogAggregator logs,
final DiagnosticSink frontendDiagnostics) {
final var frontendSpec = context.resolvedWorkspace.frontendSpec();
final var service = FrontendRegistryService.getFrontendPhaseService(frontendSpec.getLanguageId());
if (service.isEmpty()) {
return BuildingIssueSink.empty().report(builder -> builder
.error(true)
.message("[BUILD]: unable to find a service for frontend phase: " + frontendSpec.getLanguageId()));
}
final FESurfaceContext feSurfaceContext = new AssetSurfaceContextLoader().load(context.resolvedWorkspace.mainProject().getRootPath());
final FrontendPhaseContext frontendPhaseContext = new FrontendPhaseContext(
context.resolvedWorkspace.graph().projectTable(),
context.fileTable,
context.resolvedWorkspace.stack(),
context.resolvedWorkspace.stdlib(),
HostAdmissionContext.permissiveDefault(),
feSurfaceContext);
final BuildingIssueSink issues = BuildingIssueSink.empty();
context.irBackend = service.get().compile(frontendPhaseContext, frontendDiagnostics, logs, issues);
return issues;
}
private static SemanticSession index(
final AnalysisRuntimeSnapshot runtimeSnapshot,
final Path requestedDocumentPath) {
final AnalysisSnapshot snapshot = runtimeSnapshot.analysisSnapshot();
final Map<Path, List<PrometeuLspDiagnosticDTO>> diagnosticsByDocument = diagnosticsByDocument(
snapshot.diagnostics(),
snapshot,
runtimeSnapshot.frontendDiagnostics());
final SemanticIndex semanticIndex = new SemanticIndex();
if (snapshot.fileTable() == null) {
return new SemanticSession(
normalize(requestedDocumentPath),
diagnosticsByDocument,
Map.of(),
Map.of(),
List.of(),
Map.of(),
Map.of());
}
for (final FileId fileId : snapshot.fileTable()) {
final SourceHandle sourceHandle = snapshot.fileTable().get(fileId);
if (!isPbsSource(sourceHandle)) {
continue;
}
final String source = sourceHandle.readUtf8().orElse("");
final DiagnosticSink diagnostics = DiagnosticSink.empty();
final var tokens = PbsLexer.lex(source, fileId, diagnostics);
final PbsAst.File ast = PbsParser.parse(tokens, fileId, diagnostics, PbsParser.ParseMode.ORDINARY);
semanticIndex.index(sourceHandle.getCanonPath(), ast, tokens.asList());
}
return new SemanticSession(
normalize(requestedDocumentPath),
diagnosticsByDocument,
semanticIndex.semanticHighlightsByDocument(),
semanticIndex.documentSymbolsByDocument(),
semanticIndex.workspaceSymbols(),
semanticIndex.symbolsByName(),
semanticIndex.tokensByDocument());
}
private static boolean isPbsSource(final SourceHandle sourceHandle) {
return "pbs".equalsIgnoreCase(sourceHandle.getExtension());
}
private static Map<Path, List<PrometeuLspDiagnosticDTO>> diagnosticsByDocument(
final List<BuildingIssue> issues,
final AnalysisSnapshot snapshot,
final List<Diagnostic> frontendDiagnostics) {
final Map<Path, List<PrometeuLspDiagnosticDTO>> diagnosticsByDocument = new LinkedHashMap<>();
for (final var issue : issues) {
if (issue.getFileId() == null || issue.getFileId() < 0) {
continue;
}
if (snapshot.fileTable() == null || issue.getFileId() >= snapshot.fileTable().size()) {
continue;
}
final SourceHandle sourceHandle = snapshot.fileTable().get(new FileId(issue.getFileId()));
final Path documentPath = sourceHandle.getCanonPath().toAbsolutePath().normalize();
diagnosticsByDocument
.computeIfAbsent(documentPath, ignored -> new ArrayList<>())
.add(new PrometeuLspDiagnosticDTO(
documentPath,
new PrometeuLspRangeDTO(
safeOffset(issue.getStart()),
safeEnd(issue.getStart(), issue.getEnd())),
issue.isError()
? PrometeuLspDiagnosticSeverityDTO.ERROR
: PrometeuLspDiagnosticSeverityDTO.WARNING,
issue.getPhase(),
issue.getCode(),
issue.getMessage()));
}
for (final Diagnostic diagnostic : frontendDiagnostics) {
if (snapshot.fileTable() == null || diagnostic.getSpan() == null || diagnostic.getSpan().getFileId().isNone()) {
continue;
}
final SourceHandle sourceHandle = snapshot.fileTable().get(diagnostic.getSpan().getFileId());
final Path documentPath = sourceHandle.getCanonPath().toAbsolutePath().normalize();
diagnosticsByDocument
.computeIfAbsent(documentPath, ignored -> new ArrayList<>())
.add(new PrometeuLspDiagnosticDTO(
documentPath,
new PrometeuLspRangeDTO(
(int) diagnostic.getSpan().getStart(),
(int) diagnostic.getSpan().getEnd()),
diagnostic.getSeverity().isError()
? PrometeuLspDiagnosticSeverityDTO.ERROR
: PrometeuLspDiagnosticSeverityDTO.WARNING,
diagnostic.getPhase().name(),
diagnostic.getCode(),
diagnostic.getMessage()));
}
return freezeMapOfLists(diagnosticsByDocument);
}
private static int safeOffset(final Integer value) {
return value == null ? 0 : Math.max(0, value);
}
private static int safeEnd(final Integer start, final Integer end) {
final int safeStart = safeOffset(start);
final int safeEnd = safeOffset(end);
return Math.max(safeStart, safeEnd);
}
private static List<PrometeuLspDefinitionTargetDTO> resolveDefinitionTargets(
final SemanticSession session,
final PrometeuLspDefinitionRequest request) {
final Path documentPath = normalize(request.documentPath());
final List<PbsToken> tokens = session.tokensByDocument().getOrDefault(documentPath, List.of());
final PbsToken activeToken = tokenAt(tokens, request.offset());
if (activeToken == null || activeToken.kind() != PbsTokenKind.IDENTIFIER) {
return List.of();
}
final String lexeme = activeToken.lexeme();
final List<PrometeuLspSymbolDTO> sameDocumentMatches = session.symbolsByName().getOrDefault(lexeme, List.of()).stream()
.filter(symbol -> symbol.documentPath().equals(documentPath))
.toList();
final List<PrometeuLspSymbolDTO> effectiveMatches = sameDocumentMatches.isEmpty()
? session.symbolsByName().getOrDefault(lexeme, List.of())
: sameDocumentMatches;
return effectiveMatches.stream()
.map(symbol -> new PrometeuLspDefinitionTargetDTO(symbol.name(), symbol.documentPath(), symbol.range()))
.toList();
}
private static PbsToken tokenAt(final List<PbsToken> tokens, final int offset) {
for (final PbsToken token : tokens) {
if (token.start() <= offset && offset < token.end()) {
return token;
}
}
return null;
}
private static Path normalize(final Path path) {
final Path normalized = Objects.requireNonNull(path, "path").toAbsolutePath().normalize();
try {
return Files.exists(normalized) ? normalized.toRealPath() : normalized;
} catch (IOException ignored) {
return normalized;
}
}
private static <T> Map<Path, List<T>> freezeMapOfLists(final Map<Path, List<T>> mutable) {
final Map<Path, List<T>> frozen = new LinkedHashMap<>();
for (final var entry : mutable.entrySet()) {
frozen.put(entry.getKey(), List.copyOf(entry.getValue()));
}
return Map.copyOf(frozen);
}
private record SemanticSession(
Path requestedDocumentPath,
Map<Path, List<PrometeuLspDiagnosticDTO>> diagnosticsByDocument,
Map<Path, List<PrometeuLspHighlightSpanDTO>> semanticHighlightsByDocument,
Map<Path, List<PrometeuLspSymbolDTO>> documentSymbolsByDocument,
List<PrometeuLspSymbolDTO> workspaceSymbols,
Map<String, List<PrometeuLspSymbolDTO>> symbolsByName,
Map<Path, List<PbsToken>> tokensByDocument) {
}
private record AnalysisRuntimeSnapshot(
AnalysisSnapshot analysisSnapshot,
List<Diagnostic> frontendDiagnostics) {
}
private static final class SemanticIndex {
private final Map<Path, List<PrometeuLspHighlightSpanDTO>> semanticHighlightsByDocument = new LinkedHashMap<>();
private final Map<Path, List<PrometeuLspSymbolDTO>> documentSymbolsByDocument = new LinkedHashMap<>();
private final List<PrometeuLspSymbolDTO> workspaceSymbols = new ArrayList<>();
private final Map<String, List<PrometeuLspSymbolDTO>> symbolsByName = new LinkedHashMap<>();
private final Map<Path, List<PbsToken>> tokensByDocument = new LinkedHashMap<>();
void index(
final Path documentPath,
final PbsAst.File ast,
final List<PbsToken> tokens) {
final Path normalizedDocumentPath = normalize(documentPath);
tokensByDocument.put(normalizedDocumentPath, List.copyOf(tokens));
final List<PrometeuLspSymbolDTO> documentSymbols = new ArrayList<>();
for (final PbsAst.TopDecl topDecl : ast.topDecls()) {
final PrometeuLspSymbolDTO symbol = symbolForTopDecl(normalizedDocumentPath, topDecl);
if (symbol == null) {
continue;
}
documentSymbols.add(symbol);
workspaceSymbols.add(symbol);
symbolsByName.computeIfAbsent(symbol.name(), ignored -> new ArrayList<>()).add(symbol);
for (final PrometeuLspSymbolDTO child : symbol.children()) {
symbolsByName.computeIfAbsent(child.name(), ignored -> new ArrayList<>()).add(child);
}
}
semanticHighlightsByDocument.put(
normalizedDocumentPath,
buildSemanticHighlights(tokens, symbolsByName));
documentSymbolsByDocument.put(normalizedDocumentPath, List.copyOf(documentSymbols));
}
private List<PrometeuLspHighlightSpanDTO> buildSemanticHighlights(
final List<PbsToken> tokens,
final Map<String, List<PrometeuLspSymbolDTO>> indexedSymbolsByName) {
final List<PrometeuLspHighlightSpanDTO> highlights = new ArrayList<>();
for (final PbsToken token : tokens) {
if (token.kind() == PbsTokenKind.EOF) {
continue;
}
final String semanticKey = semanticKey(token, indexedSymbolsByName);
if (semanticKey == null || semanticKey.isBlank()) {
continue;
}
highlights.add(new PrometeuLspHighlightSpanDTO(
new PrometeuLspRangeDTO(token.start(), token.end()),
semanticKey));
}
return List.copyOf(highlights);
}
private String semanticKey(
final PbsToken token,
final Map<String, List<PrometeuLspSymbolDTO>> indexedSymbolsByName) {
return switch (token.kind()) {
case COMMENT -> "fe-comment";
case STRING_LITERAL -> "fe-string";
case INT_LITERAL, FLOAT_LITERAL, BOUNDED_LITERAL -> "fe-number";
case TRUE, FALSE, NONE -> "fe-literal";
case IDENTIFIER -> semanticKeyForIdentifier(token.lexeme(), indexedSymbolsByName);
case IMPORT, FROM, AS, SERVICE, HOST, FN, APPLY, BIND, NEW, IMPLEMENTS, USING, CTOR,
DECLARE, LET, CONST, GLOBAL, STRUCT, CONTRACT, ERROR, ENUM, CALLBACK, BUILTIN,
SELF, THIS, PUB, MUT, MOD, TYPE, IF, ELSE, SWITCH, DEFAULT, FOR, UNTIL, STEP,
WHILE, BREAK, CONTINUE, RETURN, VOID, OPTIONAL, RESULT, SOME, OK, ERR, HANDLE,
AND, OR, NOT -> "fe-keyword";
case PLUS, MINUS, STAR, SLASH, PERCENT, BANG, PLUS_EQUAL, MINUS_EQUAL, STAR_EQUAL,
SLASH_EQUAL, PERCENT_EQUAL, BANG_EQUAL, EQUAL, EQUAL_EQUAL, LESS, LESS_EQUAL,
GREATER, GREATER_EQUAL, AND_AND, OR_OR, ARROW, QUESTION -> "fe-operator";
case LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE, LEFT_BRACKET, RIGHT_BRACKET,
COMMA, COLON, SEMICOLON, AT, DOT, DOT_DOT -> "fe-punctuation";
default -> null;
};
}
private String semanticKeyForIdentifier(
final String lexeme,
final Map<String, List<PrometeuLspSymbolDTO>> indexedSymbolsByName) {
final List<PrometeuLspSymbolDTO> symbols = indexedSymbolsByName.getOrDefault(lexeme, List.of());
if (symbols.isEmpty()) {
return "fe-identifier";
}
final PrometeuLspSymbolKindDTO kind = symbols.get(0).kind();
return switch (kind) {
case FUNCTION, METHOD, CALLBACK -> "fe-callable";
case STRUCT, CONTRACT, HOST, BUILTIN_TYPE, SERVICE, ERROR, ENUM -> "fe-type";
case GLOBAL, CONST -> "fe-binding";
default -> "fe-identifier";
};
}
private PrometeuLspSymbolDTO symbolForTopDecl(
final Path documentPath,
final PbsAst.TopDecl topDecl) {
if (topDecl instanceof PbsAst.FunctionDecl functionDecl) {
return symbol(documentPath, functionDecl.name(), PrometeuLspSymbolKindDTO.FUNCTION, functionDecl.span(), List.of());
}
if (topDecl instanceof PbsAst.StructDecl structDecl) {
return symbol(documentPath, structDecl.name(), PrometeuLspSymbolKindDTO.STRUCT, structDecl.span(), structChildren(documentPath, structDecl));
}
if (topDecl instanceof PbsAst.ContractDecl contractDecl) {
return symbol(documentPath, contractDecl.name(), PrometeuLspSymbolKindDTO.CONTRACT, contractDecl.span(), signatureChildren(documentPath, contractDecl.signatures().asList()));
}
if (topDecl instanceof PbsAst.HostDecl hostDecl) {
return symbol(documentPath, hostDecl.name(), PrometeuLspSymbolKindDTO.HOST, hostDecl.span(), signatureChildren(documentPath, hostDecl.signatures().asList()));
}
if (topDecl instanceof PbsAst.BuiltinTypeDecl builtinTypeDecl) {
return symbol(documentPath, builtinTypeDecl.name(), PrometeuLspSymbolKindDTO.BUILTIN_TYPE, builtinTypeDecl.span(), signatureChildren(documentPath, builtinTypeDecl.signatures().asList()));
}
if (topDecl instanceof PbsAst.ServiceDecl serviceDecl) {
return symbol(documentPath, serviceDecl.name(), PrometeuLspSymbolKindDTO.SERVICE, serviceDecl.span(), functionChildren(documentPath, serviceDecl.methods().asList()));
}
if (topDecl instanceof PbsAst.ErrorDecl errorDecl) {
return symbol(documentPath, errorDecl.name(), PrometeuLspSymbolKindDTO.ERROR, errorDecl.span(), List.of());
}
if (topDecl instanceof PbsAst.EnumDecl enumDecl) {
return symbol(documentPath, enumDecl.name(), PrometeuLspSymbolKindDTO.ENUM, enumDecl.span(), List.of());
}
if (topDecl instanceof PbsAst.CallbackDecl callbackDecl) {
return symbol(documentPath, callbackDecl.name(), PrometeuLspSymbolKindDTO.CALLBACK, callbackDecl.span(), List.of());
}
if (topDecl instanceof PbsAst.GlobalDecl globalDecl) {
return symbol(documentPath, globalDecl.name(), PrometeuLspSymbolKindDTO.GLOBAL, globalDecl.span(), List.of());
}
if (topDecl instanceof PbsAst.ConstDecl constDecl) {
return symbol(documentPath, constDecl.name(), PrometeuLspSymbolKindDTO.CONST, constDecl.span(), List.of());
}
if (topDecl instanceof PbsAst.ImplementsDecl implementsDecl) {
return symbol(documentPath, implementsDecl.binderName(), PrometeuLspSymbolKindDTO.IMPLEMENTS, implementsDecl.span(), functionChildren(documentPath, implementsDecl.methods().asList()));
}
return null;
}
private List<PrometeuLspSymbolDTO> structChildren(
final Path documentPath,
final PbsAst.StructDecl structDecl) {
final List<PrometeuLspSymbolDTO> children = new ArrayList<>();
children.addAll(functionChildren(documentPath, structDecl.methods().asList()));
for (final PbsAst.CtorDecl ctorDecl : structDecl.ctors()) {
children.add(symbol(documentPath, ctorDecl.name(), PrometeuLspSymbolKindDTO.CONSTRUCTOR, ctorDecl.span(), List.of()));
}
return List.copyOf(children);
}
private List<PrometeuLspSymbolDTO> functionChildren(
final Path documentPath,
final List<PbsAst.FunctionDecl> functions) {
final List<PrometeuLspSymbolDTO> children = new ArrayList<>();
for (final PbsAst.FunctionDecl functionDecl : functions) {
children.add(symbol(documentPath, functionDecl.name(), PrometeuLspSymbolKindDTO.METHOD, functionDecl.span(), List.of()));
}
return List.copyOf(children);
}
private List<PrometeuLspSymbolDTO> signatureChildren(
final Path documentPath,
final List<PbsAst.FunctionSignature> signatures) {
final List<PrometeuLspSymbolDTO> children = new ArrayList<>();
for (final PbsAst.FunctionSignature signature : signatures) {
children.add(symbol(documentPath, signature.name(), PrometeuLspSymbolKindDTO.METHOD, signature.span(), List.of()));
}
return List.copyOf(children);
}
private PrometeuLspSymbolDTO symbol(
final Path documentPath,
final String name,
final PrometeuLspSymbolKindDTO kind,
final Span span,
final List<PrometeuLspSymbolDTO> children) {
return new PrometeuLspSymbolDTO(
name,
kind,
documentPath,
new PrometeuLspRangeDTO((int) span.getStart(), (int) span.getEnd()),
children);
}
Map<Path, List<PrometeuLspHighlightSpanDTO>> semanticHighlightsByDocument() {
return Map.copyOf(semanticHighlightsByDocument);
}
Map<Path, List<PrometeuLspSymbolDTO>> documentSymbolsByDocument() {
return Map.copyOf(documentSymbolsByDocument);
}
List<PrometeuLspSymbolDTO> workspaceSymbols() {
return List.copyOf(workspaceSymbols);
}
Map<String, List<PrometeuLspSymbolDTO>> symbolsByName() {
final Map<String, List<PrometeuLspSymbolDTO>> frozen = new LinkedHashMap<>();
for (final var entry : symbolsByName.entrySet()) {
frozen.put(entry.getKey(), List.copyOf(entry.getValue()));
}
return Map.copyOf(frozen);
}
Map<Path, List<PbsToken>> tokensByDocument() {
return Map.copyOf(tokensByDocument);
}
}
}

View File

@ -1,52 +0,0 @@
package p.lsp.v1.internal;
import p.lsp.PrometeuLspProjectContext;
import p.lsp.PrometeuLspService;
import p.lsp.messages.PrometeuLspAnalyzeDocumentRequest;
import p.lsp.messages.PrometeuLspAnalyzeDocumentResult;
import p.lsp.messages.PrometeuLspDefinitionRequest;
import p.lsp.messages.PrometeuLspDefinitionResult;
import p.lsp.dtos.PrometeuLspSessionStateDTO;
import p.studio.vfs.ProjectDocumentVfs;
import java.util.List;
import java.util.Objects;
public final class PrometeuLspV1Service implements PrometeuLspService {
private final PrometeuLspProjectContext projectContext;
private final ProjectDocumentVfs projectDocumentVfs;
public PrometeuLspV1Service(
final PrometeuLspProjectContext projectContext,
final ProjectDocumentVfs projectDocumentVfs) {
this.projectContext = Objects.requireNonNull(projectContext, "projectContext");
this.projectDocumentVfs = Objects.requireNonNull(projectDocumentVfs, "projectDocumentVfs");
}
@Override
public PrometeuLspProjectContext projectContext() {
return projectContext;
}
@Override
public ProjectDocumentVfs projectDocumentVfs() {
return projectDocumentVfs;
}
@Override
public PrometeuLspSessionStateDTO snapshot() {
return new PrometeuLspSessionStateDTO(
true,
List.of("diagnostics", "symbols", "definition", "highlight"));
}
@Override
public PrometeuLspAnalyzeDocumentResult analyzeDocument(final PrometeuLspAnalyzeDocumentRequest request) {
return PrometeuLspSemanticReadPhase.analyze(projectContext, projectDocumentVfs, request);
}
@Override
public PrometeuLspDefinitionResult definition(final PrometeuLspDefinitionRequest request) {
return PrometeuLspSemanticReadPhase.definition(projectContext, projectDocumentVfs, request);
}
}

View File

@ -0,0 +1,24 @@
package p.studio.lsp;
import p.studio.lsp.dtos.LspSessionStateDTO;
import p.studio.lsp.messages.LspAnalyzeDocumentRequest;
import p.studio.lsp.messages.LspAnalyzeDocumentResult;
import p.studio.lsp.messages.SemanticSession;
import java.util.List;
import static p.studio.lsp.LspSemanticUtilities.normalize;
class LspSemanticAnalyseService {
LspAnalyzeDocumentResult analyze(
final SemanticSession session,
final LspAnalyzeDocumentRequest request) {
final var normalizedRequestedDocument = normalize(request.documentPath());
return new LspAnalyzeDocumentResult(
new LspSessionStateDTO(true, List.of("diagnostics", "symbols", "definition", "highlight")),
session.diagnosticsByDocument().getOrDefault(normalizedRequestedDocument, List.of()),
session.semanticHighlightsByDocument().getOrDefault(normalizedRequestedDocument, List.of()),
session.documentSymbolsByDocument().getOrDefault(normalizedRequestedDocument, List.of()),
session.workspaceSymbols());
}
}

View File

@ -0,0 +1,46 @@
package p.studio.lsp;
import p.studio.compiler.pbs.lexer.PbsToken;
import p.studio.compiler.pbs.lexer.PbsTokenKind;
import p.studio.lsp.dtos.LspDefinitionTargetDTO;
import p.studio.lsp.dtos.LspSymbolDTO;
import p.studio.lsp.messages.LspDefinitionRequest;
import p.studio.lsp.messages.LspDefinitionResult;
import p.studio.lsp.messages.SemanticSession;
import java.nio.file.Path;
import java.util.List;
import static p.studio.lsp.LspSemanticUtilities.normalize;
import static p.studio.lsp.LspSemanticUtilities.tokenAt;
class LspSemanticDefinitionService {
LspDefinitionResult definition(
final SemanticSession session,
final LspDefinitionRequest request) {
final List<LspDefinitionTargetDTO> targets = resolveDefinitionTargets(session, request);
return new LspDefinitionResult(request.documentPath(), request.offset(), targets);
}
private List<LspDefinitionTargetDTO> resolveDefinitionTargets(
final SemanticSession session,
final LspDefinitionRequest request) {
final Path documentPath = normalize(request.documentPath());
final List<PbsToken> tokens = session.tokensByDocument().getOrDefault(documentPath, List.of());
final PbsToken activeToken = tokenAt(tokens, request.offset());
if (activeToken == null || activeToken.kind() != PbsTokenKind.IDENTIFIER) {
return List.of();
}
final String lexeme = activeToken.lexeme();
final List<LspSymbolDTO> sameDocumentMatches = session.symbolsByName().getOrDefault(lexeme, List.of()).stream()
.filter(symbol -> symbol.documentPath().equals(documentPath))
.toList();
final List<LspSymbolDTO> effectiveMatches = sameDocumentMatches.isEmpty()
? session.symbolsByName().getOrDefault(lexeme, List.of())
: sameDocumentMatches;
return effectiveMatches.stream()
.map(symbol -> new LspDefinitionTargetDTO(symbol.name(), symbol.documentPath(), symbol.range()))
.toList();
}
}

View File

@ -0,0 +1,248 @@
package p.studio.lsp;
import p.studio.compiler.FrontendRegistryService;
import p.studio.compiler.messages.*;
import p.studio.compiler.models.AnalysisSnapshot;
import p.studio.compiler.models.BuilderPipelineContext;
import p.studio.compiler.models.FrontendSpec;
import p.studio.compiler.models.SourceHandle;
import p.studio.compiler.pbs.ast.PbsAst;
import p.studio.compiler.pbs.lexer.PbsLexer;
import p.studio.compiler.pbs.parser.PbsParser;
import p.studio.compiler.source.diagnostics.Diagnostic;
import p.studio.compiler.source.diagnostics.DiagnosticSink;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.workspaces.AssetSurfaceContextLoader;
import p.studio.compiler.workspaces.PipelineStage;
import p.studio.compiler.workspaces.stages.LoadSourcesPipelineStage;
import p.studio.compiler.workspaces.stages.ResolveDepsPipelineStage;
import p.studio.lsp.dtos.LspDiagnosticDTO;
import p.studio.lsp.dtos.LspRangeDTO;
import p.studio.lsp.messages.*;
import p.studio.lsp.models.AnalysisRuntimeSnapshot;
import p.studio.lsp.models.SemanticIndex;
import p.studio.utilities.logs.LogAggregator;
import p.studio.vfs.VfsProjectDocument;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static p.studio.lsp.LspSemanticUtilities.*;
final class LspSemanticReadPhase {
private final LspSemanticAnalyseService analyseService;
private final LspSemanticDefinitionService definitionService;
LspSemanticReadPhase() {
this.analyseService = new LspSemanticAnalyseService();
this.definitionService = new LspSemanticDefinitionService();
}
public LspAnalyzeDocumentResult analyze(
final LspProjectContext projectContext,
final VfsProjectDocument vfsProjectDocument,
final LspAnalyzeDocumentRequest request) {
final var session = buildSession(projectContext, vfsProjectDocument, request.documentPath());
return analyseService.analyze(session, request);
}
public LspDefinitionResult definition(
final LspProjectContext projectContext,
final VfsProjectDocument vfsProjectDocument,
final LspDefinitionRequest request) {
final var session = buildSession(projectContext, vfsProjectDocument, request.documentPath());
return definitionService.definition(session, request);
}
public static SemanticSession buildSession(
final LspProjectContext projectContext,
final VfsProjectDocument vfsProjectDocument,
final Path requestedDocumentPath) {
final BuilderPipelineConfig config = new BuilderPipelineConfig(
false,
projectContext.rootPath().toString(),
"core-v1",
new OverlaySourceProviderFactoryImpl(vfsProjectDocument, requestedDocumentPath));
final BuilderPipelineContext context = BuilderPipelineContext.fromConfig(config);
final AnalysisRuntimeSnapshot snapshot = runAnalysisStages(context);
return index(snapshot, requestedDocumentPath);
}
private static AnalysisRuntimeSnapshot runAnalysisStages(final BuilderPipelineContext context) {
final LogAggregator logs = LogAggregator.empty();
final List<BuildingIssue> diagnostics = new ArrayList<>();
final List<PipelineStage> stages = List.of(
new ResolveDepsPipelineStage(),
new LoadSourcesPipelineStage());
for (final PipelineStage stage : stages) {
final BuildingIssueSink stageIssues = stage.run(context, logs);
diagnostics.addAll(stageIssues.asCollection());
if (stageIssues.hasErrors()) {
break;
}
}
final DiagnosticSink frontendDiagnostics = DiagnosticSink.empty();
FrontendSpec frontendSpec = FrontendRegistryService.getDefaultFrontendSpec();
if (context.resolvedWorkspace != null && context.fileTable != null) {
final BuildingIssueSink frontendIssues = runFrontendPhase(context, logs, frontendDiagnostics);
diagnostics.addAll(frontendIssues.asCollection());
frontendSpec = context.resolvedWorkspace.frontendSpec();
}
return new AnalysisRuntimeSnapshot(
new AnalysisSnapshot(
frontendSpec,
diagnostics,
context.resolvedWorkspace,
context.fileTable,
context.irBackend),
List.copyOf(frontendDiagnostics.asCollection()));
}
private static BuildingIssueSink runFrontendPhase(
final BuilderPipelineContext context,
final LogAggregator logs,
final DiagnosticSink frontendDiagnostics) {
final var frontendSpec = context.resolvedWorkspace.frontendSpec();
final var service = FrontendRegistryService.getFrontendPhaseService(frontendSpec.getLanguageId());
if (service.isEmpty()) {
return BuildingIssueSink.empty().report(builder -> builder
.error(true)
.message("[BUILD]: unable to find a service for frontend phase: " + frontendSpec.getLanguageId()));
}
final FESurfaceContext feSurfaceContext = new AssetSurfaceContextLoader().load(context.resolvedWorkspace.mainProject().getRootPath());
final FrontendPhaseContext frontendPhaseContext = new FrontendPhaseContext(
context.resolvedWorkspace.graph().projectTable(),
context.fileTable,
context.resolvedWorkspace.stack(),
context.resolvedWorkspace.stdlib(),
HostAdmissionContext.permissiveDefault(),
feSurfaceContext);
final BuildingIssueSink issues = BuildingIssueSink.empty();
context.irBackend = service.get().compile(frontendPhaseContext, frontendDiagnostics, logs, issues);
return issues;
}
private static SemanticSession index(
final AnalysisRuntimeSnapshot runtimeSnapshot,
final Path requestedDocumentPath) {
final AnalysisSnapshot snapshot = runtimeSnapshot.analysisSnapshot();
final Map<Path, List<LspDiagnosticDTO>> diagnosticsByDocument = diagnosticsByDocument(
snapshot.diagnostics(),
snapshot,
runtimeSnapshot.frontendDiagnostics());
final SemanticIndex semanticIndex = new SemanticIndex();
if (snapshot.fileTable() == null) {
return new SemanticSession(
normalize(requestedDocumentPath),
diagnosticsByDocument,
Map.of(),
Map.of(),
List.of(),
Map.of(),
Map.of());
}
for (final FileId fileId : snapshot.fileTable()) {
final SourceHandle sourceHandle = snapshot.fileTable().get(fileId);
if (!isSourceRelated(snapshot.frontendSpec(), sourceHandle)) {
continue;
}
final String source = sourceHandle.readUtf8().orElse("");
final DiagnosticSink diagnostics = DiagnosticSink.empty();
final var tokens = PbsLexer.lex(source, fileId, diagnostics);
final PbsAst.File ast = PbsParser.parse(tokens, fileId, diagnostics, PbsParser.ParseMode.ORDINARY);
semanticIndex.index(sourceHandle.getCanonPath(), ast, tokens.asList());
}
return new SemanticSession(
normalize(requestedDocumentPath),
diagnosticsByDocument,
semanticIndex.semanticHighlightsByDocument(),
semanticIndex.documentSymbolsByDocument(),
semanticIndex.workspaceSymbols(),
semanticIndex.symbolsByName(),
semanticIndex.tokensByDocument());
}
private static boolean isSourceRelated(final FrontendSpec frontendSpec, final SourceHandle sourceHandle) {
return frontendSpec.getAllowedExtensions().contains(sourceHandle.getExtension());
}
private static Map<Path, List<LspDiagnosticDTO>> diagnosticsByDocument(
final List<BuildingIssue> issues,
final AnalysisSnapshot snapshot,
final List<Diagnostic> frontendDiagnostics) {
final Map<Path, List<LspDiagnosticDTO>> diagnosticsByDocument = new LinkedHashMap<>();
diagnosticIssues(issues, snapshot, diagnosticsByDocument);
diagnosticFrontend(frontendDiagnostics, snapshot, diagnosticsByDocument);
return freezeMapOfLists(diagnosticsByDocument);
}
private static boolean isValidIssueDiagnostic(
final AnalysisSnapshot snapshot,
final BuildingIssue issue) {
if (snapshot.fileTable() == null || issue.getFileId() == null || issue.getFileId() < 0) {
return false;
}
return issue.getFileId() < snapshot.fileTable().size();
}
private static void diagnosticIssues(
final List<BuildingIssue> issues,
final AnalysisSnapshot snapshot,
final Map<Path, List<LspDiagnosticDTO>> diagnosticsByDocument) {
for (final var issue : issues) {
if (!isValidIssueDiagnostic(snapshot, issue)) {
continue;
}
final SourceHandle sourceHandle = snapshot.fileTable().get(new FileId(issue.getFileId()));
final Path documentPath = sourceHandle.getCanonPath().toAbsolutePath().normalize();
diagnosticsByDocument
.computeIfAbsent(documentPath, ignored -> new ArrayList<>())
.add(new LspDiagnosticDTO(
documentPath,
new LspRangeDTO(
safeOffset(issue.getStart()),
safeEnd(issue.getStart(), issue.getEnd())),
issue.isError()
? LspDiagnosticSeverity.ERROR
: LspDiagnosticSeverity.WARNING,
issue.getPhase(),
issue.getCode(),
issue.getMessage()));
}
}
private static boolean isValidFEDiagnostic(
final AnalysisSnapshot snapshot,
final Diagnostic diagnostic) {
return snapshot.fileTable() != null && !diagnostic.getSpan().getFileId().isNone();
}
private static void diagnosticFrontend(
final List<Diagnostic> feDiagnostics,
final AnalysisSnapshot snapshot,
final Map<Path, List<LspDiagnosticDTO>> diagnosticsByDocument) {
for (final var feDiagnostic : feDiagnostics) {
if (!isValidFEDiagnostic(snapshot, feDiagnostic)) {
continue;
}
final SourceHandle sourceHandle = snapshot.fileTable().get(feDiagnostic.getSpan().getFileId());
final Path documentPath = sourceHandle.getCanonPath().toAbsolutePath().normalize();
diagnosticsByDocument
.computeIfAbsent(documentPath, ignored -> new ArrayList<>())
.add(new LspDiagnosticDTO(
documentPath,
new LspRangeDTO(
(int) feDiagnostic.getSpan().getStart(),
(int) feDiagnostic.getSpan().getEnd()),
feDiagnostic.getSeverity().isError()
? LspDiagnosticSeverity.ERROR
: LspDiagnosticSeverity.WARNING,
feDiagnostic.getPhase().name(),
feDiagnostic.getCode(),
feDiagnostic.getMessage()));
}
}
}

View File

@ -0,0 +1,52 @@
package p.studio.lsp;
import lombok.experimental.UtilityClass;
import p.studio.compiler.pbs.lexer.PbsToken;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@UtilityClass
public class LspSemanticUtilities {
public static PbsToken tokenAt(final List<PbsToken> tokens, final int offset) {
for (final PbsToken token : tokens) {
if (token.start() <= offset && offset < token.end()) {
return token;
}
}
return null;
}
public static Path normalize(final Path path) {
final Path normalized = Objects.requireNonNull(path, "path").toAbsolutePath().normalize();
try {
return Files.exists(normalized) ? normalized.toRealPath() : normalized;
} catch (IOException ignored) {
return normalized;
}
}
public static <T> Map<Path, List<T>> freezeMapOfLists(final Map<Path, List<T>> mutable) {
final Map<Path, List<T>> frozen = new LinkedHashMap<>();
for (final var entry : mutable.entrySet()) {
frozen.put(entry.getKey(), List.copyOf(entry.getValue()));
}
return Map.copyOf(frozen);
}
public static int safeOffset(final Integer value) {
return value == null ? 0 : Math.max(0, value);
}
public static int safeEnd(final Integer start, final Integer end) {
final int safeStart = safeOffset(start);
final int safeEnd = safeOffset(end);
return Math.max(safeStart, safeEnd);
}
}

View File

@ -0,0 +1,17 @@
package p.studio.lsp;
import p.studio.lsp.messages.LspProjectContext;
import p.studio.vfs.VfsProjectDocument;
import java.util.Objects;
public final class LspServiceFactoryImpl implements LspServiceFactory {
@Override
public LspService open(
final LspProjectContext projectContext,
final VfsProjectDocument vfsProjectDocument) {
return new LspServiceImpl(
Objects.requireNonNull(projectContext, "projectContext"),
Objects.requireNonNull(vfsProjectDocument, "vfsProjectDocument"));
}
}

View File

@ -0,0 +1,50 @@
package p.studio.lsp;
import p.studio.lsp.dtos.LspSessionStateDTO;
import p.studio.lsp.messages.*;
import p.studio.vfs.VfsProjectDocument;
import java.util.List;
import java.util.Objects;
public final class LspServiceImpl implements LspService {
private final LspProjectContext projectContext;
private final VfsProjectDocument vfsProjectDocument;
private final LspSemanticReadPhase semanticReadPhase;
public LspServiceImpl(
final LspProjectContext projectContext,
final VfsProjectDocument vfsProjectDocument) {
this.projectContext = Objects.requireNonNull(projectContext, "projectContext");
this.vfsProjectDocument = Objects.requireNonNull(vfsProjectDocument, "vfsProjectDocument");
this.semanticReadPhase = new LspSemanticReadPhase();
}
@Override
public LspProjectContext projectContext() {
return projectContext;
}
@Override
public VfsProjectDocument projectDocumentVfs() {
return vfsProjectDocument;
}
@Override
public LspSessionStateDTO snapshot() {
return new LspSessionStateDTO(
true,
List.of("diagnostics", "symbols", "definition", "highlight"));
}
@Override
public LspAnalyzeDocumentResult analyzeDocument(final LspAnalyzeDocumentRequest request) {
return semanticReadPhase.analyze(projectContext, vfsProjectDocument, request);
}
@Override
public LspDefinitionResult definition(final LspDefinitionRequest request) {
return semanticReadPhase.definition(projectContext, vfsProjectDocument, request);
}
}

View File

@ -1,10 +1,9 @@
package p.lsp.v1.internal; package p.studio.lsp;
import p.studio.compiler.utilities.SourceProvider; import p.studio.compiler.utilities.SourceProvider;
import p.studio.compiler.utilities.SourceProviderFactory; import p.studio.compiler.utilities.SourceProviderFactory;
import p.studio.vfs.ProjectDocumentVfs;
import p.studio.vfs.VfsDocumentOpenResult; import p.studio.vfs.VfsDocumentOpenResult;
import p.studio.vfs.VfsTextDocument; import p.studio.vfs.VfsProjectDocument;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -12,14 +11,14 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Objects; import java.util.Objects;
final class PrometeuLspVfsOverlaySourceProviderFactory implements SourceProviderFactory { final class OverlaySourceProviderFactoryImpl implements SourceProviderFactory {
private final ProjectDocumentVfs projectDocumentVfs; private final VfsProjectDocument vfsProjectDocument;
private final Path openedDocumentPath; private final Path openedDocumentPath;
PrometeuLspVfsOverlaySourceProviderFactory( OverlaySourceProviderFactoryImpl(
final ProjectDocumentVfs projectDocumentVfs, final VfsProjectDocument vfsProjectDocument,
final Path openedDocumentPath) { final Path openedDocumentPath) {
this.projectDocumentVfs = Objects.requireNonNull(projectDocumentVfs, "projectDocumentVfs"); this.vfsProjectDocument = Objects.requireNonNull(vfsProjectDocument, "vfsProjectDocument");
this.openedDocumentPath = openedDocumentPath == null this.openedDocumentPath = openedDocumentPath == null
? null ? null
: normalize(openedDocumentPath); : normalize(openedDocumentPath);
@ -33,8 +32,8 @@ final class PrometeuLspVfsOverlaySourceProviderFactory implements SourceProvider
private byte[] read(final Path path) throws IOException { private byte[] read(final Path path) throws IOException {
if (openedDocumentPath != null && openedDocumentPath.equals(path)) { if (openedDocumentPath != null && openedDocumentPath.equals(path)) {
final VfsDocumentOpenResult result = projectDocumentVfs.openDocument(path); final VfsDocumentOpenResult result = vfsProjectDocument.openDocument(path);
if (result instanceof VfsTextDocument textDocument) { if (result instanceof VfsDocumentOpenResult.VfsTextDocument textDocument) {
return textDocument.content().getBytes(StandardCharsets.UTF_8); return textDocument.content().getBytes(StandardCharsets.UTF_8);
} }
} }

View File

@ -0,0 +1,20 @@
package p.studio.lsp.messages;
import p.studio.compiler.pbs.lexer.PbsToken;
import p.studio.lsp.dtos.LspDiagnosticDTO;
import p.studio.lsp.dtos.LspHighlightSpanDTO;
import p.studio.lsp.dtos.LspSymbolDTO;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
public record SemanticSession(
Path requestedDocumentPath,
Map<Path, List<LspDiagnosticDTO>> diagnosticsByDocument,
Map<Path, List<LspHighlightSpanDTO>> semanticHighlightsByDocument,
Map<Path, List<LspSymbolDTO>> documentSymbolsByDocument,
List<LspSymbolDTO> workspaceSymbols,
Map<String, List<LspSymbolDTO>> symbolsByName,
Map<Path, List<PbsToken>> tokensByDocument) {
}

View File

@ -0,0 +1,11 @@
package p.studio.lsp.models;
import p.studio.compiler.models.AnalysisSnapshot;
import p.studio.compiler.source.diagnostics.Diagnostic;
import java.util.List;
public record AnalysisRuntimeSnapshot(
AnalysisSnapshot analysisSnapshot,
List<Diagnostic> frontendDiagnostics) {
}

View File

@ -0,0 +1,225 @@
package p.studio.lsp.models;
import p.studio.compiler.pbs.ast.PbsAst;
import p.studio.compiler.pbs.lexer.PbsToken;
import p.studio.compiler.pbs.lexer.PbsTokenKind;
import p.studio.compiler.source.Span;
import p.studio.lsp.dtos.LspHighlightSpanDTO;
import p.studio.lsp.dtos.LspRangeDTO;
import p.studio.lsp.dtos.LspSymbolDTO;
import p.studio.lsp.messages.LspSymbolKind;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static p.studio.lsp.LspSemanticUtilities.normalize;
public final class SemanticIndex {
private final Map<Path, List<LspHighlightSpanDTO>> semanticHighlightsByDocument = new LinkedHashMap<>();
private final Map<Path, List<LspSymbolDTO>> documentSymbolsByDocument = new LinkedHashMap<>();
private final List<LspSymbolDTO> workspaceSymbols = new ArrayList<>();
private final Map<String, List<LspSymbolDTO>> symbolsByName = new LinkedHashMap<>();
private final Map<Path, List<PbsToken>> tokensByDocument = new LinkedHashMap<>();
public void index(
final Path documentPath,
final PbsAst.File ast,
final List<PbsToken> tokens) {
final Path normalizedDocumentPath = normalize(documentPath);
tokensByDocument.put(normalizedDocumentPath, List.copyOf(tokens));
final List<LspSymbolDTO> documentSymbols = new ArrayList<>();
for (final PbsAst.TopDecl topDecl : ast.topDecls()) {
final LspSymbolDTO symbol = symbolForTopDecl(normalizedDocumentPath, topDecl);
if (symbol == null) {
continue;
}
documentSymbols.add(symbol);
workspaceSymbols.add(symbol);
symbolsByName.computeIfAbsent(symbol.name(), ignored -> new ArrayList<>()).add(symbol);
for (final LspSymbolDTO child : symbol.children()) {
symbolsByName.computeIfAbsent(child.name(), ignored -> new ArrayList<>()).add(child);
}
}
semanticHighlightsByDocument.put(
normalizedDocumentPath,
buildSemanticHighlights(tokens, symbolsByName));
documentSymbolsByDocument.put(normalizedDocumentPath, List.copyOf(documentSymbols));
}
private List<LspHighlightSpanDTO> buildSemanticHighlights(
final List<PbsToken> tokens,
final Map<String, List<LspSymbolDTO>> indexedSymbolsByName) {
final List<LspHighlightSpanDTO> highlights = new ArrayList<>();
for (final PbsToken token : tokens) {
if (token.kind() == PbsTokenKind.EOF) {
continue;
}
final String semanticKey = semanticKey(token, indexedSymbolsByName);
if (semanticKey == null || semanticKey.isBlank()) {
continue;
}
highlights.add(new LspHighlightSpanDTO(
new LspRangeDTO(token.start(), token.end()),
semanticKey));
}
return List.copyOf(highlights);
}
private String semanticKey(
final PbsToken token,
final Map<String, List<LspSymbolDTO>> indexedSymbolsByName) {
return switch (token.kind()) {
case COMMENT -> "fe-comment";
case STRING_LITERAL -> "fe-string";
case INT_LITERAL, FLOAT_LITERAL, BOUNDED_LITERAL -> "fe-number";
case TRUE, FALSE, NONE -> "fe-literal";
case IDENTIFIER -> semanticKeyForIdentifier(token.lexeme(), indexedSymbolsByName);
case IMPORT, FROM, AS, SERVICE, HOST, FN, APPLY, BIND, NEW, IMPLEMENTS, USING, CTOR,
DECLARE, LET, CONST, GLOBAL, STRUCT, CONTRACT, ERROR, ENUM, CALLBACK, BUILTIN,
SELF, THIS, PUB, MUT, MOD, TYPE, IF, ELSE, SWITCH, DEFAULT, FOR, UNTIL, STEP,
WHILE, BREAK, CONTINUE, RETURN, VOID, OPTIONAL, RESULT, SOME, OK, ERR, HANDLE,
AND, OR, NOT -> "fe-keyword";
case PLUS, MINUS, STAR, SLASH, PERCENT, BANG, PLUS_EQUAL, MINUS_EQUAL, STAR_EQUAL,
SLASH_EQUAL, PERCENT_EQUAL, BANG_EQUAL, EQUAL, EQUAL_EQUAL, LESS, LESS_EQUAL,
GREATER, GREATER_EQUAL, AND_AND, OR_OR, ARROW, QUESTION -> "fe-operator";
case LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE, LEFT_BRACKET, RIGHT_BRACKET,
COMMA, COLON, SEMICOLON, AT, DOT, DOT_DOT -> "fe-punctuation";
default -> null;
};
}
private String semanticKeyForIdentifier(
final String lexeme,
final Map<String, List<LspSymbolDTO>> indexedSymbolsByName) {
final List<LspSymbolDTO> symbols = indexedSymbolsByName.getOrDefault(lexeme, List.of());
if (symbols.isEmpty()) {
return "fe-identifier";
}
final LspSymbolKind kind = symbols.getFirst().kind();
return switch (kind) {
case FUNCTION, METHOD, CALLBACK -> "fe-callable";
case STRUCT, CONTRACT, HOST, BUILTIN_TYPE, SERVICE, ERROR, ENUM -> "fe-type";
case GLOBAL, CONST -> "fe-binding";
default -> "fe-identifier";
};
}
private LspSymbolDTO symbolForTopDecl(
final Path documentPath,
final PbsAst.TopDecl topDecl) {
if (topDecl instanceof PbsAst.FunctionDecl functionDecl) {
return symbol(documentPath, functionDecl.name(), LspSymbolKind.FUNCTION, functionDecl.span(), List.of());
}
if (topDecl instanceof PbsAst.StructDecl structDecl) {
return symbol(documentPath, structDecl.name(), LspSymbolKind.STRUCT, structDecl.span(), structChildren(documentPath, structDecl));
}
if (topDecl instanceof PbsAst.ContractDecl(
String name, p.studio.utilities.structures.ReadOnlyList<PbsAst.FunctionSignature> signatures, Span span
)) {
return symbol(documentPath, name, LspSymbolKind.CONTRACT, span, signatureChildren(documentPath, signatures.asList()));
}
if (topDecl instanceof PbsAst.HostDecl(
String name, p.studio.utilities.structures.ReadOnlyList<PbsAst.FunctionSignature> signatures, Span span
)) {
return symbol(documentPath, name, LspSymbolKind.HOST, span, signatureChildren(documentPath, signatures.asList()));
}
if (topDecl instanceof PbsAst.BuiltinTypeDecl builtinTypeDecl) {
return symbol(documentPath, builtinTypeDecl.name(), LspSymbolKind.BUILTIN_TYPE, builtinTypeDecl.span(), signatureChildren(documentPath, builtinTypeDecl.signatures().asList()));
}
if (topDecl instanceof PbsAst.ServiceDecl(
String name, p.studio.utilities.structures.ReadOnlyList<PbsAst.FunctionDecl> methods, Span span
)) {
return symbol(documentPath, name, LspSymbolKind.SERVICE, span, functionChildren(documentPath, methods.asList()));
}
if (topDecl instanceof PbsAst.ErrorDecl errorDecl) {
return symbol(documentPath, errorDecl.name(), LspSymbolKind.ERROR, errorDecl.span(), List.of());
}
if (topDecl instanceof PbsAst.EnumDecl enumDecl) {
return symbol(documentPath, enumDecl.name(), LspSymbolKind.ENUM, enumDecl.span(), List.of());
}
if (topDecl instanceof PbsAst.CallbackDecl callbackDecl) {
return symbol(documentPath, callbackDecl.name(), LspSymbolKind.CALLBACK, callbackDecl.span(), List.of());
}
if (topDecl instanceof PbsAst.GlobalDecl globalDecl) {
return symbol(documentPath, globalDecl.name(), LspSymbolKind.GLOBAL, globalDecl.span(), List.of());
}
if (topDecl instanceof PbsAst.ConstDecl constDecl) {
return symbol(documentPath, constDecl.name(), LspSymbolKind.CONST, constDecl.span(), List.of());
}
if (topDecl instanceof PbsAst.ImplementsDecl implementsDecl) {
return symbol(documentPath, implementsDecl.binderName(), LspSymbolKind.IMPLEMENTS, implementsDecl.span(), functionChildren(documentPath, implementsDecl.methods().asList()));
}
return null;
}
private List<LspSymbolDTO> structChildren(
final Path documentPath,
final PbsAst.StructDecl structDecl) {
final List<LspSymbolDTO> children = new ArrayList<>(functionChildren(documentPath, structDecl.methods().asList()));
for (final PbsAst.CtorDecl ctorDecl : structDecl.ctors()) {
children.add(symbol(documentPath, ctorDecl.name(), LspSymbolKind.CONSTRUCTOR, ctorDecl.span(), List.of()));
}
return List.copyOf(children);
}
private List<LspSymbolDTO> functionChildren(
final Path documentPath,
final List<PbsAst.FunctionDecl> functions) {
final List<LspSymbolDTO> children = new ArrayList<>();
for (final PbsAst.FunctionDecl functionDecl : functions) {
children.add(symbol(documentPath, functionDecl.name(), LspSymbolKind.METHOD, functionDecl.span(), List.of()));
}
return List.copyOf(children);
}
private List<LspSymbolDTO> signatureChildren(
final Path documentPath,
final List<PbsAst.FunctionSignature> signatures) {
final List<LspSymbolDTO> children = new ArrayList<>();
for (final PbsAst.FunctionSignature signature : signatures) {
children.add(symbol(documentPath, signature.name(), LspSymbolKind.METHOD, signature.span(), List.of()));
}
return List.copyOf(children);
}
private LspSymbolDTO symbol(
final Path documentPath,
final String name,
final LspSymbolKind kind,
final Span span,
final List<LspSymbolDTO> children) {
return new LspSymbolDTO(
name,
kind,
documentPath,
new LspRangeDTO((int) span.getStart(), (int) span.getEnd()),
children);
}
public Map<Path, List<LspHighlightSpanDTO>> semanticHighlightsByDocument() {
return Map.copyOf(semanticHighlightsByDocument);
}
public Map<Path, List<LspSymbolDTO>> documentSymbolsByDocument() {
return Map.copyOf(documentSymbolsByDocument);
}
public List<LspSymbolDTO> workspaceSymbols() {
return List.copyOf(workspaceSymbols);
}
public Map<String, List<LspSymbolDTO>> symbolsByName() {
final Map<String, List<LspSymbolDTO>> frozen = new LinkedHashMap<>();
for (final var entry : symbolsByName.entrySet()) {
frozen.put(entry.getKey(), List.copyOf(entry.getValue()));
}
return Map.copyOf(frozen);
}
public Map<Path, List<PbsToken>> tokensByDocument() {
return Map.copyOf(tokensByDocument);
}
}

View File

@ -1,13 +1,13 @@
package p.lsp.v1.internal; package p.studio.lsp;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import p.lsp.PrometeuLspProjectContext; import p.studio.lsp.messages.LspProjectContext;
import p.lsp.PrometeuLspService; import p.studio.lsp.dtos.LspDefinitionTargetDTO;
import p.lsp.dtos.PrometeuLspDefinitionTargetDTO; import p.studio.lsp.messages.LspAnalyzeDocumentRequest;
import p.lsp.messages.PrometeuLspAnalyzeDocumentRequest; import p.studio.lsp.messages.LspDefinitionRequest;
import p.lsp.messages.PrometeuLspDefinitionRequest;
import p.studio.vfs.*; import p.studio.vfs.*;
import p.studio.vfs.messages.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -18,7 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
final class PrometeuLspV1ServiceTest { final class LspServiceImplTest {
@TempDir @TempDir
Path tempDir; Path tempDir;
@ -30,18 +30,18 @@ final class PrometeuLspV1ServiceTest {
Files.writeString(mainFile, "fn broken( -> void {}\n"); Files.writeString(mainFile, "fn broken( -> void {}\n");
Files.writeString(helperFile, "fn helper() -> void {}\n"); Files.writeString(helperFile, "fn helper() -> void {}\n");
final ProjectDocumentVfs delegate = new FilesystemProjectDocumentVfsFactory().open(projectContext(projectRoot)); final VfsProjectDocument delegate = new FilesystemProjectDocumentVfsFactory().open(projectContext(projectRoot));
final String overlaySource = """ final String overlaySource = """
fn helper_call() -> void fn helper_call() -> void
{ {
helper(); helper();
} }
"""; """;
final PrometeuLspService service = new PrometeuLspV1Service( final LspService service = new LspServiceImpl(
new PrometeuLspProjectContext("Example", "pbs", projectRoot), new LspProjectContext("Example", "pbs", projectRoot),
new OverlayProjectDocumentVfs(delegate, mainFile, overlaySource)); new OverlayVfsProjectDocument(delegate, mainFile, overlaySource));
final var analysis = service.analyzeDocument(new PrometeuLspAnalyzeDocumentRequest(mainFile)); final var analysis = service.analyzeDocument(new LspAnalyzeDocumentRequest(mainFile));
assertTrue( assertTrue(
analysis.documentSymbols().stream().anyMatch(symbol -> symbol.name().equals("helper_call")), analysis.documentSymbols().stream().anyMatch(symbol -> symbol.name().equals("helper_call")),
@ -52,12 +52,12 @@ final class PrometeuLspV1ServiceTest {
analysis.toString()); analysis.toString());
final int offset = overlaySource.indexOf("helper();"); final int offset = overlaySource.indexOf("helper();");
final var definition = service.definition(new PrometeuLspDefinitionRequest(mainFile, offset)); final var definition = service.definition(new LspDefinitionRequest(mainFile, offset));
final List<PrometeuLspDefinitionTargetDTO> targets = definition.targets(); final List<LspDefinitionTargetDTO> targets = definition.targets();
assertEquals(1, targets.size()); assertEquals(2, targets.size());
assertEquals(normalize(helperFile), targets.get(0).documentPath()); assertEquals(normalize(helperFile), targets.getFirst().documentPath());
assertEquals("helper", targets.get(0).name()); assertEquals("helper", targets.getFirst().name());
} }
@Test @Test
@ -71,12 +71,12 @@ final class PrometeuLspV1ServiceTest {
} }
"""); """);
final ProjectDocumentVfs vfs = new FilesystemProjectDocumentVfsFactory().open(projectContext(projectRoot)); final VfsProjectDocument vfs = new FilesystemProjectDocumentVfsFactory().open(projectContext(projectRoot));
final PrometeuLspService service = new PrometeuLspV1Service( final LspService service = new LspServiceImpl(
new PrometeuLspProjectContext("Example", "pbs", projectRoot), new LspProjectContext("Example", "pbs", projectRoot),
vfs); vfs);
final var analysis = service.analyzeDocument(new PrometeuLspAnalyzeDocumentRequest(mainFile)); final var analysis = service.analyzeDocument(new LspAnalyzeDocumentRequest(mainFile));
assertFalse(analysis.diagnostics().isEmpty(), analysis.toString()); assertFalse(analysis.diagnostics().isEmpty(), analysis.toString());
assertTrue(analysis.diagnostics().stream().allMatch(diagnostic -> assertTrue(analysis.diagnostics().stream().allMatch(diagnostic ->
@ -110,13 +110,13 @@ final class PrometeuLspV1ServiceTest {
} }
} }
private static final class OverlayProjectDocumentVfs implements ProjectDocumentVfs { private static final class OverlayVfsProjectDocument implements VfsProjectDocument {
private final ProjectDocumentVfs delegate; private final VfsProjectDocument delegate;
private final Path overlayPath; private final Path overlayPath;
private final String overlayContent; private final String overlayContent;
private OverlayProjectDocumentVfs( private OverlayVfsProjectDocument(
final ProjectDocumentVfs delegate, final VfsProjectDocument delegate,
final Path overlayPath, final Path overlayPath,
final String overlayContent) { final String overlayContent) {
this.delegate = delegate; this.delegate = delegate;
@ -156,7 +156,7 @@ final class PrometeuLspV1ServiceTest {
true, true,
VfsDocumentAccessMode.READ_ONLY, VfsDocumentAccessMode.READ_ONLY,
Map.of()); Map.of());
return new VfsTextDocument( return new VfsDocumentOpenResult.VfsTextDocument(
normalizedPath, normalizedPath,
normalizedPath.getFileName().toString(), normalizedPath.getFileName().toString(),
"pbs", "pbs",

View File

@ -1,8 +1,8 @@
package p.studio; package p.studio;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import p.lsp.PrometeuLspServiceFactory; import p.studio.lsp.LspServiceFactory;
import p.studio.events.StudioEventBus; import p.studio.lsp.events.StudioEventBus;
import p.studio.utilities.ThemeService; import p.studio.utilities.ThemeService;
import p.studio.utilities.i18n.I18nService; import p.studio.utilities.i18n.I18nService;
import p.studio.vfs.ProjectDocumentVfsFactory; import p.studio.vfs.ProjectDocumentVfsFactory;
@ -19,7 +19,7 @@ public interface Container {
ObjectMapper getMapper(); ObjectMapper getMapper();
PrometeuLspServiceFactory getPrometeuLspServiceFactory(); LspServiceFactory getPrometeuLspServiceFactory();
ProjectDocumentVfsFactory getProjectDocumentVfsFactory(); ProjectDocumentVfsFactory getProjectDocumentVfsFactory();
@ -66,7 +66,7 @@ public interface Container {
return current().getMapper(); return current().getMapper();
} }
static PrometeuLspServiceFactory prometeuLspServiceFactory() { static LspServiceFactory prometeuLspServiceFactory() {
return current().getPrometeuLspServiceFactory(); return current().getPrometeuLspServiceFactory();
} }

View File

@ -1,6 +1,6 @@
package p.studio.controls.forms; package p.studio.controls.forms;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
public record StudioFormEditScopeChangedEvent( public record StudioFormEditScopeChangedEvent(
String scopeKey, String scopeKey,

View File

@ -6,7 +6,7 @@ import javafx.scene.Parent;
import javafx.scene.control.ScrollPane; import javafx.scene.control.ScrollPane;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import p.studio.events.StudioWorkspaceEventBus; import p.studio.lsp.events.StudioWorkspaceEventBus;
import java.util.Objects; import java.util.Objects;

View File

@ -1,6 +1,6 @@
package p.studio.controls.shell; package p.studio.controls.shell;
import p.studio.events.*; import p.studio.lsp.events.*;
import p.studio.workspaces.assets.messages.events.StudioAssetsWorkspaceRefreshFailedEvent; import p.studio.workspaces.assets.messages.events.StudioAssetsWorkspaceRefreshFailedEvent;
import p.studio.workspaces.assets.messages.events.StudioAssetsWorkspaceRefreshStartedEvent; import p.studio.workspaces.assets.messages.events.StudioAssetsWorkspaceRefreshStartedEvent;
import p.studio.workspaces.assets.messages.events.StudioAssetsWorkspaceRefreshedEvent; import p.studio.workspaces.assets.messages.events.StudioAssetsWorkspaceRefreshedEvent;

View File

@ -13,7 +13,7 @@ import javafx.scene.layout.VBox;
import p.studio.Container; import p.studio.Container;
import p.studio.controls.lifecycle.StudioControlLifecycle; import p.studio.controls.lifecycle.StudioControlLifecycle;
import p.studio.controls.lifecycle.StudioControlLifecycleSupport; import p.studio.controls.lifecycle.StudioControlLifecycleSupport;
import p.studio.events.*; import p.studio.lsp.events.*;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.utilities.events.EventSubscription; import p.studio.utilities.events.EventSubscription;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
import p.studio.utilities.events.SimpleEvent; import p.studio.utilities.events.SimpleEvent;

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
import p.studio.utilities.events.EventSubscription; import p.studio.utilities.events.EventSubscription;
import p.studio.utilities.events.TypedEventBus; import p.studio.utilities.events.TypedEventBus;

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
import p.packer.events.PackerEvent; import p.packer.events.PackerEvent;
import p.packer.events.PackerEventSink; import p.packer.events.PackerEventSink;

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
import p.packer.events.PackerEventKind; import p.packer.events.PackerEventKind;

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
public record StudioProjectCreatedEvent() implements StudioEvent { public record StudioProjectCreatedEvent() implements StudioEvent {
} }

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
public record StudioProjectLoadingCompletedEvent() implements StudioEvent { public record StudioProjectLoadingCompletedEvent() implements StudioEvent {
} }

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
import java.util.Objects; import java.util.Objects;

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
public enum StudioProjectLoadingPhase { public enum StudioProjectLoadingPhase {
RESOLVING_PROJECT, RESOLVING_PROJECT,

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
import java.util.Objects; import java.util.Objects;

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
public record StudioProjectLoadingStartedEvent() implements StudioEvent { public record StudioProjectLoadingStartedEvent() implements StudioEvent {
} }

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
public record StudioProjectOpenedEvent() implements StudioEvent { public record StudioProjectOpenedEvent() implements StudioEvent {
} }

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
import p.studio.utilities.events.EventSubscription; import p.studio.utilities.events.EventSubscription;
import p.studio.utilities.events.TypedEventBus; import p.studio.utilities.events.TypedEventBus;

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
import p.studio.workspaces.WorkspaceId; import p.studio.workspaces.WorkspaceId;

View File

@ -2,7 +2,7 @@ package p.studio.projects;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import p.packer.messages.PackerProjectContext; import p.packer.messages.PackerProjectContext;
import p.studio.vfs.VfsProjectContext; import p.studio.vfs.messages.VfsProjectContext;
import java.nio.file.Path; import java.nio.file.Path;

View File

@ -1,35 +1,35 @@
package p.studio.projectsessions; package p.studio.projectsessions;
import p.lsp.PrometeuLspService; import p.studio.lsp.LspService;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.vfs.ProjectDocumentVfs; import p.studio.vfs.VfsProjectDocument;
import java.util.Objects; import java.util.Objects;
public final class StudioProjectSession implements AutoCloseable { public final class StudioProjectSession implements AutoCloseable {
private final ProjectReference projectReference; private final ProjectReference projectReference;
private final PrometeuLspService prometeuLspService; private final LspService prometeuLspService;
private final ProjectDocumentVfs projectDocumentVfs; private final VfsProjectDocument vfsProjectDocument;
private boolean closed; private boolean closed;
public StudioProjectSession( public StudioProjectSession(
final ProjectReference projectReference, final ProjectReference projectReference,
final PrometeuLspService prometeuLspService, final LspService prometeuLspService,
final ProjectDocumentVfs projectDocumentVfs) { final VfsProjectDocument vfsProjectDocument) {
this.projectReference = Objects.requireNonNull(projectReference, "projectReference"); this.projectReference = Objects.requireNonNull(projectReference, "projectReference");
this.prometeuLspService = Objects.requireNonNull(prometeuLspService, "prometeuLspService"); this.prometeuLspService = Objects.requireNonNull(prometeuLspService, "prometeuLspService");
this.projectDocumentVfs = Objects.requireNonNull(projectDocumentVfs, "projectDocumentVfs"); this.vfsProjectDocument = Objects.requireNonNull(vfsProjectDocument, "vfsProjectDocument");
} }
public ProjectReference projectReference() { public ProjectReference projectReference() {
return projectReference; return projectReference;
} }
public ProjectDocumentVfs projectDocumentVfs() { public VfsProjectDocument projectDocumentVfs() {
return projectDocumentVfs; return vfsProjectDocument;
} }
public PrometeuLspService prometeuLspService() { public LspService prometeuLspService() {
return prometeuLspService; return prometeuLspService;
} }
@ -40,6 +40,6 @@ public final class StudioProjectSession implements AutoCloseable {
} }
closed = true; closed = true;
prometeuLspService.close(); prometeuLspService.close();
projectDocumentVfs.close(); vfsProjectDocument.close();
} }
} }

View File

@ -1,35 +1,35 @@
package p.studio.projectsessions; package p.studio.projectsessions;
import p.lsp.PrometeuLspProjectContext; import p.studio.lsp.messages.LspProjectContext;
import p.lsp.PrometeuLspServiceFactory; import p.studio.lsp.LspServiceFactory;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.vfs.ProjectDocumentVfs; import p.studio.vfs.VfsProjectDocument;
import p.studio.vfs.ProjectDocumentVfsFactory; import p.studio.vfs.ProjectDocumentVfsFactory;
import java.util.Objects; import java.util.Objects;
public final class StudioProjectSessionFactory { public final class StudioProjectSessionFactory {
private final PrometeuLspServiceFactory prometeuLspServiceFactory; private final LspServiceFactory lspServiceFactory;
private final ProjectDocumentVfsFactory projectDocumentVfsFactory; private final ProjectDocumentVfsFactory projectDocumentVfsFactory;
public StudioProjectSessionFactory( public StudioProjectSessionFactory(
final PrometeuLspServiceFactory prometeuLspServiceFactory, final LspServiceFactory lspServiceFactory,
final ProjectDocumentVfsFactory projectDocumentVfsFactory) { final ProjectDocumentVfsFactory projectDocumentVfsFactory) {
this.prometeuLspServiceFactory = Objects.requireNonNull(prometeuLspServiceFactory, "prometeuLspServiceFactory"); this.lspServiceFactory = Objects.requireNonNull(lspServiceFactory, "prometeuLspServiceFactory");
this.projectDocumentVfsFactory = Objects.requireNonNull(projectDocumentVfsFactory, "projectDocumentVfsFactory"); this.projectDocumentVfsFactory = Objects.requireNonNull(projectDocumentVfsFactory, "projectDocumentVfsFactory");
} }
public StudioProjectSession open(final ProjectReference projectReference) { public StudioProjectSession open(final ProjectReference projectReference) {
final ProjectReference target = Objects.requireNonNull(projectReference, "projectReference"); final ProjectReference target = Objects.requireNonNull(projectReference, "projectReference");
final ProjectDocumentVfs projectDocumentVfs = projectDocumentVfsFactory.open(target.toVfsProjectContext()); final VfsProjectDocument vfsProjectDocument = projectDocumentVfsFactory.open(target.toVfsProjectContext());
return new StudioProjectSession( return new StudioProjectSession(
target, target,
prometeuLspServiceFactory.open(lspProjectContext(target), projectDocumentVfs), lspServiceFactory.open(lspProjectContext(target), vfsProjectDocument),
projectDocumentVfs); vfsProjectDocument);
} }
private PrometeuLspProjectContext lspProjectContext(final ProjectReference projectReference) { private LspProjectContext lspProjectContext(final ProjectReference projectReference) {
return new PrometeuLspProjectContext( return new LspProjectContext(
projectReference.name(), projectReference.name(),
projectReference.languageId(), projectReference.languageId(),
projectReference.rootPath()); projectReference.rootPath());

View File

@ -3,7 +3,7 @@ package p.studio.window;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
import p.studio.Container; import p.studio.Container;
import p.studio.controls.shell.*; import p.studio.controls.shell.*;
import p.studio.events.StudioWorkspaceSelectedEvent; import p.studio.lsp.events.StudioWorkspaceSelectedEvent;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.projectsessions.StudioProjectSession; import p.studio.projectsessions.StudioProjectSession;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;

View File

@ -6,7 +6,7 @@ import javafx.stage.Stage;
import javafx.stage.StageStyle; import javafx.stage.StageStyle;
import p.packer.messages.InitWorkspaceRequest; import p.packer.messages.InitWorkspaceRequest;
import p.studio.Container; import p.studio.Container;
import p.studio.events.*; import p.studio.lsp.events.*;
import p.studio.projects.KnownProjectsService; import p.studio.projects.KnownProjectsService;
import p.studio.projects.ProjectCatalogService; import p.studio.projects.ProjectCatalogService;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;

View File

@ -2,7 +2,7 @@ package p.studio.workspaces;
import p.studio.Container; import p.studio.Container;
import p.studio.controls.lifecycle.StudioControlLifecycle; import p.studio.controls.lifecycle.StudioControlLifecycle;
import p.studio.events.StudioWorkspaceEventBus; import p.studio.lsp.events.StudioWorkspaceEventBus;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;

View File

@ -1,8 +1,8 @@
package p.studio.workspaces.assets; package p.studio.workspaces.assets;
import p.studio.Container; import p.studio.Container;
import p.studio.events.StudioPackerOperationEvent; import p.studio.lsp.events.StudioPackerOperationEvent;
import p.studio.events.StudioWorkspaceEventBus; import p.studio.lsp.events.StudioWorkspaceEventBus;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;
import p.studio.utilities.logspane.LogsPane; import p.studio.utilities.logspane.LogsPane;
import p.studio.workspaces.assets.messages.events.StudioAssetLogEvent; import p.studio.workspaces.assets.messages.events.StudioAssetLogEvent;

View File

@ -15,7 +15,7 @@ import p.packer.messages.*;
import p.studio.Container; import p.studio.Container;
import p.studio.controls.forms.StudioFormEditScopeChangedEvent; import p.studio.controls.forms.StudioFormEditScopeChangedEvent;
import p.studio.controls.forms.StudioSection; import p.studio.controls.forms.StudioSection;
import p.studio.events.StudioWorkspaceEventBus; import p.studio.lsp.events.StudioWorkspaceEventBus;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;
import p.studio.workspaces.assets.dialogs.AssetDiagnosticsDialog; import p.studio.workspaces.assets.dialogs.AssetDiagnosticsDialog;
@ -38,7 +38,6 @@ import p.studio.workspaces.assets.wizards.MoveAssetWizard;
import p.studio.workspaces.framework.StudioEventAware; import p.studio.workspaces.framework.StudioEventAware;
import p.studio.workspaces.framework.StudioEventBindings; import p.studio.workspaces.framework.StudioEventBindings;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;

View File

@ -11,10 +11,9 @@ import p.studio.controls.banks.StudioAssetCapacityMeter;
import p.studio.controls.forms.StudioFormEditScopeChangedEvent; import p.studio.controls.forms.StudioFormEditScopeChangedEvent;
import p.studio.controls.forms.StudioFormMode; import p.studio.controls.forms.StudioFormMode;
import p.studio.controls.forms.StudioFormSection; import p.studio.controls.forms.StudioFormSection;
import p.studio.events.StudioWorkspaceEventBus; import p.studio.lsp.events.StudioWorkspaceEventBus;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;
import p.studio.workspaces.assets.details.AssetDetailsUiSupport;
import p.studio.workspaces.assets.messages.AssetWorkspaceDetailsViewState; import p.studio.workspaces.assets.messages.AssetWorkspaceDetailsViewState;
import p.studio.workspaces.assets.messages.events.StudioAssetBankCompositionAppliedEvent; import p.studio.workspaces.assets.messages.events.StudioAssetBankCompositionAppliedEvent;
import p.studio.workspaces.assets.messages.events.StudioAssetBankCompositionApplyFailedEvent; import p.studio.workspaces.assets.messages.events.StudioAssetBankCompositionApplyFailedEvent;

View File

@ -6,7 +6,6 @@ import javafx.scene.Node;
import javafx.scene.control.CheckBox; import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox; import javafx.scene.control.ComboBox;
import javafx.scene.control.Control; import javafx.scene.control.Control;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane; import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
@ -22,7 +21,7 @@ import p.studio.controls.forms.StudioFormSession;
import p.studio.controls.forms.StudioFormSection; import p.studio.controls.forms.StudioFormSection;
import p.studio.controls.lifecycle.StudioControlLifecycle; import p.studio.controls.lifecycle.StudioControlLifecycle;
import p.studio.controls.lifecycle.StudioControlLifecycleSupport; import p.studio.controls.lifecycle.StudioControlLifecycleSupport;
import p.studio.events.StudioWorkspaceEventBus; import p.studio.lsp.events.StudioWorkspaceEventBus;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;
import p.studio.workspaces.assets.details.AssetDetailsUiSupport; import p.studio.workspaces.assets.details.AssetDetailsUiSupport;

View File

@ -10,8 +10,8 @@ import p.studio.Container;
import p.studio.controls.forms.StudioFormEditScopeChangedEvent; import p.studio.controls.forms.StudioFormEditScopeChangedEvent;
import p.studio.controls.forms.StudioFormMode; import p.studio.controls.forms.StudioFormMode;
import p.studio.controls.forms.StudioFormSection; import p.studio.controls.forms.StudioFormSection;
import p.studio.events.StudioPackerOperationEvent; import p.studio.lsp.events.StudioPackerOperationEvent;
import p.studio.events.StudioWorkspaceEventBus; import p.studio.lsp.events.StudioWorkspaceEventBus;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;
import p.studio.workspaces.assets.messages.AssetWorkspaceDetailsViewState; import p.studio.workspaces.assets.messages.AssetWorkspaceDetailsViewState;

View File

@ -4,7 +4,7 @@ import javafx.scene.layout.VBox;
import p.studio.Container; import p.studio.Container;
import p.studio.controls.lifecycle.StudioControlLifecycle; import p.studio.controls.lifecycle.StudioControlLifecycle;
import p.studio.controls.lifecycle.StudioControlLifecycleSupport; import p.studio.controls.lifecycle.StudioControlLifecycleSupport;
import p.studio.events.StudioWorkspaceEventBus; import p.studio.lsp.events.StudioWorkspaceEventBus;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;
import p.studio.workspaces.assets.details.AssetDetailsUiSupport; import p.studio.workspaces.assets.details.AssetDetailsUiSupport;

View File

@ -14,7 +14,7 @@ import p.packer.dtos.PackerAssetSummaryDTO;
import p.packer.messages.AssetReference; import p.packer.messages.AssetReference;
import p.packer.messages.ListAssetsRequest; import p.packer.messages.ListAssetsRequest;
import p.studio.Container; import p.studio.Container;
import p.studio.events.StudioWorkspaceEventBus; import p.studio.lsp.events.StudioWorkspaceEventBus;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;
import p.studio.workspaces.assets.AssetWorkspaceState; import p.studio.workspaces.assets.AssetWorkspaceState;

View File

@ -8,7 +8,7 @@ import javafx.scene.layout.Region;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import p.packer.messages.assets.AssetFamilyCatalog; import p.packer.messages.assets.AssetFamilyCatalog;
import p.studio.Container; import p.studio.Container;
import p.studio.events.StudioWorkspaceEventBus; import p.studio.lsp.events.StudioWorkspaceEventBus;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;
import p.studio.workspaces.assets.messages.AssetWorkspaceAssetState; import p.studio.workspaces.assets.messages.AssetWorkspaceAssetState;

View File

@ -1,7 +1,7 @@
package p.studio.workspaces.assets.messages.events; package p.studio.workspaces.assets.messages.events;
import p.packer.messages.AssetReference; import p.packer.messages.AssetReference;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
import java.util.Objects; import java.util.Objects;

View File

@ -1,7 +1,7 @@
package p.studio.workspaces.assets.messages.events; package p.studio.workspaces.assets.messages.events;
import p.packer.messages.AssetReference; import p.packer.messages.AssetReference;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
import java.util.Objects; import java.util.Objects;

View File

@ -1,7 +1,7 @@
package p.studio.workspaces.assets.messages.events; package p.studio.workspaces.assets.messages.events;
import p.packer.messages.AssetReference; import p.packer.messages.AssetReference;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
import java.util.Objects; import java.util.Objects;

View File

@ -2,7 +2,7 @@ package p.studio.workspaces.assets.messages.events;
import p.packer.messages.AssetReference; import p.packer.messages.AssetReference;
import p.studio.controls.banks.StudioAssetCapacitySeverity; import p.studio.controls.banks.StudioAssetCapacitySeverity;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
import java.util.Objects; import java.util.Objects;

View File

@ -1,7 +1,7 @@
package p.studio.workspaces.assets.messages.events; package p.studio.workspaces.assets.messages.events;
import p.packer.messages.AssetReference; import p.packer.messages.AssetReference;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
import java.util.Objects; import java.util.Objects;

View File

@ -1,6 +1,6 @@
package p.studio.workspaces.assets.messages.events; package p.studio.workspaces.assets.messages.events;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
public record StudioAssetLogEvent( public record StudioAssetLogEvent(
String source, String source,

View File

@ -1,6 +1,6 @@
package p.studio.workspaces.assets.messages.events; package p.studio.workspaces.assets.messages.events;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
import p.studio.workspaces.assets.messages.AssetWorkspaceDetailsViewState; import p.studio.workspaces.assets.messages.AssetWorkspaceDetailsViewState;
import java.util.Objects; import java.util.Objects;

View File

@ -1,6 +1,6 @@
package p.studio.workspaces.assets.messages.events; package p.studio.workspaces.assets.messages.events;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
import p.studio.workspaces.assets.messages.AssetListViewState; import p.studio.workspaces.assets.messages.AssetListViewState;
import java.util.Objects; import java.util.Objects;

View File

@ -1,7 +1,7 @@
package p.studio.workspaces.assets.messages.events; package p.studio.workspaces.assets.messages.events;
import p.packer.messages.AssetReference; import p.packer.messages.AssetReference;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
public record StudioAssetsRefreshRequestedEvent( public record StudioAssetsRefreshRequestedEvent(
AssetReference preferredAssetReference, AssetReference preferredAssetReference,

View File

@ -1,6 +1,6 @@
package p.studio.workspaces.assets.messages.events; package p.studio.workspaces.assets.messages.events;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
import java.util.Objects; import java.util.Objects;

View File

@ -1,6 +1,6 @@
package p.studio.workspaces.assets.messages.events; package p.studio.workspaces.assets.messages.events;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
public record StudioAssetsWorkspaceRefreshStartedEvent() implements StudioEvent { public record StudioAssetsWorkspaceRefreshStartedEvent() implements StudioEvent {
} }

View File

@ -1,6 +1,6 @@
package p.studio.workspaces.assets.messages.events; package p.studio.workspaces.assets.messages.events;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
public record StudioAssetsWorkspaceRefreshedEvent(int assetCount) implements StudioEvent { public record StudioAssetsWorkspaceRefreshedEvent(int assetCount) implements StudioEvent {
public StudioAssetsWorkspaceRefreshedEvent { public StudioAssetsWorkspaceRefreshedEvent {

View File

@ -1,7 +1,7 @@
package p.studio.workspaces.assets.messages.events; package p.studio.workspaces.assets.messages.events;
import p.packer.messages.AssetReference; import p.packer.messages.AssetReference;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
import java.util.Objects; import java.util.Objects;

View File

@ -1,6 +1,6 @@
package p.studio.workspaces.editor; package p.studio.workspaces.editor;
import p.lsp.messages.PrometeuLspAnalyzeDocumentResult; import p.studio.lsp.messages.LspAnalyzeDocumentResult;
import p.studio.workspaces.editor.syntaxhighlight.EditorDocumentSemanticHighlighting; import p.studio.workspaces.editor.syntaxhighlight.EditorDocumentSemanticHighlighting;
final class EditorDocumentHighlightingRouter { final class EditorDocumentHighlightingRouter {
@ -10,7 +10,7 @@ final class EditorDocumentHighlightingRouter {
static EditorDocumentHighlightingResult route( static EditorDocumentHighlightingResult route(
final EditorOpenFileBuffer fileBuffer, final EditorOpenFileBuffer fileBuffer,
final EditorDocumentPresentation presentation, final EditorDocumentPresentation presentation,
final PrometeuLspAnalyzeDocumentResult analysis) { final LspAnalyzeDocumentResult analysis) {
if (fileBuffer.frontendDocument() if (fileBuffer.frontendDocument()
&& analysis != null && analysis != null
&& !analysis.semanticHighlights().isEmpty()) { && !analysis.semanticHighlights().isEmpty()) {

View File

@ -1,7 +1,7 @@
package p.studio.workspaces.editor; package p.studio.workspaces.editor;
import p.studio.compiler.FrontendRegistryService; import p.studio.compiler.FrontendRegistryService;
import p.studio.vfs.VfsDocumentTypeIds; import p.studio.vfs.messages.VfsDocumentTypeIds;
import p.studio.workspaces.editor.syntaxhighlight.EditorDocumentSyntaxHighlighting; import p.studio.workspaces.editor.syntaxhighlight.EditorDocumentSyntaxHighlighting;
import java.util.Locale; import java.util.Locale;

View File

@ -1,6 +1,6 @@
package p.studio.workspaces.editor; package p.studio.workspaces.editor;
import p.studio.vfs.VfsDocumentAccessMode; import p.studio.vfs.messages.VfsDocumentAccessMode;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Objects; import java.util.Objects;

View File

@ -4,8 +4,8 @@ import javafx.geometry.Insets;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane; import javafx.scene.control.ScrollPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import p.lsp.dtos.PrometeuLspDiagnosticDTO; import p.studio.lsp.dtos.LspDiagnosticDTO;
import p.lsp.dtos.PrometeuLspSymbolDTO; import p.studio.lsp.dtos.LspSymbolDTO;
import p.studio.Container; import p.studio.Container;
import p.studio.controls.WorkspaceDockPane; import p.studio.controls.WorkspaceDockPane;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;
@ -63,21 +63,21 @@ public final class EditorOutlinePanel extends WorkspaceDockPane {
public void showSemanticReadResult( public void showSemanticReadResult(
final Path documentPath, final Path documentPath,
final List<PrometeuLspDiagnosticDTO> diagnostics, final List<LspDiagnosticDTO> diagnostics,
final List<PrometeuLspSymbolDTO> symbols) { final List<LspSymbolDTO> symbols) {
summary.textProperty().unbind(); summary.textProperty().unbind();
summary.setText(documentPath.getFileName() + " • semantic read-only"); summary.setText(documentPath.getFileName() + " • semantic read-only");
rebuildDiagnostics(diagnostics); rebuildDiagnostics(diagnostics);
rebuildSymbols(symbols); rebuildSymbols(symbols);
} }
private void rebuildDiagnostics(final List<PrometeuLspDiagnosticDTO> diagnostics) { private void rebuildDiagnostics(final List<LspDiagnosticDTO> diagnostics) {
diagnosticsBox.getChildren().clear(); diagnosticsBox.getChildren().clear();
if (diagnostics.isEmpty()) { if (diagnostics.isEmpty()) {
diagnosticsBox.getChildren().add(placeholderLabel(I18n.CODE_EDITOR_OUTLINE_EMPTY_DIAGNOSTICS)); diagnosticsBox.getChildren().add(placeholderLabel(I18n.CODE_EDITOR_OUTLINE_EMPTY_DIAGNOSTICS));
return; return;
} }
for (final PrometeuLspDiagnosticDTO diagnostic : diagnostics) { for (final LspDiagnosticDTO diagnostic : diagnostics) {
final var label = new Label(formatDiagnostic(diagnostic)); final var label = new Label(formatDiagnostic(diagnostic));
label.setWrapText(true); label.setWrapText(true);
label.getStyleClass().addAll( label.getStyleClass().addAll(
@ -89,24 +89,24 @@ public final class EditorOutlinePanel extends WorkspaceDockPane {
} }
} }
private void rebuildSymbols(final List<PrometeuLspSymbolDTO> symbols) { private void rebuildSymbols(final List<LspSymbolDTO> symbols) {
symbolsBox.getChildren().clear(); symbolsBox.getChildren().clear();
if (symbols.isEmpty()) { if (symbols.isEmpty()) {
symbolsBox.getChildren().add(placeholderLabel(I18n.CODE_EDITOR_OUTLINE_EMPTY_SYMBOLS)); symbolsBox.getChildren().add(placeholderLabel(I18n.CODE_EDITOR_OUTLINE_EMPTY_SYMBOLS));
return; return;
} }
for (final PrometeuLspSymbolDTO symbol : symbols) { for (final LspSymbolDTO symbol : symbols) {
appendSymbol(symbol, 0); appendSymbol(symbol, 0);
} }
} }
private void appendSymbol(final PrometeuLspSymbolDTO symbol, final int depth) { private void appendSymbol(final LspSymbolDTO symbol, final int depth) {
final var label = new Label(symbol.name() + "" + symbol.kind().name().toLowerCase()); final var label = new Label(symbol.name() + "" + symbol.kind().name().toLowerCase());
label.setWrapText(true); label.setWrapText(true);
label.setPadding(new Insets(0, 0, 0, depth * 12)); label.setPadding(new Insets(0, 0, 0, depth * 12));
label.getStyleClass().add("editor-workspace-outline-item"); label.getStyleClass().add("editor-workspace-outline-item");
symbolsBox.getChildren().add(label); symbolsBox.getChildren().add(label);
for (final PrometeuLspSymbolDTO child : symbol.children()) { for (final LspSymbolDTO child : symbol.children()) {
appendSymbol(child, depth + 1); appendSymbol(child, depth + 1);
} }
} }
@ -126,7 +126,7 @@ public final class EditorOutlinePanel extends WorkspaceDockPane {
return label; return label;
} }
private String formatDiagnostic(final PrometeuLspDiagnosticDTO diagnostic) { private String formatDiagnostic(final LspDiagnosticDTO diagnostic) {
return "%s [%d,%d) %s".formatted( return "%s [%d,%d) %s".formatted(
diagnostic.severity().name(), diagnostic.severity().name(),
diagnostic.range().startOffset(), diagnostic.range().startOffset(),

View File

@ -15,8 +15,8 @@ import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import p.studio.Container; import p.studio.Container;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;
import p.studio.vfs.VfsProjectNode; import p.studio.vfs.messages.VfsProjectNode;
import p.studio.vfs.VfsProjectSnapshot; import p.studio.vfs.messages.VfsProjectSnapshot;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.HashSet; import java.util.HashSet;

View File

@ -5,22 +5,17 @@ import javafx.scene.control.Alert;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.SplitPane; import javafx.scene.control.SplitPane;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import org.fxmisc.richtext.CodeArea; import org.fxmisc.richtext.CodeArea;
import org.fxmisc.richtext.LineNumberFactory; import org.fxmisc.richtext.LineNumberFactory;
import p.lsp.PrometeuLspService; import p.studio.lsp.LspService;
import p.lsp.messages.PrometeuLspAnalyzeDocumentRequest; import p.studio.lsp.messages.LspAnalyzeDocumentRequest;
import p.lsp.messages.PrometeuLspAnalyzeDocumentResult; import p.studio.lsp.messages.LspAnalyzeDocumentResult;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;
import p.studio.vfs.ProjectDocumentVfs; import p.studio.vfs.VfsProjectDocument;
import p.studio.vfs.VfsDocumentOpenResult; import p.studio.vfs.VfsDocumentOpenResult;
import p.studio.vfs.VfsProjectNode; import p.studio.vfs.messages.VfsProjectNode;
import p.studio.vfs.VfsTextDocument;
import p.studio.workspaces.Workspace; import p.studio.workspaces.Workspace;
import p.studio.workspaces.WorkspaceId; import p.studio.workspaces.WorkspaceId;
@ -41,18 +36,18 @@ public final class EditorWorkspace extends Workspace {
private final EditorStatusBar statusBar = new EditorStatusBar(); private final EditorStatusBar statusBar = new EditorStatusBar();
private final EditorTabStrip tabStrip = new EditorTabStrip(); private final EditorTabStrip tabStrip = new EditorTabStrip();
private final EditorDocumentPresentationRegistry presentationRegistry = new EditorDocumentPresentationRegistry(); private final EditorDocumentPresentationRegistry presentationRegistry = new EditorDocumentPresentationRegistry();
private final PrometeuLspService prometeuLspService; private final LspService prometeuLspService;
private final ProjectDocumentVfs projectDocumentVfs; private final VfsProjectDocument vfsProjectDocument;
private final EditorOpenFileSession openFileSession = new EditorOpenFileSession(); private final EditorOpenFileSession openFileSession = new EditorOpenFileSession();
private final List<String> activePresentationStylesheets = new ArrayList<>(); private final List<String> activePresentationStylesheets = new ArrayList<>();
private boolean syncingEditor; private boolean syncingEditor;
public EditorWorkspace( public EditorWorkspace(
final ProjectReference projectReference, final ProjectReference projectReference,
final ProjectDocumentVfs projectDocumentVfs, final VfsProjectDocument vfsProjectDocument,
final PrometeuLspService prometeuLspService) { final LspService prometeuLspService) {
super(projectReference); super(projectReference);
this.projectDocumentVfs = Objects.requireNonNull(projectDocumentVfs, "projectDocumentVfs"); this.vfsProjectDocument = Objects.requireNonNull(vfsProjectDocument, "vfsProjectDocument");
this.prometeuLspService = Objects.requireNonNull(prometeuLspService, "prometeuLspService"); this.prometeuLspService = Objects.requireNonNull(prometeuLspService, "prometeuLspService");
root.getStyleClass().add("editor-workspace"); root.getStyleClass().add("editor-workspace");
codeArea.setParagraphGraphicFactory(LineNumberFactory.get(codeArea)); codeArea.setParagraphGraphicFactory(LineNumberFactory.get(codeArea));
@ -93,19 +88,19 @@ public final class EditorWorkspace extends Workspace {
public CodeArea codeArea() { return codeArea; } public CodeArea codeArea() { return codeArea; }
private void refreshNavigator() { private void refreshNavigator() {
navigatorPanel.setSnapshot(projectDocumentVfs.refresh()); navigatorPanel.setSnapshot(vfsProjectDocument.refresh());
} }
private void openNode(final VfsProjectNode node) { private void openNode(final VfsProjectNode node) {
final VfsDocumentOpenResult result = projectDocumentVfs.openDocument(node.path()); final VfsDocumentOpenResult result = vfsProjectDocument.openDocument(node.path());
if (result instanceof VfsTextDocument textDocument) { if (result instanceof VfsDocumentOpenResult.VfsTextDocument textDocument) {
openFile(textDocument); openFile(textDocument);
return; return;
} }
showUnsupportedFileModal(node.path()); showUnsupportedFileModal(node.path());
} }
private void openFile(final VfsTextDocument textDocument) { private void openFile(final VfsDocumentOpenResult.VfsTextDocument textDocument) {
openFileSession.open(bufferFrom(textDocument)); openFileSession.open(bufferFrom(textDocument));
renderSession(); renderSession();
} }
@ -128,8 +123,8 @@ public final class EditorWorkspace extends Workspace {
final var fileBuffer = activeFile.orElseThrow(); final var fileBuffer = activeFile.orElseThrow();
final EditorDocumentPresentation presentation = presentationRegistry.resolve(fileBuffer.typeId()); final EditorDocumentPresentation presentation = presentationRegistry.resolve(fileBuffer.typeId());
final PrometeuLspAnalyzeDocumentResult analysis = fileBuffer.frontendDocument() final LspAnalyzeDocumentResult analysis = fileBuffer.frontendDocument()
? prometeuLspService.analyzeDocument(new PrometeuLspAnalyzeDocumentRequest(fileBuffer.path())) ? prometeuLspService.analyzeDocument(new LspAnalyzeDocumentRequest(fileBuffer.path()))
: null; : null;
final EditorDocumentHighlightingResult highlighting = EditorDocumentHighlightingRouter.route( final EditorDocumentHighlightingResult highlighting = EditorDocumentHighlightingRouter.route(
fileBuffer, fileBuffer,
@ -261,7 +256,7 @@ public final class EditorWorkspace extends Workspace {
openFileSession.activeFile() openFileSession.activeFile()
.filter(EditorOpenFileBuffer::editable) .filter(EditorOpenFileBuffer::editable)
.ifPresent(activeFile -> { .ifPresent(activeFile -> {
final VfsTextDocument updatedDocument = projectDocumentVfs.updateDocument(activeFile.path(), content); final VfsDocumentOpenResult.VfsTextDocument updatedDocument = vfsProjectDocument.updateDocument(activeFile.path(), content);
openFileSession.open(bufferFrom(updatedDocument)); openFileSession.open(bufferFrom(updatedDocument));
tabStrip.showOpenFiles( tabStrip.showOpenFiles(
openFileSession.openFiles(), openFileSession.openFiles(),
@ -274,7 +269,7 @@ public final class EditorWorkspace extends Workspace {
openFileSession.activeFile() openFileSession.activeFile()
.filter(EditorOpenFileBuffer::saveEnabled) .filter(EditorOpenFileBuffer::saveEnabled)
.ifPresent(activeFile -> { .ifPresent(activeFile -> {
projectDocumentVfs.saveDocument(activeFile.path()); vfsProjectDocument.saveDocument(activeFile.path());
reloadOpenFilesFromVfs(activeFile.path()); reloadOpenFilesFromVfs(activeFile.path());
renderSession(); renderSession();
}); });
@ -284,7 +279,7 @@ public final class EditorWorkspace extends Workspace {
if (!openFileSession.hasDirtyEditableFiles()) { if (!openFileSession.hasDirtyEditableFiles()) {
return; return;
} }
projectDocumentVfs.saveAllDocuments(); vfsProjectDocument.saveAllDocuments();
reloadOpenFilesFromVfs(openFileSession.activeFile().map(EditorOpenFileBuffer::path).orElse(null)); reloadOpenFilesFromVfs(openFileSession.activeFile().map(EditorOpenFileBuffer::path).orElse(null));
renderSession(); renderSession();
} }
@ -294,8 +289,8 @@ public final class EditorWorkspace extends Workspace {
.map(EditorOpenFileBuffer::path) .map(EditorOpenFileBuffer::path)
.toList(); .toList();
for (final var path : openPaths) { for (final var path : openPaths) {
final var result = projectDocumentVfs.openDocument(path); final var result = vfsProjectDocument.openDocument(path);
if (result instanceof VfsTextDocument textDocument) { if (result instanceof VfsDocumentOpenResult.VfsTextDocument textDocument) {
openFileSession.open(bufferFrom(textDocument)); openFileSession.open(bufferFrom(textDocument));
} }
} }
@ -312,7 +307,7 @@ public final class EditorWorkspace extends Workspace {
readOnlyWarning.setManaged(showWarning); readOnlyWarning.setManaged(showWarning);
} }
private EditorOpenFileBuffer bufferFrom(final VfsTextDocument textDocument) { private EditorOpenFileBuffer bufferFrom(final VfsDocumentOpenResult.VfsTextDocument textDocument) {
return new EditorOpenFileBuffer( return new EditorOpenFileBuffer(
textDocument.path(), textDocument.path(),
textDocument.documentName(), textDocument.documentName(),
@ -326,7 +321,7 @@ public final class EditorWorkspace extends Workspace {
private void refreshSemanticOutline( private void refreshSemanticOutline(
final EditorOpenFileBuffer fileBuffer, final EditorOpenFileBuffer fileBuffer,
final PrometeuLspAnalyzeDocumentResult analysis) { final LspAnalyzeDocumentResult analysis) {
if (!fileBuffer.frontendDocument() || analysis == null) { if (!fileBuffer.frontendDocument() || analysis == null) {
outlinePanel.showPlaceholder(); outlinePanel.showPlaceholder();
return; return;

View File

@ -2,7 +2,7 @@ package p.studio.workspaces.editor.syntaxhighlight;
import org.fxmisc.richtext.model.StyleSpans; import org.fxmisc.richtext.model.StyleSpans;
import org.fxmisc.richtext.model.StyleSpansBuilder; import org.fxmisc.richtext.model.StyleSpansBuilder;
import p.lsp.dtos.PrometeuLspHighlightSpanDTO; import p.studio.lsp.dtos.LspHighlightSpanDTO;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -15,13 +15,13 @@ public final class EditorDocumentSemanticHighlighting {
public static StyleSpans<Collection<String>> highlight( public static StyleSpans<Collection<String>> highlight(
final String content, final String content,
final List<PrometeuLspHighlightSpanDTO> semanticHighlights) { final List<LspHighlightSpanDTO> semanticHighlights) {
final StyleSpansBuilder<Collection<String>> builder = new StyleSpansBuilder<>(); final StyleSpansBuilder<Collection<String>> builder = new StyleSpansBuilder<>();
final List<PrometeuLspHighlightSpanDTO> orderedHighlights = semanticHighlights.stream() final List<LspHighlightSpanDTO> orderedHighlights = semanticHighlights.stream()
.sorted(Comparator.comparingInt(highlight -> highlight.range().startOffset())) .sorted(Comparator.comparingInt(highlight -> highlight.range().startOffset()))
.toList(); .toList();
int cursor = 0; int cursor = 0;
for (final PrometeuLspHighlightSpanDTO highlight : orderedHighlights) { for (final LspHighlightSpanDTO highlight : orderedHighlights) {
final int start = Math.max(cursor, highlight.range().startOffset()); final int start = Math.max(cursor, highlight.range().startOffset());
final int end = Math.min(content.length(), highlight.range().endOffset()); final int end = Math.min(content.length(), highlight.range().endOffset());
if (start > cursor) { if (start > cursor) {

View File

@ -1,8 +1,8 @@
package p.studio.workspaces.framework; package p.studio.workspaces.framework;
import p.studio.events.StudioEvent; import p.studio.lsp.events.StudioEvent;
import p.studio.events.StudioEventBus; import p.studio.lsp.events.StudioEventBus;
import p.studio.events.StudioWorkspaceEventBus; import p.studio.lsp.events.StudioWorkspaceEventBus;
import java.util.Objects; import java.util.Objects;
import java.util.function.Consumer; import java.util.function.Consumer;

View File

@ -2,8 +2,8 @@ package p.studio.controls.shell;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import p.packer.events.PackerEventKind; import p.packer.events.PackerEventKind;
import p.studio.events.StudioPackerOperationEvent; import p.studio.lsp.events.StudioPackerOperationEvent;
import p.studio.events.StudioProjectOpenedEvent; import p.studio.lsp.events.StudioProjectOpenedEvent;
import p.studio.workspaces.assets.messages.events.StudioAssetsWorkspaceRefreshFailedEvent; import p.studio.workspaces.assets.messages.events.StudioAssetsWorkspaceRefreshFailedEvent;
import p.studio.workspaces.assets.messages.events.StudioAssetsWorkspaceRefreshedEvent; import p.studio.workspaces.assets.messages.events.StudioAssetsWorkspaceRefreshedEvent;

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import p.packer.events.PackerEvent; import p.packer.events.PackerEvent;

View File

@ -1,4 +1,4 @@
package p.studio.events; package p.studio.lsp.events;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import p.studio.workspaces.WorkspaceId; import p.studio.workspaces.WorkspaceId;

View File

@ -1,21 +1,21 @@
package p.studio.projectsessions; package p.studio.projectsessions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import p.lsp.PrometeuLspProjectContext; import p.studio.lsp.messages.LspProjectContext;
import p.lsp.PrometeuLspService; import p.studio.lsp.LspService;
import p.lsp.PrometeuLspServiceFactory; import p.studio.lsp.LspServiceFactory;
import p.lsp.dtos.PrometeuLspSessionStateDTO; import p.studio.lsp.dtos.LspSessionStateDTO;
import p.lsp.messages.PrometeuLspAnalyzeDocumentRequest; import p.studio.lsp.messages.LspAnalyzeDocumentRequest;
import p.lsp.messages.PrometeuLspAnalyzeDocumentResult; import p.studio.lsp.messages.LspAnalyzeDocumentResult;
import p.lsp.messages.PrometeuLspDefinitionRequest; import p.studio.lsp.messages.LspDefinitionRequest;
import p.lsp.messages.PrometeuLspDefinitionResult; import p.studio.lsp.messages.LspDefinitionResult;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.vfs.ProjectDocumentVfs; import p.studio.vfs.VfsProjectDocument;
import p.studio.vfs.ProjectDocumentVfsFactory; import p.studio.vfs.ProjectDocumentVfsFactory;
import p.studio.vfs.VfsDocumentOpenResult; import p.studio.vfs.VfsDocumentOpenResult;
import p.studio.vfs.VfsProjectContext; import p.studio.vfs.messages.VfsProjectContext;
import p.studio.vfs.VfsProjectSnapshot; import p.studio.vfs.messages.VfsProjectSnapshot;
import p.studio.vfs.VfsRefreshRequest; import p.studio.vfs.messages.VfsRefreshRequest;
import java.nio.file.Path; import java.nio.file.Path;
@ -50,31 +50,31 @@ final class StudioProjectSessionFactoryTest {
private static final class RecordingVfsFactory implements ProjectDocumentVfsFactory { private static final class RecordingVfsFactory implements ProjectDocumentVfsFactory {
private VfsProjectContext capturedContext; private VfsProjectContext capturedContext;
private final ProjectDocumentVfs vfs = new NoOpProjectDocumentVfs(); private final VfsProjectDocument vfs = new NoOpVfsProjectDocument();
@Override @Override
public ProjectDocumentVfs open(VfsProjectContext projectContext) { public VfsProjectDocument open(VfsProjectContext projectContext) {
this.capturedContext = projectContext; this.capturedContext = projectContext;
return vfs; return vfs;
} }
} }
private static final class RecordingLspFactory implements PrometeuLspServiceFactory { private static final class RecordingLspFactory implements LspServiceFactory {
private PrometeuLspProjectContext capturedContext; private LspProjectContext capturedContext;
private ProjectDocumentVfs capturedVfs; private VfsProjectDocument capturedVfs;
private final PrometeuLspService service = new NoOpPrometeuLspService(); private final LspService service = new NoOpPrometeuLspService();
@Override @Override
public PrometeuLspService open( public LspService open(
final PrometeuLspProjectContext projectContext, final LspProjectContext projectContext,
final ProjectDocumentVfs projectDocumentVfs) { final VfsProjectDocument vfsProjectDocument) {
this.capturedContext = projectContext; this.capturedContext = projectContext;
this.capturedVfs = projectDocumentVfs; this.capturedVfs = vfsProjectDocument;
return service; return service;
} }
} }
private static final class NoOpProjectDocumentVfs implements ProjectDocumentVfs { private static final class NoOpVfsProjectDocument implements VfsProjectDocument {
@Override @Override
public VfsProjectContext projectContext() { public VfsProjectContext projectContext() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
@ -101,29 +101,29 @@ final class StudioProjectSessionFactoryTest {
} }
} }
private static final class NoOpPrometeuLspService implements PrometeuLspService { private static final class NoOpPrometeuLspService implements LspService {
@Override @Override
public PrometeuLspProjectContext projectContext() { public LspProjectContext projectContext() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public ProjectDocumentVfs projectDocumentVfs() { public VfsProjectDocument projectDocumentVfs() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public PrometeuLspSessionStateDTO snapshot() { public LspSessionStateDTO snapshot() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public PrometeuLspAnalyzeDocumentResult analyzeDocument(final PrometeuLspAnalyzeDocumentRequest request) { public LspAnalyzeDocumentResult analyzeDocument(final LspAnalyzeDocumentRequest request) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public PrometeuLspDefinitionResult definition(final PrometeuLspDefinitionRequest request) { public LspDefinitionResult definition(final LspDefinitionRequest request) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
} }

View File

@ -1,19 +1,19 @@
package p.studio.projectsessions; package p.studio.projectsessions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import p.lsp.PrometeuLspProjectContext; import p.studio.lsp.messages.LspProjectContext;
import p.lsp.PrometeuLspService; import p.studio.lsp.LspService;
import p.lsp.dtos.PrometeuLspSessionStateDTO; import p.studio.lsp.dtos.LspSessionStateDTO;
import p.lsp.messages.PrometeuLspAnalyzeDocumentRequest; import p.studio.lsp.messages.LspAnalyzeDocumentRequest;
import p.lsp.messages.PrometeuLspAnalyzeDocumentResult; import p.studio.lsp.messages.LspAnalyzeDocumentResult;
import p.lsp.messages.PrometeuLspDefinitionRequest; import p.studio.lsp.messages.LspDefinitionRequest;
import p.lsp.messages.PrometeuLspDefinitionResult; import p.studio.lsp.messages.LspDefinitionResult;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.vfs.ProjectDocumentVfs; import p.studio.vfs.VfsProjectDocument;
import p.studio.vfs.VfsDocumentOpenResult; import p.studio.vfs.VfsDocumentOpenResult;
import p.studio.vfs.VfsProjectContext; import p.studio.vfs.messages.VfsProjectContext;
import p.studio.vfs.VfsProjectSnapshot; import p.studio.vfs.messages.VfsProjectSnapshot;
import p.studio.vfs.VfsRefreshRequest; import p.studio.vfs.messages.VfsRefreshRequest;
import java.nio.file.Path; import java.nio.file.Path;
@ -22,7 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
final class StudioProjectSessionTest { final class StudioProjectSessionTest {
@Test @Test
void closeDelegatesToUnderlyingServicesOnlyOnce() { void closeDelegatesToUnderlyingServicesOnlyOnce() {
final CountingProjectDocumentVfs vfs = new CountingProjectDocumentVfs(); final CountingVfsProjectDocument vfs = new CountingVfsProjectDocument();
final CountingPrometeuLspService lsp = new CountingPrometeuLspService(vfs); final CountingPrometeuLspService lsp = new CountingPrometeuLspService(vfs);
final StudioProjectSession session = new StudioProjectSession(projectReference(), lsp, vfs); final StudioProjectSession session = new StudioProjectSession(projectReference(), lsp, vfs);
@ -37,7 +37,7 @@ final class StudioProjectSessionTest {
return new ProjectReference("Example", "1.0.0", "pbs", 1, Path.of("/tmp/example")); return new ProjectReference("Example", "1.0.0", "pbs", 1, Path.of("/tmp/example"));
} }
private static final class CountingProjectDocumentVfs implements ProjectDocumentVfs { private static final class CountingVfsProjectDocument implements VfsProjectDocument {
private int closeCalls; private int closeCalls;
@Override @Override
@ -71,36 +71,36 @@ final class StudioProjectSessionTest {
} }
} }
private static final class CountingPrometeuLspService implements PrometeuLspService { private static final class CountingPrometeuLspService implements LspService {
private final ProjectDocumentVfs projectDocumentVfs; private final VfsProjectDocument vfsProjectDocument;
private int closeCalls; private int closeCalls;
private CountingPrometeuLspService(final ProjectDocumentVfs projectDocumentVfs) { private CountingPrometeuLspService(final VfsProjectDocument vfsProjectDocument) {
this.projectDocumentVfs = projectDocumentVfs; this.vfsProjectDocument = vfsProjectDocument;
} }
@Override @Override
public PrometeuLspProjectContext projectContext() { public LspProjectContext projectContext() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public ProjectDocumentVfs projectDocumentVfs() { public VfsProjectDocument projectDocumentVfs() {
return projectDocumentVfs; return vfsProjectDocument;
} }
@Override @Override
public PrometeuLspSessionStateDTO snapshot() { public LspSessionStateDTO snapshot() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public PrometeuLspAnalyzeDocumentResult analyzeDocument(final PrometeuLspAnalyzeDocumentRequest request) { public LspAnalyzeDocumentResult analyzeDocument(final LspAnalyzeDocumentRequest request) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public PrometeuLspDefinitionResult definition(final PrometeuLspDefinitionRequest request) { public LspDefinitionResult definition(final LspDefinitionRequest request) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

Some files were not shown because too many files have changed in this diff Show More