Skip to content

Commit d239369

Browse files
authored
Merge pull request #704 from usethesource/feature/rename-refactoring/parametric
Feature: rename refactoring/parametric
2 parents 9519d57 + f3c6b3c commit d239369

16 files changed

Lines changed: 540 additions & 122 deletions

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

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,35 @@
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;
3842
import org.eclipse.lsp4j.DidChangeConfigurationParams;
3943
import org.eclipse.lsp4j.DidChangeWatchedFilesParams;
4044
import org.eclipse.lsp4j.DidChangeWorkspaceFoldersParams;
4145
import org.eclipse.lsp4j.ExecuteCommandParams;
46+
import org.eclipse.lsp4j.FileOperationFilter;
47+
import org.eclipse.lsp4j.FileOperationOptions;
48+
import org.eclipse.lsp4j.FileOperationPattern;
49+
import org.eclipse.lsp4j.FileOperationsServerCapabilities;
50+
import org.eclipse.lsp4j.RenameFilesParams;
4251
import org.eclipse.lsp4j.ServerCapabilities;
4352
import org.eclipse.lsp4j.WorkspaceFolder;
4453
import org.eclipse.lsp4j.WorkspaceFoldersOptions;
4554
import org.eclipse.lsp4j.WorkspaceServerCapabilities;
4655
import org.eclipse.lsp4j.services.LanguageClient;
4756
import org.eclipse.lsp4j.services.LanguageClientAware;
4857
import org.eclipse.lsp4j.services.WorkspaceService;
58+
import org.rascalmpl.vscode.lsp.util.locations.Locations;
4959

5060
public class BaseWorkspaceService implements WorkspaceService, LanguageClientAware {
61+
private static final Logger logger = LogManager.getLogger(BaseWorkspaceService.class);
62+
5163
public static final String RASCAL_LANGUAGE = "Rascal";
5264
public static final String RASCAL_META_COMMAND = "rascal-meta-command";
5365
public static final String RASCAL_COMMAND = "rascal-command";
@@ -72,13 +84,24 @@ public void initialize(ClientCapabilities clientCap, @Nullable List<WorkspaceFol
7284

7385
var clientWorkspaceCap = clientCap.getWorkspace();
7486

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));
87+
WorkspaceServerCapabilities workspaceCapabilities = new WorkspaceServerCapabilities();
88+
if (clientWorkspaceCap != null) {
89+
if (clientWorkspaceCap.getWorkspaceFolders()) {
90+
var folderOptions = new WorkspaceFoldersOptions();
91+
folderOptions.setSupported(true);
92+
folderOptions.setChangeNotifications(true);
93+
workspaceCapabilities.setWorkspaceFolders(folderOptions);
94+
}
95+
96+
if (clientWorkspaceCap.getFileOperations().getDidRename()) {
97+
var fileOperationCapabilities = new FileOperationsServerCapabilities();
98+
fileOperationCapabilities.setDidRename(new FileOperationOptions(
99+
List.of(new FileOperationFilter(new FileOperationPattern("**")))));
100+
workspaceCapabilities.setFileOperations(fileOperationCapabilities);
101+
}
80102
}
81103

104+
capabilities.setWorkspace(workspaceCapabilities);
82105
}
83106

84107
public List<WorkspaceFolder> workspaceFolders() {
@@ -112,6 +135,16 @@ public void didChangeWorkspaceFolders(DidChangeWorkspaceFoldersParams params) {
112135
}
113136
}
114137

