Skip to content

Commit

Permalink
IRenameParticipant.doRename() is not conform with LSP-defined rename …
Browse files Browse the repository at this point in the history
…result eclipse#1521
  • Loading branch information
vrubezhny committed Jun 10, 2023
1 parent c7f50b8 commit daaa002
Show file tree
Hide file tree
Showing 14 changed files with 214 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
*******************************************************************************/
package org.eclipse.lemminx.extensions.references.participants;

import static org.eclipse.lemminx.utils.TextEditUtils.creatTextDocumentEdit;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand All @@ -24,8 +26,11 @@
import org.eclipse.lemminx.services.extensions.IPrepareRenameRequest;
import org.eclipse.lemminx.services.extensions.IRenameParticipant;
import org.eclipse.lemminx.services.extensions.IRenameRequest;
import org.eclipse.lemminx.services.extensions.IRenameResponse;
import org.eclipse.lsp4j.PrepareRenameResult;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.ResourceOperation;
import org.eclipse.lsp4j.TextDocumentEdit;
import org.eclipse.lsp4j.TextEdit;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
Expand Down Expand Up @@ -88,19 +93,19 @@ private static String createPlaceHolder(SearchNode searchNode) {
// --------------- Rename

@Override
public void doRename(IRenameRequest request, List<TextEdit> edits, CancelChecker cancelChecker) {
edits.addAll(getRenameTextEdits(request, cancelChecker));
public void doRename(IRenameRequest request, IRenameResponse renameResponse, CancelChecker cancelChecker) {
renameResponse.addTextDocumentEdit(getRenameTextDocumentEdit(request, cancelChecker));
}

private List<TextEdit> getRenameTextEdits(IRenameRequest request, CancelChecker cancelChecker) {
private TextDocumentEdit getRenameTextDocumentEdit(IRenameRequest request, CancelChecker cancelChecker) {
SearchQuery query = SearchQueryFactory.createToQueryByRetrievingToBefore(request.getNode(), request.getOffset(),
plugin.getReferencesSettings(), cancelChecker);
if (query == null) {
// The query cannot be created because:
// - the node is neither a text nor an attribute
// - it doesn't exists some expressions for the DOM document of the node.
// - there are none expressions which matches the node.
return Collections.emptyList();
return null;
}
query.setMatchNode(true);
query.setSearchInIncludedFiles(true);
Expand All @@ -117,7 +122,7 @@ private List<TextEdit> getRenameTextEdits(IRenameRequest request, CancelChecker
// Insert at first, the text edit for the node which was updated
Range range = query.getSearchNode().createRange(true);
textEdits.add(0, new TextEdit(range, newText));
return textEdits;
return creatTextDocumentEdit(request.getXMLDocument(), textEdits);
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2022 Red Hat Inc. and others.
* Copyright (c) 2022, 2023 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
Expand All @@ -11,6 +11,8 @@
*******************************************************************************/
package org.eclipse.lemminx.extensions.relaxng.grammar.rng;

import static org.eclipse.lemminx.utils.TextEditUtils.creatTextDocumentEdit;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand All @@ -25,11 +27,13 @@
import org.eclipse.lemminx.services.extensions.IPrepareRenameRequest;
import org.eclipse.lemminx.services.extensions.IRenameParticipant;
import org.eclipse.lemminx.services.extensions.IRenameRequest;
import org.eclipse.lemminx.services.extensions.IRenameResponse;
import org.eclipse.lemminx.utils.DOMUtils;
import org.eclipse.lemminx.utils.XMLPositionUtility;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.PrepareRenameResult;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentEdit;
import org.eclipse.lsp4j.TextEdit;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
Expand Down Expand Up @@ -59,22 +63,22 @@ public Either<Range, PrepareRenameResult> prepareRename(IPrepareRenameRequest re
// --------------- Rename

@Override
public void doRename(IRenameRequest request, List<TextEdit> edits, CancelChecker cancelChecker) {
edits.addAll(getRenameTextEdits(request, cancelChecker));
public void doRename(IRenameRequest request, IRenameResponse renameResponse, CancelChecker cancelChecker) {
renameResponse.addTextDocumentEdit(getRenameTextDocumentEdit(request, cancelChecker));
}

private List<TextEdit> getRenameTextEdits(IRenameRequest request, CancelChecker cancelChecker) {
private TextDocumentEdit getRenameTextDocumentEdit(IRenameRequest request, CancelChecker cancelChecker) {
// RNG rename can be applied for:
// - define/@name
DOMAttr attr = findAttrToRename(request);
if (attr == null) {
return Collections.emptyList();
return null;
}
DOMElement ownerElement = attr.getOwnerElement();
DOMDocument document = request.getXMLDocument();
String newText = request.getNewText();
List<Location> locations = getReferenceLocations(ownerElement, cancelChecker);
return renameAttributeValueTextEdits(document, attr, newText, locations);
return creatTextDocumentEdit(document, renameAttributeValueTextEdits(document, attr, newText, locations));
}

private List<Location> getReferenceLocations(DOMNode node, CancelChecker cancelChecker) {
Expand Down Expand Up @@ -105,9 +109,7 @@ private List<TextEdit> renameAttributeValueTextEdits(DOMDocument document, DOMAt
for (Location location : locations) {
Range textEditRange = location.getRange();
reduceRangeFromBothEnds(textEditRange, 1);

TextEdit textEdit = new TextEdit(textEditRange, newText);
textEdits.add(textEdit);
textEdits.add(new TextEdit(textEditRange, newText));
}

return textEdits;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019 Red Hat Inc. and others.
* Copyright (c) 2019, 2023 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
Expand All @@ -11,6 +11,8 @@
*******************************************************************************/
package org.eclipse.lemminx.extensions.xsd.participants;

import static org.eclipse.lemminx.utils.TextEditUtils.creatTextDocumentEdit;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand All @@ -26,12 +28,14 @@
import org.eclipse.lemminx.services.extensions.IPrepareRenameRequest;
import org.eclipse.lemminx.services.extensions.IRenameParticipant;
import org.eclipse.lemminx.services.extensions.IRenameRequest;
import org.eclipse.lemminx.services.extensions.IRenameResponse;
import org.eclipse.lemminx.utils.DOMUtils;
import org.eclipse.lemminx.utils.XMLPositionUtility;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.PrepareRenameResult;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentEdit;
import org.eclipse.lsp4j.TextEdit;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
Expand Down Expand Up @@ -62,23 +66,23 @@ public Either<Range, PrepareRenameResult> prepareRename(IPrepareRenameRequest re
// --------------- Rename

@Override
public void doRename(IRenameRequest request, List<TextEdit> edits, CancelChecker cancelChecker) {
edits.addAll(getRenameTextEdits(request, cancelChecker));
public void doRename(IRenameRequest request, IRenameResponse renameResponse, CancelChecker cancelChecker) {
renameResponse.addTextDocumentEdit(getRenameTextDocumentEdit(request, cancelChecker));
}

private List<TextEdit> getRenameTextEdits(IRenameRequest request, CancelChecker cancelChecker) {
private TextDocumentEdit getRenameTextDocumentEdit(IRenameRequest request, CancelChecker cancelChecker) {
// XSD rename can be applied for:
// - xsd:complexType/@name
// - xs:simpleType/@name
DOMAttr attr = findAttrToRename(request);
if (attr == null) {
return Collections.emptyList();
return null;
}
DOMElement ownerElement = attr.getOwnerElement();
DOMDocument document = request.getXMLDocument();
String newText = request.getNewText();
List<Location> locations = getReferenceLocations(ownerElement, cancelChecker);
return renameAttributeValueTextEdits(document, attr, newText, locations);
return creatTextDocumentEdit(document, renameAttributeValueTextEdits(document, attr, newText, locations));
}

private List<Location> getReferenceLocations(DOMNode node, CancelChecker cancelChecker) {
Expand Down Expand Up @@ -123,8 +127,7 @@ private List<TextEdit> renameAttributeValueTextEdits(DOMDocument document, DOMAt
increaseStartRange(textEditRange, colonIndex + 1);
}

TextEdit textEdit = new TextEdit(textEditRange, newText);
textEdits.add(textEdit);
textEdits.add(new TextEdit(textEditRange, newText));
}

return textEdits;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*******************************************************************************
* Copyright (c) 2023 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.lemminx.services;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.eclipse.lemminx.services.extensions.IRenameResponse;
import org.eclipse.lsp4j.ResourceOperation;
import org.eclipse.lsp4j.TextDocumentEdit;
import org.eclipse.lsp4j.TextEdit;
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
import org.eclipse.lsp4j.jsonrpc.messages.Either;

/**
* Rename response object to store the rename operation results
*/
class RenameResponse implements IRenameResponse {
private List<Either<TextDocumentEdit, ResourceOperation>> documentChanges = new ArrayList<>();

@Override
public void addTextDocumentEdit(TextDocumentEdit textDocumentEdit) {
if (textDocumentEdit == null) {
return;
}

String documentURI = textDocumentEdit.getTextDocument().getUri();
Optional<TextDocumentEdit> change = documentChanges.stream().filter(Either::isLeft)
.filter(e -> documentURI.equals(e.getLeft().getTextDocument().getUri()))
.map(Either::getLeft).findFirst();
if(change.isPresent()) {
TextDocumentEdit existingTextDocumentEdit = change.get();
List<TextEdit> edits = new ArrayList<>();
edits.addAll(existingTextDocumentEdit.getEdits());
textDocumentEdit.getEdits().stream().forEach(te -> {
if (!edits.contains(te)) {
edits.add(te);
}
});
existingTextDocumentEdit.setEdits(edits);
} else {
documentChanges.add(Either.forLeft(textDocumentEdit));
}
}

@Override
public void addResourceOperation(ResourceOperation resourceOperation) {
documentChanges.add(Either.forRight(resourceOperation));
}

public List<Either<TextDocumentEdit, ResourceOperation>> getDocumentChanges() {
return documentChanges;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 Angelo ZERR
* Copyright (c) 2018, 2023 Angelo ZERR
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -27,12 +27,12 @@
import org.eclipse.lemminx.extensions.contentmodel.settings.XMLValidationSettings;
import org.eclipse.lemminx.services.extensions.XMLExtensionsRegistry;
import org.eclipse.lemminx.services.extensions.diagnostics.DiagnosticsResult;
import org.eclipse.lemminx.services.format.TextEditUtils;
import org.eclipse.lemminx.settings.SharedSettings;
import org.eclipse.lemminx.settings.XMLCodeLensSettings;
import org.eclipse.lemminx.settings.XMLCompletionSettings;
import org.eclipse.lemminx.settings.XMLFoldingSettings;
import org.eclipse.lemminx.settings.XMLSymbolSettings;
import org.eclipse.lemminx.utils.TextEditUtils;
import org.eclipse.lemminx.utils.XMLPositionUtility;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.CodeActionContext;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019 Red Hat Inc. and others.
* Copyright (c) 2019, 2023 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
Expand All @@ -11,6 +11,8 @@
*******************************************************************************/
package org.eclipse.lemminx.services;

import static org.eclipse.lemminx.utils.TextEditUtils.creatTextDocumentEdit;
import static org.eclipse.lemminx.utils.TextEditUtils.createWorkspaceEdit;
import static org.eclipse.lemminx.utils.XMLPositionUtility.covers;
import static org.eclipse.lemminx.utils.XMLPositionUtility.doesTagCoverPosition;
import static org.eclipse.lemminx.utils.XMLPositionUtility.getTagNameRange;
Expand Down Expand Up @@ -47,7 +49,7 @@
*
* Author: Nikolas Komonen - [email protected]
*/
public class XMLRename {
class XMLRename {

private static final Logger LOGGER = Logger.getLogger(XMLRename.class.getName());

Expand Down Expand Up @@ -76,14 +78,14 @@ public WorkspaceEdit doRename(DOMDocument xmlDocument, Position position, String
if (node == null || (!node.isAttribute() && !node.isElement() && !node.isText())
|| (node.isElement() && !((DOMElement) node).hasTagName())) {

return createWorkspaceEdit(xmlDocument.getDocumentURI(), Collections.emptyList());
cancelChecker.checkCanceled();
return createWorkspaceEdit(Collections.emptyList());
}

List<TextEdit> textEdits = new ArrayList<>();

RenameResponse renameResponse = new RenameResponse();
for (IRenameParticipant participant : extensionsRegistry.getRenameParticipants()) {
try {
participant.doRename(renameRequest, textEdits, cancelChecker);
participant.doRename(renameRequest, renameResponse, cancelChecker);
} catch (CancellationException e) {
throw e;
} catch (Exception e) {
Expand All @@ -93,11 +95,12 @@ public WorkspaceEdit doRename(DOMDocument xmlDocument, Position position, String
}
}

textEdits.addAll(getRenameTextEdits(xmlDocument, node, position, newText));
cancelChecker.checkCanceled();
renameResponse.addTextDocumentEdit(creatTextDocumentEdit(
xmlDocument, getRenameTextEdits(xmlDocument, node, position, newText)));

cancelChecker.checkCanceled();

return createWorkspaceEdit(xmlDocument.getDocumentURI(), textEdits);
return createWorkspaceEdit(renameResponse.getDocumentChanges());
}

private List<TextEdit> getRenameTextEdits(DOMDocument xmlDocument, DOMNode node, Position position,
Expand Down Expand Up @@ -279,12 +282,6 @@ private List<TextEdit> getXmlnsAttrRenameTextEdits(DOMDocument xmlDocument, DOME
return Collections.emptyList();
}

private WorkspaceEdit createWorkspaceEdit(String documentURI, List<TextEdit> textEdits) {
Map<String, List<TextEdit>> changes = new HashMap<>();
changes.put(documentURI, textEdits);
return new WorkspaceEdit(changes);
}

/**
* Creates a list of start and end tag rename's.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019 Red Hat Inc. and others.
* Copyright (c) 2019, 2023 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
Expand All @@ -15,7 +15,6 @@

import org.eclipse.lsp4j.PrepareRenameResult;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextEdit;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.eclipse.lsp4j.jsonrpc.messages.Either;

Expand All @@ -25,7 +24,22 @@
*/
public interface IRenameParticipant {

void doRename(IRenameRequest request, List<TextEdit> edits, CancelChecker cancelChecker);
/**
* Creates the list of document changes for the rename operation.
*
* @param request A rename request
* @param documentChanges A list to collect either text document edits or rename operations
* @param cancelChecker Cancel checker
* @since 0.26
*/
void doRename(IRenameRequest request, IRenameResponse renameResponse, CancelChecker cancelChecker);

/**
* Checks if rename operation can be executed for a given prepare rename request
*
* @param request A prepare rename request
* @param cancelChecker Cancel checker
* @return Either range or rename operation result of prepare rename operation
*/
Either<Range, PrepareRenameResult> prepareRename(IPrepareRenameRequest request, CancelChecker cancelChecker);
}
Loading

0 comments on commit daaa002

Please sign in to comment.