Skip to content

Commit 16a7eb3

Browse files
committed
Merge branch 'main' into migrate-dap
2 parents 5c03b61 + 0b0186f commit 16a7eb3

17 files changed

Lines changed: 608 additions & 124 deletions

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/BaseWorkspaceService.java

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,37 @@
3131
import java.util.concurrent.CompletableFuture;
3232
import java.util.concurrent.CopyOnWriteArrayList;
3333
import java.util.concurrent.ExecutorService;
34+
import java.util.stream.Collectors;
3435

3536
import com.google.gson.JsonPrimitive;
37+
38+
import org.apache.logging.log4j.LogManager;
39+
import org.apache.logging.log4j.Logger;
3640
import org.checkerframework.checker.nullness.qual.Nullable;
3741
import org.eclipse.lsp4j.ClientCapabilities;
42+
import org.eclipse.lsp4j.DeleteFilesParams;
3843
import org.eclipse.lsp4j.DidChangeConfigurationParams;
3944
import org.eclipse.lsp4j.DidChangeWatchedFilesParams;
4045
import org.eclipse.lsp4j.DidChangeWorkspaceFoldersParams;
4146
import org.eclipse.lsp4j.ExecuteCommandParams;
47+
import org.eclipse.lsp4j.FileDelete;
48+
import org.eclipse.lsp4j.FileOperationFilter;
49+
import org.eclipse.lsp4j.FileOperationOptions;
50+
import org.eclipse.lsp4j.FileOperationPattern;
51+
import org.eclipse.lsp4j.FileOperationsServerCapabilities;
52+
import org.eclipse.lsp4j.RenameFilesParams;
4253
import org.eclipse.lsp4j.ServerCapabilities;
4354
import org.eclipse.lsp4j.WorkspaceFolder;
4455
import org.eclipse.lsp4j.WorkspaceFoldersOptions;
4556
import org.eclipse.lsp4j.WorkspaceServerCapabilities;
4657
import org.eclipse.lsp4j.services.LanguageClient;
4758
import org.eclipse.lsp4j.services.LanguageClientAware;
4859
import org.eclipse.lsp4j.services.WorkspaceService;
60+
import org.rascalmpl.vscode.lsp.util.locations.Locations;
4961

