Skip to content

Commit

Permalink
Determine cursor tree again for renaming.
Browse files Browse the repository at this point in the history
  • Loading branch information
toinehartman committed Dec 16, 2024
1 parent 5491327 commit 899ed7f
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -210,11 +207,7 @@ public InterruptibleFuture<IList> getDocumentSymbols(IConstructor module) {
}


public InterruptibleFuture<ITuple> getRename(ITree module, Position cursor, Set<ISourceLocation> workspaceFolders, Function<ISourceLocation, PathConfig> 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<ITuple> getRename(ITree cursorTree, Set<ISourceLocation> workspaceFolders, Function<ISourceLocation, PathConfig> getPathConfig, String newName) {
return runEvaluator("Rascal rename", semanticEvaluator, eval -> {
try {
IFunction rascalGetPathConfig = eval.getFunctionValueFactory().function(getPathConfigType, (t, u) -> addResources(getPathConfig.apply((ISourceLocation) t[0])));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,43 @@ public CompletableFuture<Either<List<? extends Location>, List<? extends Locatio
;
}

private ITree getCursorFromPosition(ISourceLocation file, ITree moduleTree, Position p) {
Position rascalCursorPos = Locations.toRascalPosition(file, p, columns);

// Find all trees containing the cursor, in ascending order of size
IList focusList = TreeSearch.computeFocusList(moduleTree, rascalCursorPos.getLine(), rascalCursorPos.getCharacter());
List<String> 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<Either3<Range, PrepareRenameResult, PrepareRenameDefaultBehavior>> prepareRename(PrepareRenameParams params) {
logger.debug("textDocument/prepareRename: {} at {}", params.getTextDocument(), params.getPosition());
Expand All @@ -304,42 +341,9 @@ public CompletableFuture<Either3<Range, PrepareRenameResult, PrepareRenameDefaul
return file.getCurrentTreeAsync()
.thenApply(Versioned::get)
.handle((t, r) -> (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<String> 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
Expand All @@ -355,7 +359,8 @@ public CompletableFuture<WorkspaceEdit> 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));
}

Expand Down

0 comments on commit 899ed7f

Please sign in to comment.