From 899ed7faa8dc64980e29a92f865fc967c72d8ab9 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Mon, 16 Dec 2024 18:41:33 +0100 Subject: [PATCH] Determine cursor tree again for renaming. --- .../lsp/rascal/RascalLanguageServices.java | 9 +-- .../lsp/rascal/RascalTextDocumentService.java | 79 ++++++++++--------- 2 files changed, 43 insertions(+), 45 deletions(-) diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalLanguageServices.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalLanguageServices.java index 92528f4d..3e6c740f 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalLanguageServices.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalLanguageServices.java @@ -49,7 +49,6 @@ import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.Nullable; import org.eclipse.lsp4j.FileRename; -import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.jsonrpc.ResponseErrorException; import org.eclipse.lsp4j.jsonrpc.messages.ResponseError; import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode; @@ -69,8 +68,6 @@ import org.rascalmpl.vscode.lsp.util.EvaluatorUtil; import org.rascalmpl.vscode.lsp.util.RascalServices; import org.rascalmpl.vscode.lsp.util.concurrent.InterruptibleFuture; -import org.rascalmpl.vscode.lsp.util.locations.ColumnMaps; -import org.rascalmpl.vscode.lsp.util.locations.Locations; import io.usethesource.vallang.IConstructor; import io.usethesource.vallang.IList; @@ -210,11 +207,7 @@ public InterruptibleFuture getDocumentSymbols(IConstructor module) { } - public InterruptibleFuture getRename(ITree module, Position cursor, Set workspaceFolders, Function getPathConfig, String newName, ColumnMaps columns) { - var moduleLocation = TreeAdapter.getLocation(module); - Position pos = Locations.toRascalPosition(moduleLocation, cursor, columns); - var cursorTree = TreeAdapter.locateLexical(module, pos.getLine(), pos.getCharacter()); - + public InterruptibleFuture getRename(ITree cursorTree, Set workspaceFolders, Function getPathConfig, String newName) { return runEvaluator("Rascal rename", semanticEvaluator, eval -> { try { IFunction rascalGetPathConfig = eval.getFunctionValueFactory().function(getPathConfigType, (t, u) -> addResources(getPathConfig.apply((ISourceLocation) t[0]))); 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 c4436e5c..2ce9505d 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 @@ -296,6 +296,43 @@ public CompletableFuture, List sortNames = focusList.stream() + .map(tree -> ProductionAdapter.getSortName(TreeAdapter.getProduction((ITree) tree))) + .collect(Collectors.toList()); + + int qNameIdx = sortNames.indexOf("QualifiedName"); + if (qNameIdx != -1) { + // Cursor is at a qualified name + ITree qualifiedName = (ITree) focusList.get(qNameIdx); + + // If the qualified name is in a header, but not in module parameters or a syntax defintion, it is a full module path + if (sortNames.contains("Header") && !(sortNames.contains("ModuleParameters") || sortNames.contains("SyntaxDefinition"))) { + return qualifiedName; + } + + // Since the cursor is not in a header, the qualified name consists of a declaration name on the right, and an optional module path prefix. + IList names = TreeAdapter.getListASTArgs(TreeAdapter.getArg(qualifiedName, "names")); + + // Even if the cursor is on the module prefix, we steer towards renaming the declaration + return (ITree) names.get(names.size() - 1); + } + + switch (sortNames.get(0)) { + case "Name": // intentional fall-through + case "Nonterminal": // intentional fall-through + case "NonterminalLabel": { + // Return name location + return (ITree) focusList.get(0); + } + default: return null; + } + } + @Override public CompletableFuture> prepareRename(PrepareRenameParams params) { logger.debug("textDocument/prepareRename: {} at {}", params.getTextDocument(), params.getPosition()); @@ -304,42 +341,9 @@ public CompletableFuture (t == null ? file.getMostRecentTree().get() : t)) - .thenApply(tr -> { - Position rascalCursorPos = Locations.toRascalPosition(file.getLocation(), params.getPosition(), columns); - - // Find all trees containing the cursor, in ascending order of size - IList focusList = TreeSearch.computeFocusList(tr, rascalCursorPos.getLine(), rascalCursorPos.getCharacter()); - List sortNames = focusList.stream() - .map(tree -> ProductionAdapter.getSortName(TreeAdapter.getProduction((ITree) tree))) - .collect(Collectors.toList()); - - int qNameIdx = sortNames.indexOf("QualifiedName"); - if (qNameIdx != -1) { - // Cursor is at a qualified name - ITree qualifiedName = (ITree) focusList.get(qNameIdx); - - // If the qualified name is in a header, but not in module parameters or a syntax defintion, it is a full module path - if (sortNames.contains("Header") && !(sortNames.contains("ModuleParameters") || sortNames.contains("SyntaxDefinition"))) { - return Either3.forLeft3(DocumentChanges.locationToRange(this, TreeAdapter.getLocation(qualifiedName))); - } - - // Since the cursor is not in a header, the qualified name consists of a declaration name on the right, and an optional module path prefix. - IList names = TreeAdapter.getListASTArgs(TreeAdapter.getArg(qualifiedName, "names")); - - // Even if the cursor is on the module prefix, we steer towards renaming the declaration - return Either3.forLeft3(DocumentChanges.locationToRange(this, TreeAdapter.getLocation((ITree) names.get(names.size() - 1)))); - } - - switch (sortNames.get(0)) { - case "Name": // intentional fall-through - case "Nonterminal": // intentional fall-through - case "NonterminalLabel": { - // Return name location - return Either3.forLeft3(DocumentChanges.locationToRange(this, TreeAdapter.getLocation((ITree) focusList.get(0)))); - } - default: return null; - } - }); + .thenApply(tr -> getCursorFromPosition(file.getLocation(), tr, params.getPosition())) + .thenApply(cur -> DocumentChanges.locationToRange(this, TreeAdapter.getLocation(cur))) + .thenApply(Either3::forFirst); } @Override @@ -355,7 +359,8 @@ public CompletableFuture rename(RenameParams params) { return file.getCurrentTreeAsync() .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(tr -> getCursorFromPosition(file.getLocation(), tr, params.getPosition())) + .thenCompose(cursor -> rascalServices.getRename(cursor, workspaceFolders, facts::getPathConfig, params.getNewName()).get()) .thenApply(t -> DocumentChanges.translateDocumentChanges(this, t)); }