5062
public class BaseWorkspaceService implements WorkspaceService, LanguageClientAware {
63+
private static final Logger logger = LogManager.getLogger(BaseWorkspaceService.class);
64+
5165
public static final String RASCAL_LANGUAGE = "Rascal";
5266
public static final String RASCAL_META_COMMAND = "rascal-meta-command";
5367
public static final String RASCAL_COMMAND = "rascal-command";
@@ -57,10 +71,13 @@ public class BaseWorkspaceService implements WorkspaceService, LanguageClientAwa
5771
private final IBaseTextDocumentService documentService;
5872
private final CopyOnWriteArrayList<WorkspaceFolder> workspaceFolders = new CopyOnWriteArrayList<>();
5973

74+
private final List<FileOperationPattern> interestedInFiles;
75+
6076

61-
protected BaseWorkspaceService(ExecutorService exec, IBaseTextDocumentService documentService) {
77+
protected BaseWorkspaceService(ExecutorService exec, IBaseTextDocumentService documentService, List<FileOperationPattern> interestedInFiles) {
6278
this.documentService = documentService;
6379
this.ownExecuter = exec;
80+
this.interestedInFiles = interestedInFiles;
6481
}
6582

6683

@@ -72,13 +89,35 @@ public void initialize(ClientCapabilities clientCap, @Nullable List<WorkspaceFol
7289

7390
var clientWorkspaceCap = clientCap.getWorkspace();
7491

75-
if (clientWorkspaceCap != null && Boolean.TRUE.equals(clientWorkspaceCap.getWorkspaceFolders())) {
76-
var workspaceCap = new WorkspaceFoldersOptions();
77-
workspaceCap.setSupported(true);
78-
workspaceCap.setChangeNotifications(true);
79-
capabilities.setWorkspace(new WorkspaceServerCapabilities(workspaceCap));
92+
WorkspaceServerCapabilities workspaceCapabilities = new WorkspaceServerCapabilities();
93+
if (clientWorkspaceCap != null) {
94+
if (clientWorkspaceCap.getWorkspaceFolders()) {
95+
var folderOptions = new WorkspaceFoldersOptions();
96+
folderOptions.setSupported(true);
97+
folderOptions.setChangeNotifications(true);
98+
workspaceCapabilities.setWorkspaceFolders(folderOptions);
99+
}
100+
101+
var fileOperationCapabilities = new FileOperationsServerCapabilities();
102+
var whichFiles = new FileOperationOptions(interestedInFiles.stream()
103+
.map(FileOperationFilter::new)
104+
.collect(Collectors.toList())
105+
);
106+
boolean watchesSet = false;
107+
if (clientWorkspaceCap.getFileOperations().getDidRename()) {
108+
fileOperationCapabilities.setDidRename(whichFiles);
109+
watchesSet = true;
110+
}
111+
if (clientWorkspaceCap.getFileOperations().getDidDelete()) {
112+
fileOperationCapabilities.setDidDelete(whichFiles);
113+
watchesSet = true;
114+
}
115+
if (watchesSet) {
116+
workspaceCapabilities.setFileOperations(fileOperationCapabilities);
117+
}
80118
}
81119

120+
capabilities.setWorkspace(workspaceCapabilities);
82121
}
83122

84123
public List<WorkspaceFolder> workspaceFolders() {
@@ -112,6 +151,33 @@ public void didChangeWorkspaceFolders(DidChangeWorkspaceFoldersParams params) {
112151
}
113152
}
114153

154+
@Override
155+
public void didRenameFiles(RenameFilesParams params) {
156+
logger.debug("workspace/didRenameFiles: {}", params.getFiles());
157+
158+
ownExecuter.submit(() -> {
159+
documentService.didRenameFiles(params, workspaceFolders());
160+
});
161+
162+
ownExecuter.submit(() -> {
163+
// cleanup the old files (we do not get a `didDelete` event)
164+
var oldFiles = params.getFiles().stream()
165+
.map(f -> f.getOldUri())
166+
.map(FileDelete::new)
167+
.collect(Collectors.toList());
168+
documentService.didDeleteFiles(new DeleteFilesParams(oldFiles));
169+
});
170+
}
171+
172+
@Override
173+
public void didDeleteFiles(DeleteFilesParams params) {
174+
logger.debug("workspace/didDeleteFiles: {}", params.getFiles());
175+
176+
ownExecuter.submit(() -> {
177+
documentService.didDeleteFiles(params);
178+
});
179+
}
180+
115181
@Override
116182
public CompletableFuture<Object> executeCommand(ExecuteCommandParams params) {
117183
if (params.getCommand().startsWith(RASCAL_META_COMMAND) || params.getCommand().startsWith(RASCAL_COMMAND)) {
@@ -120,7 +186,7 @@ public CompletableFuture<Object> executeCommand(ExecuteCommandParams params) {
120186
return documentService.executeCommand(languageName, command).thenApply(v -> v);
121187
}
122188

123-
return CompletableFuture.supplyAsync(() -> params.getCommand() + " was ignored.");
189+
return CompletableFuture.supplyAsync(() -> params.getCommand() + " was ignored.", ownExecuter);
124190
}
125191

126192

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/IBaseTextDocumentService.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@
2727
package org.rascalmpl.vscode.lsp;
2828

2929
import java.time.Duration;
30-
import java.util.Set;
30+
import java.util.List;
3131
import java.util.concurrent.CompletableFuture;
3232

33+
import org.eclipse.lsp4j.DeleteFilesParams;
3334
import org.eclipse.lsp4j.RenameFilesParams;
3435
import org.eclipse.lsp4j.ServerCapabilities;
36+
import org.eclipse.lsp4j.WorkspaceFolder;
3537
import org.eclipse.lsp4j.services.LanguageClient;
3638
import org.eclipse.lsp4j.services.TextDocumentService;
3739
import org.rascalmpl.vscode.lsp.terminal.ITerminalIDEServer.LanguageParameter;
@@ -56,6 +58,7 @@ public interface IBaseTextDocumentService extends TextDocumentService {
5658

5759
boolean isManagingFile(ISourceLocation file);
5860

59-
default void didRenameFiles(RenameFilesParams params, Set<ISourceLocation> workspaceFolders) {}
61+
void didRenameFiles(RenameFilesParams params, List<WorkspaceFolder> workspaceFolders);
62+
void didDeleteFiles(DeleteFilesParams params);
6063
void cancelProgress(String progressId);
6164
}

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ILanguageContributions.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import io.usethesource.vallang.IList;
3939
import io.usethesource.vallang.ISet;
4040
import io.usethesource.vallang.ISourceLocation;
41+
import io.usethesource.vallang.ITuple;
4142
import io.usethesource.vallang.IValue;
4243
import io.usethesource.vallang.type.Type;
4344
import io.usethesource.vallang.type.TypeFactory;
@@ -60,19 +61,25 @@ public interface ILanguageContributions {
6061
public InterruptibleFuture<IList> codeAction(IList focus);
6162
public InterruptibleFuture<IList> selectionRange(IList focus);
6263

64+
public InterruptibleFuture<ISourceLocation> prepareRename(IList focus);
65+
public InterruptibleFuture<ITuple> rename(IList focus, String name);
66+
public InterruptibleFuture<ITuple> didRenameFiles(IList fileRenames);
67+
6368
public CompletableFuture<IList> parseCodeActions(String command);
6469

6570
public CompletableFuture<Boolean> hasAnalysis();
6671
public CompletableFuture<Boolean> hasBuild();
6772
public CompletableFuture<Boolean> hasDocumentSymbol();
6873
public CompletableFuture<Boolean> hasCodeLens();
6974
public CompletableFuture<Boolean> hasInlayHint();
75+
public CompletableFuture<Boolean> hasRename();
7076
public CompletableFuture<Boolean> hasExecution();
7177
public CompletableFuture<Boolean> hasHover();
7278
public CompletableFuture<Boolean> hasDefinition();
7379
public CompletableFuture<Boolean> hasReferences();
7480
public CompletableFuture<Boolean> hasImplementation();
7581
public CompletableFuture<Boolean> hasCodeAction();
82+
public CompletableFuture<Boolean> hasDidRenameFiles();
7683
public CompletableFuture<Boolean> hasSelectionRange();
7784

7885
public CompletableFuture<Boolean> specialCaseHighlighting();

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/InterpretedLanguageContributions.java

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import io.usethesource.vallang.IList;
5858
import io.usethesource.vallang.ISet;
5959
import io.usethesource.vallang.ISourceLocation;
60+
import io.usethesource.vallang.ITuple;
6061
import io.usethesource.vallang.IValue;
6162
import io.usethesource.vallang.IValueFactory;
6263
import io.usethesource.vallang.exceptions.FactTypeUseException;
@@ -88,6 +89,9 @@ public class InterpretedLanguageContributions implements ILanguageContributions
8889
private final CompletableFuture<@Nullable IFunction> references;
8990
private final CompletableFuture<@Nullable IFunction> implementation;
9091
private final CompletableFuture<@Nullable IFunction> codeAction;
92+
private final CompletableFuture<@Nullable IFunction> prepareRename;
93+
private final CompletableFuture<@Nullable IFunction> rename;
94+
private final CompletableFuture<@Nullable IFunction> didRenameFiles;
9195
private final CompletableFuture<@Nullable IFunction> selectionRange;
9296

9397
private final CompletableFuture<Boolean> hasAnalysis;
@@ -101,6 +105,8 @@ public class InterpretedLanguageContributions implements ILanguageContributions
101105
private final CompletableFuture<Boolean> hasReferences;
102106
private final CompletableFuture<Boolean> hasImplementation;
103107
private final CompletableFuture<Boolean> hasCodeAction;
108+
private final CompletableFuture<Boolean> hasRename;
109+
private final CompletableFuture<Boolean> hasDidRenameFiles;
104110
private final CompletableFuture<Boolean> hasSelectionRange;
105111

106112
private final CompletableFuture<Boolean> specialCaseHighlighting;
@@ -144,6 +150,9 @@ public InterpretedLanguageContributions(LanguageParameter lang, IBaseTextDocumen
144150
this.references = getFunctionFor(contributions, LanguageContributions.REFERENCES);
145151
this.implementation = getFunctionFor(contributions, LanguageContributions.IMPLEMENTATION);
146152
this.codeAction = getFunctionFor(contributions, LanguageContributions.CODE_ACTION);
153+
this.prepareRename = getKeywordParamFunctionFor(contributions, LanguageContributions.RENAME, LanguageContributions.PREPARE_RENAME_SERVICE);
154+
this.rename = getFunctionFor(contributions, LanguageContributions.RENAME);
155+
this.didRenameFiles = getFunctionFor(contributions, LanguageContributions.DID_RENAME_FILES);
147156
this.selectionRange = getFunctionFor(contributions, LanguageContributions.SELECTION_RANGE);
148157

149158
// assign boolean properties once instead of wasting futures all the time
@@ -158,6 +167,8 @@ public InterpretedLanguageContributions(LanguageParameter lang, IBaseTextDocumen
158167
this.hasReferences = nonNull(this.references);
159168
this.hasImplementation = nonNull(this.implementation);
160169
this.hasCodeAction = nonNull(this.codeAction);
170+
this.hasRename = nonNull(this.rename);
171+
this.hasDidRenameFiles = nonNull(this.didRenameFiles);
161172
this.hasSelectionRange = nonNull(this.selectionRange);
162173

163174
this.specialCaseHighlighting = getContributionParameter(contributions,
@@ -260,19 +271,29 @@ private CompletableFuture<IConstructor> parseCommand(String command) {
260271
});
261272
}
262273

263-
private static CompletableFuture<@Nullable IFunction> getFunctionFor(CompletableFuture<ISet> contributions, String cons) {
274+
private static CompletableFuture<@Nullable IConstructor> getContribution(CompletableFuture<ISet> contributions, String cons) {
264275
return contributions.thenApply(conts -> {
265276
for (IValue elem : conts) {
266277
IConstructor contrib = (IConstructor) elem;
267278
if (cons.equals(contrib.getConstructorType().getName())) {
268-
return (IFunction) contrib.get(0);
279+
return contrib;
269280
}
270281
}
271282
logger.debug("No {} defined", cons);
272283
return null;
273284
});
274285
}
275286

287+
private static CompletableFuture<@Nullable IFunction> getFunctionFor(CompletableFuture<ISet> contributions, String cons) {
288+
return getContribution(contributions, cons).thenApply(contribution -> (IFunction) contribution.get(0));
289+
}
290+
291+
private static CompletableFuture<@Nullable IFunction> getKeywordParamFunctionFor(CompletableFuture<ISet> contributions, String cons, String kwParam) {
292+
return getContribution(contributions, cons).thenApply(contribution ->
293+
(IFunction) contribution.asWithKeywordParameters().getParameter(kwParam)
294+
);
295+
}
296+
276297
@Override
277298
public String getName() {
278299
return name;
@@ -314,6 +335,24 @@ public InterruptibleFuture<IList> inlayHint(@Nullable ITree input) {
314335
return execFunction(LanguageContributions.INLAY_HINT, inlayHint, VF.list(), input);
315336
}
316337

338+
@Override
339+
public InterruptibleFuture<ISourceLocation> prepareRename(IList focus) {
340+
debug(LanguageContributions.PREPARE_RENAME_SERVICE, focus.isEmpty() ? "" : focus.get(0));
341+
return execFunction(LanguageContributions.PREPARE_RENAME_SERVICE, prepareRename, URIUtil.unknownLocation(), focus);
342+
}
343+
344+
@Override
345+
public InterruptibleFuture<ITuple> rename(IList focus, String newName) {
346+
debug(LanguageContributions.RENAME_SERVICE, newName, focus.isEmpty() ? "" : focus.get(0));
347+
return execFunction(LanguageContributions.RENAME_SERVICE, rename, VF.tuple(VF.list(), VF.list()), focus, VF.string(newName));
348+
}
349+
350+
@Override
351+
public InterruptibleFuture<ITuple> didRenameFiles(IList fileRenames) {
352+
debug(LanguageContributions.DID_RENAME_FILES, fileRenames);
353+
return execFunction(LanguageContributions.DID_RENAME_FILES, didRenameFiles, VF.tuple(VF.list(), VF.list()), fileRenames);
354+
}
355+
317356
@Override
318357
public InterruptibleFuture<ISet> hover(IList focus) {
319358
debug(LanguageContributions.HOVER, focus.length());
@@ -388,6 +427,16 @@ public CompletableFuture<Boolean> hasInlayHint() {
388427
return hasInlayHint;
389428
}
390429

430+
@Override
431+
public CompletableFuture<Boolean> hasRename() {
432+
return hasRename;
433+
}
434+
435+
@Override
436+
public CompletableFuture<Boolean> hasDidRenameFiles() {
437+
return hasDidRenameFiles;
438+
}
439+
391440
@Override
392441
public CompletableFuture<Boolean> hasCodeLens() {
393442
return hasCodeLens;

0 commit comments

Comments
 (0)