From 026331cc1bae8094c3a3a457fc7241ae8c39f766 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Tue, 15 Oct 2024 15:25:13 +0200 Subject: [PATCH 01/16] Add annotated changes to rename framework. --- .../lsp/rascal/RascalTextDocumentService.java | 12 +++++-- .../vscode/lsp/util/DocumentChanges.java | 23 ++++++++++++- .../lang/rascal/lsp/refactor/Rename.rsc | 26 +++++++++++--- .../lang/rascal/lsp/refactor/TextEdits.rsc | 16 +++++++++ .../lang/rascal/tests/rename/TestUtils.rsc | 34 +++++++++---------- .../lang/rascal/tests/rename/ValidNames.rsc | 2 +- 6 files changed, 87 insertions(+), 26 deletions(-) create mode 100644 rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/TextEdits.rsc diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java index 6de9d8b44..6eb067746 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java @@ -105,7 +105,10 @@ import org.rascalmpl.vscode.lsp.util.locations.LineColumnOffsetMap; import org.rascalmpl.vscode.lsp.util.locations.Locations; +import io.usethesource.vallang.IList; +import io.usethesource.vallang.IMap; import io.usethesource.vallang.ISourceLocation; +import io.usethesource.vallang.ITuple; import io.usethesource.vallang.IValue; public class RascalTextDocumentService implements IBaseTextDocumentService, LanguageClientAware { @@ -287,8 +290,13 @@ public CompletableFuture rename(RenameParams params) { .thenApply(Versioned::get) .handle((t, r) -> (t == null ? (file.getMostRecentTree().get()) : t)) .thenCompose(tr -> rascalServices.getRename(tr, params.getPosition(), workspaceFolders, facts::getPathConfig, params.getNewName(), columns).get()) - .thenApply(c -> new WorkspaceEdit(DocumentChanges.translateDocumentChanges(this, c))) - ; + .thenApply(c -> { + ITuple t = (ITuple) c; + WorkspaceEdit wsEdit = new WorkspaceEdit(); + wsEdit.setDocumentChanges(DocumentChanges.translateDocumentChanges(this, (IList) t.get(0))); + wsEdit.setChangeAnnotations(DocumentChanges.translateChangeAnnotations((IMap) t.get(1))); + return wsEdit; + }); } @Override diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/DocumentChanges.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/DocumentChanges.java index d931eed21..515551f7b 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/DocumentChanges.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/util/DocumentChanges.java @@ -28,8 +28,11 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; +import org.eclipse.lsp4j.AnnotatedTextEdit; +import org.eclipse.lsp4j.ChangeAnnotation; import org.eclipse.lsp4j.CreateFile; import org.eclipse.lsp4j.DeleteFile; import org.eclipse.lsp4j.Range; @@ -43,8 +46,10 @@ import org.rascalmpl.vscode.lsp.util.locations.LineColumnOffsetMap; import org.rascalmpl.vscode.lsp.util.locations.Locations; +import io.usethesource.vallang.IBool; import io.usethesource.vallang.IConstructor; import io.usethesource.vallang.IList; +import io.usethesource.vallang.IMap; import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.IString; import io.usethesource.vallang.IValue; @@ -90,7 +95,9 @@ public static List> translateDocumen private static List translateTextEdits(final IBaseTextDocumentService docService, IList edits) { return edits.stream() .map(e -> (IConstructor) e) - .map(c -> new TextEdit(locationToRange(docService, (ISourceLocation) c.get("range")), ((IString) c.get("replacement")).getValue())) + .map(c -> (c.has("annotation") + ? new AnnotatedTextEdit(locationToRange(docService, (ISourceLocation) c.get("range")), ((IString) c.get("replacement")).getValue(), ((IString) c.get("annotation")).getValue()) + : new TextEdit(locationToRange(docService, (ISourceLocation) c.get("range")), ((IString) c.get("replacement")).getValue()))) .collect(Collectors.toList()); } @@ -102,4 +109,18 @@ private static Range locationToRange(final IBaseTextDocumentService docService, private static String getFileURI(IConstructor edit, String label) { return ((ISourceLocation) edit.get(label)).getURI().toString(); } + + public static Map translateChangeAnnotations(IMap annos) { + return annos.stream() + .map(id -> (IString) id) + .map(id -> { + IConstructor c = (IConstructor) annos.get(id); + ChangeAnnotation anno = new ChangeAnnotation(); + anno.setLabel(((IString) c.get("label")).getValue()); + anno.setDescription(((IString) c.get("description")).getValue()); + anno.setNeedsConfirmation(((IBool) c.get("needsConfirmation")).getValue()); + return Map.entry(id.getValue(), anno); + }) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } } diff --git a/rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/Rename.rsc b/rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/Rename.rsc index e50b9f164..76fb4d8ca 100644 --- a/rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/Rename.rsc +++ b/rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/Rename.rsc @@ -53,13 +53,15 @@ extend lang::rascal::lsp::refactor::Exception; import lang::rascal::lsp::refactor::Util; import lang::rascal::lsp::refactor::WorkspaceInfo; -import analysis::diff::edits::TextEdits; +import lang::rascal::lsp::refactor::TextEdits; import util::FileSystem; import util::Maybe; import util::Monitor; import util::Reflective; +alias Edits = tuple[list[DocumentEdit], map[ChangeAnnotationId, ChangeAnnotation]]; + // Rascal compiler-specific extension void throwAnyErrors(list[ModuleMessages] mmsgs) { for (mmsg <- mmsgs) { @@ -508,8 +510,8 @@ private bool rascalContainsName(loc l, str name) { 2. It does not change the semantics of the application. 3. It does not change definitions outside of the current workspace. } -list[DocumentEdit] rascalRenameSymbol(Tree cursorT, set[loc] workspaceFolders, str newName, PathConfig(loc) getPathConfig) - = job("renaming to ", list[DocumentEdit](void(str, int) step) { +Edits rascalRenameSymbol(Tree cursorT, set[loc] workspaceFolders, str newName, PathConfig(loc) getPathConfig) + = job("renaming to ", Edits(void(str, int) step) { loc cursorLoc = cursorT.src; str cursorName = ""; @@ -576,6 +578,22 @@ list[DocumentEdit] rascalRenameSymbol(Tree cursorT, set[loc] workspaceFolders, s set[loc] \files = defsPerFile.file + usesPerFile.file; step("checking rename validity", 1); + + map[ChangeAnnotationId, ChangeAnnotation] changeAnnotations = (); + ChangeAnnotationId registerChangeAnnotation(str label, str description, bool needsConfirmation) { + ChangeAnnotationId makeKey(str label, int suffix) = "