-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathLJDiagnosticsService.java
More file actions
157 lines (139 loc) · 5.55 KB
/
LJDiagnosticsService.java
File metadata and controls
157 lines (139 loc) · 5.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import java.io.File;
import java.net.URI;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.lsp4j.DidChangeConfigurationParams;
import org.eclipse.lsp4j.DidChangeTextDocumentParams;
import org.eclipse.lsp4j.DidChangeWatchedFilesParams;
import org.eclipse.lsp4j.DidCloseTextDocumentParams;
import org.eclipse.lsp4j.DidOpenTextDocumentParams;
import org.eclipse.lsp4j.DidSaveTextDocumentParams;
import org.eclipse.lsp4j.PublishDiagnosticsParams;
import org.eclipse.lsp4j.services.TextDocumentService;
import org.eclipse.lsp4j.services.WorkspaceService;
import liquidjava.diagnostics.LJDiagnostic;
import liquidjava.processor.context.ContextHistory;
import utils.ContextHistoryConverter;
import utils.DiagnosticConverter;
import utils.PathUtils;
public class LJDiagnosticsService implements TextDocumentService, WorkspaceService {
private LJLanguageClient client;
private String workspaceRoot;
private final ExecutorService diagnosticsExecutor = Executors.newSingleThreadExecutor(r -> {
Thread thread = new Thread(r, "liquidjava-diagnostics");
thread.setDaemon(true);
return thread;
});
public void setClient(LJLanguageClient client) {
this.client = client;
}
public void setWorkspaceRoot(String workspaceRoot) {
this.workspaceRoot = workspaceRoot;
}
/**
* Sends diagnostics notification to the client
* @param diagnostics the diagnostics to send
*/
public void sendDiagnosticsNotification(List<LJDiagnostic> diagnostics) {
if (this.client == null) return;
System.out.println("Sending diagnostics notification with " + diagnostics.size() + " diagnostics");
List<Object> dtos = diagnostics.stream()
.map(DiagnosticConverter::convertToDTO)
.collect(Collectors.toList());
this.client.sendDiagnostics(dtos);
}
/**
* Generates diagnostics for the given URI and publishes them to the client
* @param uri the URI of the document
*/
public void generateDiagnostics(String uri) {
String path = PathUtils.extractBasePath(uri);
LJDiagnostics ljDiagnostics = LJDiagnosticsHandler.getLJDiagnostics(path);
List<PublishDiagnosticsParams> nativeDiagnostics = LJDiagnosticsHandler.getNativeDiagnostics(ljDiagnostics, uri);
nativeDiagnostics.forEach(params -> {
this.client.publishDiagnostics(params);
});
List<LJDiagnostic> diagnostics = Stream.concat(ljDiagnostics.errors().stream(), ljDiagnostics.warnings().stream()).collect(Collectors.toList());
sendDiagnosticsNotification(diagnostics);
this.client.sendContext(ContextHistoryConverter.convertToDTO(ContextHistory.getInstance()));
}
/**
* Schedules diagnostics generation without blocking the LSP thread
* @param uri the URI of the document
* @return a future that completes when diagnostics are published
*/
public CompletableFuture<Void> generateDiagnosticsAsync(String uri) {
return CompletableFuture.runAsync(() -> generateDiagnostics(uri), diagnosticsExecutor);
}
/**
* Stops background diagnostics work
*/
public void shutdown() {
diagnosticsExecutor.shutdownNow();
}
/**
* Clear a diagnostic for a specific URI
* @param uri the URI of the document
*/
public void clearDiagnostic(String uri) {
this.client.publishDiagnostics(LJDiagnosticsHandler.getEmptyDiagnostics(uri));
// TODO: fix consistency between native and custom diagnostics
// sendDiagnosticsNotification(List.of());
}
/**
* Checks diagnostics when a document is opened
* @param params
*/
@Override
public void didOpen(DidOpenTextDocumentParams params) {
String uri = params.getTextDocument().getUri();
if (!PathUtils.isFileInDirectory(uri, workspaceRoot)) return;
System.out.println("Document opened — checking diagnostics");
generateDiagnosticsAsync(uri);
}
/**
* Checks diagnostics when a document is saved
* @param params
*/
@Override
public void didSave(DidSaveTextDocumentParams params) {
String uri = params.getTextDocument().getUri();
if (!PathUtils.isFileInDirectory(uri, workspaceRoot)) return;
System.out.println("Document saved — checking diagnostics");
clearDiagnostic(uri);
generateDiagnosticsAsync(uri);
}
/**
* Clears diagnostics for a deleted document
* @param params
*/
@Override
public void didClose(DidCloseTextDocumentParams params) {
String uri = params.getTextDocument().getUri();
if (!PathUtils.isFileInDirectory(uri, workspaceRoot)) return;
try {
// check if the file still exists on disk
File file = new File(new URI(uri));
if (!file.exists()) {
System.out.println("File deleted — clearing diagnostic");
clearDiagnostic(uri);
}
} catch (Exception e) {}
}
@Override
public void didChange(DidChangeTextDocumentParams params) {
// do nothing, diagnostics are checked on save to avoid excessive checks
}
@Override
public void didChangeConfiguration(DidChangeConfigurationParams params) {
// do nothing, ignore
}
@Override
public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) {
// do nothing, ignore
}
}