diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCompletions.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCompletions.java index 420b6cbd7..ae593e3c8 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCompletions.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCompletions.java @@ -31,6 +31,7 @@ import org.eclipse.lemminx.dom.DOMDocument; import org.eclipse.lemminx.dom.DOMElement; import org.eclipse.lemminx.dom.DOMNode; +import org.eclipse.lemminx.dom.DOMText; import org.eclipse.lemminx.dom.DTDDeclParameter; import org.eclipse.lemminx.dom.parser.Scanner; import org.eclipse.lemminx.dom.parser.ScannerState; @@ -53,6 +54,7 @@ import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.jsonrpc.CancelChecker; +import org.w3c.dom.Node; /** * XML completions support. @@ -135,12 +137,11 @@ public CompletionList doComplete(DOMDocument xmlDocument, Position position, Sha if (DOMNode.isIncluded(systemId, offset)) { /** - * Completion invoked within systemId parameter - * ie, completion offset is at | like so: - * + * Completion invoked within systemId parameter ie, completion offset is at | + * like so: */ - collectDTDSystemIdSuggestions(systemId.getStart(), systemId.getEnd(), - completionRequest, completionResponse); + collectDTDSystemIdSuggestions(systemId.getStart(), systemId.getEnd(), completionRequest, + completionResponse); return completionResponse; } break; @@ -346,16 +347,16 @@ private static Integer getSuffixIndex(String text, String suffix, final int init // There is one of character of the suffix offset++; if (suffixIndex == suffix.length()) { - // the suffix index is the last character of the suffix + // the suffix index is the last character of the suffix return offset; } // Try to eat the most characters of the suffix - for (; offset < text.length(); offset++) { + for (; offset < text.length(); offset++) { suffixIndex++; if (suffixIndex == suffix.length()) { - // the suffix index is the last character of the suffix + // the suffix index is the last character of the suffix return offset; - } + } ch = text.charAt(offset); if (suffix.charAt(suffixIndex) != ch) { return offset; @@ -752,6 +753,11 @@ private void collectInsideContent(CompletionRequest request, CompletionResponse collectOpenTagSuggestions(false, tagNameRange, request, response); collectCloseTagSuggestions(tagNameRange, true, true, false, request, response); } + // Adjust the range for covering the text node. + Range textRange = getTextRangeInsideContent(request.getNode()); + if (textRange != null) { + request.setReplaceRange(textRange); + } // Participant completion on XML content for (ICompletionParticipant participant : getCompletionParticipants()) { try { @@ -763,6 +769,29 @@ private void collectInsideContent(CompletionRequest request, CompletionResponse collectionRegionProposals(request, response); } + private static Range getTextRangeInsideContent(DOMNode node) { + switch (node.getNodeType()) { + case Node.ELEMENT_NODE: + Node firstChild = node.getFirstChild(); + if (firstChild == null) { + // ex : | + DOMElement element = (DOMElement) node; + return XMLPositionUtility.createRange(element.getStartTagCloseOffset() + 1, + element.getStartTagCloseOffset() + 1, element.getOwnerDocument()); + } + if (firstChild.getNodeType() == Node.TEXT_NODE) { + // ex : abcd| + return XMLPositionUtility.selectText((DOMText) firstChild); + } + return null; + case Node.TEXT_NODE: + // ex : | + return XMLPositionUtility.selectText((DOMText) node); + } + // should never occur + return null; + } + private void collectionRegionProposals(ICompletionRequest request, ICompletionResponse response) { // Completion for #region try { @@ -884,8 +913,10 @@ private void collectAttributeValueSuggestions(int valueStart, int valueEnd, Comp /** * Collect completion items for DTD systemId * - * @param valueStart the start offset of the systemId value, including quote - * @param valueEnd the end offset of the systemId value, including quote + * @param valueStart the start offset of the systemId value, including + * quote + * @param valueEnd the end offset of the systemId value, including + * quote * @param completionRequest the completion request * @param completionResponse the completion response */ diff --git a/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/services/extensions/HTMLCompletionExtensionsTest.java b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/services/extensions/HTMLCompletionExtensionsTest.java index 5528eca96..52943e4a6 100644 --- a/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/services/extensions/HTMLCompletionExtensionsTest.java +++ b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/services/extensions/HTMLCompletionExtensionsTest.java @@ -13,6 +13,7 @@ package org.eclipse.lemminx.services.extensions; import static org.eclipse.lemminx.XMLAssert.c; +import static org.eclipse.lemminx.XMLAssert.r; import org.eclipse.lemminx.XMLAssert; import org.eclipse.lemminx.commons.BadLocationException; @@ -20,6 +21,7 @@ import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionItemKind; import org.eclipse.lsp4j.InsertTextFormat; +import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.jsonrpc.messages.Either; @@ -120,6 +122,20 @@ public void testHTMLAttributeValueCompletion() throws BadLocationException { c("checkbox", "\"checkbox\"" /* "|", // + c("Test replace range", "replacement text", r(0, 7, 0, 7), null)); + testCompletionFor(" |", // + c("Test replace range", "replacement text", r(0, 7, 0, 8), null)); + testCompletionFor("| ", // + c("Test replace range", "replacement text", r(0, 7, 0, 8), null)); + testCompletionFor("some extisti|ng text", // + c("Test replace range", "replacement text", r(0, 7, 0, 26), null)); + testCompletionFor("some extisti|ng
text", // + c("Test replace range", "replacement text", r(0, 7, 0, 22), null)); + } + public static void testCompletionFor(String value, CompletionItem... expectedItems) throws BadLocationException { XMLAssert.testCompletionFor(new HTMLLanguageService(), value, (String) null, null, null, null, true, expectedItems); @@ -180,8 +196,8 @@ public void onAttributeName(boolean generateValue, ICompletionRequest completion } @Override - public void onAttributeValue(String valuePrefix, - ICompletionRequest completionRequest, ICompletionResponse completionResponse) { + public void onAttributeValue(String valuePrefix, ICompletionRequest completionRequest, + ICompletionResponse completionResponse) { String tag = completionRequest.getCurrentTag(); String attributeName = completionRequest.getCurrentAttributeName(); HTMLTag htmlTag = HTMLTag.getHTMLTag(tag); @@ -201,7 +217,7 @@ public void onAttributeValue(String valuePrefix, String[] values = HTMLTag.getAttributeValues(attrType); for (String value : values) { String insertText = completionRequest.getInsertAttrValue(value); - + CompletionItem item = new CompletionItem(); item.setLabel(value); item.setFilterText(insertText); @@ -216,6 +232,16 @@ public void onAttributeValue(String valuePrefix, } } } + + @Override + public void onXMLContent(ICompletionRequest request, ICompletionResponse response) { + CompletionItem completion = new CompletionItem("Test replace range"); + TextEdit edit = new TextEdit(); + edit.setNewText("replacement text"); + edit.setRange(request.getReplaceRange()); + completion.setTextEdit(edit); + response.addCompletionItem(completion); + } } } }