refactor, rename and reducing complexity
This commit is contained in:
parent
b64be2a9a1
commit
ba55b8e65f
@ -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
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
package p.lsp;
|
|
||||||
|
|
||||||
import p.studio.vfs.ProjectDocumentVfs;
|
|
||||||
|
|
||||||
public interface PrometeuLspServiceFactory {
|
|
||||||
PrometeuLspService open(PrometeuLspProjectContext projectContext, ProjectDocumentVfs projectDocumentVfs);
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
package p.lsp.dtos;
|
|
||||||
|
|
||||||
public enum PrometeuLspDiagnosticSeverityDTO {
|
|
||||||
ERROR,
|
|
||||||
WARNING
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
package p.lsp.events;
|
|
||||||
|
|
||||||
public enum PrometeuLspEventKind {
|
|
||||||
SESSION_READY
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
package p.lsp.events;
|
|
||||||
|
|
||||||
public interface PrometeuLspEventSink {
|
|
||||||
void publish(PrometeuLspEvent event);
|
|
||||||
}
|
|
||||||
@ -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"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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);
|
||||||
|
}
|
||||||
@ -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");
|
||||||
@ -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");
|
||||||
@ -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");
|
||||||
}
|
}
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
@ -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"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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();
|
||||||
@ -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");
|
||||||
}
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package p.studio.lsp.events;
|
||||||
|
|
||||||
|
public enum LspEventKind {
|
||||||
|
SESSION_READY
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package p.studio.lsp.events;
|
||||||
|
|
||||||
|
public interface LspEventSink {
|
||||||
|
void publish(LspEvent event);
|
||||||
|
}
|
||||||
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
@ -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"));
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
package p.studio.lsp.messages;
|
||||||
|
|
||||||
|
public enum LspDiagnosticSeverity {
|
||||||
|
ERROR,
|
||||||
|
WARNING
|
||||||
|
}
|
||||||
@ -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();
|
||||||
@ -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,
|
||||||
@ -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"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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) {
|
||||||
|
}
|
||||||
@ -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) {
|
||||||
|
}
|
||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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",
|
||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
@ -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;
|
||||||
@ -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;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package p.studio.events;
|
package p.studio.lsp.events;
|
||||||
|
|
||||||
import p.packer.events.PackerEventKind;
|
import p.packer.events.PackerEventKind;
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package p.studio.events;
|
package p.studio.lsp.events;
|
||||||
|
|
||||||
public record StudioProjectCreatedEvent() implements StudioEvent {
|
public record StudioProjectCreatedEvent() implements StudioEvent {
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package p.studio.events;
|
package p.studio.lsp.events;
|
||||||
|
|
||||||
public record StudioProjectLoadingCompletedEvent() implements StudioEvent {
|
public record StudioProjectLoadingCompletedEvent() implements StudioEvent {
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package p.studio.events;
|
package p.studio.lsp.events;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package p.studio.events;
|
package p.studio.lsp.events;
|
||||||
|
|
||||||
public enum StudioProjectLoadingPhase {
|
public enum StudioProjectLoadingPhase {
|
||||||
RESOLVING_PROJECT,
|
RESOLVING_PROJECT,
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package p.studio.events;
|
package p.studio.lsp.events;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package p.studio.events;
|
package p.studio.lsp.events;
|
||||||
|
|
||||||
public record StudioProjectLoadingStartedEvent() implements StudioEvent {
|
public record StudioProjectLoadingStartedEvent() implements StudioEvent {
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package p.studio.events;
|
package p.studio.lsp.events;
|
||||||
|
|
||||||
public record StudioProjectOpenedEvent() implements StudioEvent {
|
public record StudioProjectOpenedEvent() implements StudioEvent {
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package p.studio.events;
|
package p.studio.lsp.events;
|
||||||
|
|
||||||
import p.studio.workspaces.WorkspaceId;
|
import p.studio.workspaces.WorkspaceId;
|
||||||
|
|
||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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());
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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 {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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()) {
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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(),
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
@ -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;
|
||||||
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
Loading…
x
Reference in New Issue
Block a user