138+
@Override
139+
public void didRenameFiles(RenameFilesParams params) {
140+
logger.debug("workspace/didRenameFiles: {}", params.getFiles());
141+
142+
CompletableFuture.supplyAsync(() -> {
143+
documentService.didRenameFiles(params, workspaceFolders());
144+
return null; // Void return type requires a return.
145+
});
146+
}
147+
115148
@Override
116149
public CompletableFuture<Object> executeCommand(ExecuteCommandParams params) {
117150
if (params.getCommand().startsWith(RASCAL_META_COMMAND) || params.getCommand().startsWith(RASCAL_COMMAND)) {

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@
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

3333
import org.eclipse.lsp4j.RenameFilesParams;
3434
import org.eclipse.lsp4j.ServerCapabilities;
35+
import org.eclipse.lsp4j.WorkspaceFolder;
3536
import org.eclipse.lsp4j.services.LanguageClient;
3637
import org.eclipse.lsp4j.services.TextDocumentService;
3738
import org.rascalmpl.vscode.lsp.terminal.ITerminalIDEServer.LanguageParameter;
@@ -56,6 +57,6 @@ public interface IBaseTextDocumentService extends TextDocumentService {
5657

5758
boolean isManagingFile(ISourceLocation file);
5859

59-
default void didRenameFiles(RenameFilesParams params, Set<ISourceLocation> workspaceFolders) {}
60+
default void didRenameFiles(RenameFilesParams params, List<WorkspaceFolder> workspaceFolders) {}
6061
void cancelProgress(String progressId);
6162
}

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;

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.util.concurrent.ExecutorService;
3232
import java.util.function.BinaryOperator;
3333
import java.util.function.Function;
34+
3435
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
3536
import org.checkerframework.checker.nullness.qual.Nullable;
3637
import org.rascalmpl.values.parsetrees.ITree;
@@ -39,6 +40,7 @@
3940
import io.usethesource.vallang.IList;
4041
import io.usethesource.vallang.ISet;
4142
import io.usethesource.vallang.ISourceLocation;
43+
import io.usethesource.vallang.ITuple;
4244
import io.usethesource.vallang.IValue;
4345

4446
@SuppressWarnings("java:S3077") // Fields in this class are read/written sequentially
@@ -64,6 +66,9 @@ private static final <T> CompletableFuture<T> failedInitialization() {
6466
private volatile CompletableFuture<ILanguageContributions> references = failedInitialization();
6567
private volatile CompletableFuture<ILanguageContributions> implementation = failedInitialization();
6668
private volatile CompletableFuture<ILanguageContributions> codeAction = failedInitialization();
69+
private volatile CompletableFuture<ILanguageContributions> prepareRename = failedInitialization();
70+
private volatile CompletableFuture<ILanguageContributions> rename = failedInitialization();
71+
private volatile CompletableFuture<ILanguageContributions> didRenameFiles = failedInitialization();
6772
private volatile CompletableFuture<ILanguageContributions> selectionRange = failedInitialization();
6873

6974
private volatile CompletableFuture<Boolean> hasAnalysis = failedInitialization();
@@ -77,6 +82,8 @@ private static final <T> CompletableFuture<T> failedInitialization() {
7782
private volatile CompletableFuture<Boolean> hasReferences = failedInitialization();
7883
private volatile CompletableFuture<Boolean> hasImplementation = failedInitialization();
7984
private volatile CompletableFuture<Boolean> hasCodeAction = failedInitialization();
85+
private volatile CompletableFuture<Boolean> hasRename = failedInitialization();
86+
private volatile CompletableFuture<Boolean> hasDidRenameFiles = failedInitialization();
8087
private volatile CompletableFuture<Boolean> hasSelectionRange = failedInitialization();
8188

8289
private volatile CompletableFuture<Boolean> specialCaseHighlighting = failedInitialization();
@@ -151,6 +158,9 @@ private synchronized void calculateRouting() {
151158
references = findFirstOrDefault(ILanguageContributions::hasReferences);
152159
implementation = findFirstOrDefault(ILanguageContributions::hasImplementation);
153160
codeAction = findFirstOrDefault(ILanguageContributions::hasCodeAction);
161+
rename = findFirstOrDefault(ILanguageContributions::hasRename);
162+
prepareRename = findFirstOrDefault(ILanguageContributions::hasRename);
163+
didRenameFiles = findFirstOrDefault(ILanguageContributions::hasDidRenameFiles);
154164
selectionRange = findFirstOrDefault(ILanguageContributions::hasSelectionRange);
155165

156166
hasAnalysis = anyTrue(ILanguageContributions::hasAnalysis);
@@ -163,6 +173,8 @@ private synchronized void calculateRouting() {
163173
hasDefinition = anyTrue(ILanguageContributions::hasDefinition);
164174
hasReferences = anyTrue(ILanguageContributions::hasReferences);
165175
hasImplementation = anyTrue(ILanguageContributions::hasImplementation);
176+
hasRename = anyTrue(ILanguageContributions::hasRename);
177+
hasDidRenameFiles = anyTrue(ILanguageContributions::hasDidRenameFiles);
166178
hasCodeAction = anyTrue(ILanguageContributions::hasCodeAction);
167179
hasSelectionRange = anyTrue(ILanguageContributions::hasSelectionRange);
168180

@@ -275,6 +287,21 @@ public InterruptibleFuture<IList> inlayHint(@Nullable ITree input) {
275287
return flatten(inlayHint, c -> c.inlayHint(input));
276288
}
277289

290+
@Override
291+
public InterruptibleFuture<ISourceLocation> prepareRename(IList focus) {
292+
return flatten(prepareRename, c -> c.prepareRename(focus));
293+
}
294+
295+
@Override
296+
public InterruptibleFuture<ITuple> rename(IList focus, String name) {
297+
return flatten(rename, c -> c.rename(focus, name));
298+
}
299+
300+
@Override
301+
public InterruptibleFuture<ITuple> didRenameFiles(IList oldToNew) {
302+
return flatten(didRenameFiles, c -> c.didRenameFiles(oldToNew));
303+
}
304+
278305
@Override
279306
public InterruptibleFuture<ISet> hover(IList focus) {
280307
return flatten(hover, c -> c.hover(focus));
@@ -365,6 +392,16 @@ public CompletableFuture<Boolean> hasInlayHint() {
365392
return hasInlayHint;
366393
}
367394

395+
@Override
396+
public CompletableFuture<Boolean> hasRename() {
397+
return hasRename;
398+
}
399+
400+
@Override
401+
public CompletableFuture<Boolean> hasDidRenameFiles() {
402+
return hasDidRenameFiles;
403+
}
404+
368405
@Override
369406
public CompletableFuture<Boolean> specialCaseHighlighting() {
370407
return specialCaseHighlighting;

0 commit comments

Comments
 (0)