Skip to content

Commit

Permalink
Don't generate end element on apply completion if it exists
Browse files Browse the repository at this point in the history
Fixes eclipse-lemminx#651

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Apr 22, 2020
1 parent 47fe693 commit eafa172
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.lemminx.commons.BadLocationException;
import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.dom.DOMElement;
import org.eclipse.lemminx.dom.DOMNode;
import org.eclipse.lemminx.extensions.contentmodel.model.CMAttributeDeclaration;
import org.eclipse.lemminx.extensions.contentmodel.model.CMDocument;
import org.eclipse.lemminx.extensions.contentmodel.model.CMElementDeclaration;
Expand Down Expand Up @@ -219,11 +221,11 @@ private static void addTagName(NodeList list, Set<String> tags, ICompletionReque
}
}

private static void addCompletionItem(CMElementDeclaration elementDeclaration, DOMElement element,
private static void addCompletionItem(CMElementDeclaration elementDeclaration, DOMElement parentElement,
String defaultPrefix, boolean forceUseOfPrefix, ICompletionRequest request, ICompletionResponse response,
XMLGenerator generator, Set<String> tags) {
String prefix = forceUseOfPrefix ? defaultPrefix
: (element != null ? element.getPrefix(elementDeclaration.getNamespace()) : null);
: (parentElement != null ? parentElement.getPrefix(elementDeclaration.getNamespace()) : null);
String label = elementDeclaration.getName(prefix);
if (tags != null) {
if (tags.contains(label)) {
Expand All @@ -238,12 +240,69 @@ private static void addCompletionItem(CMElementDeclaration elementDeclaration, D
item.setKind(CompletionItemKind.Property);
MarkupContent documentation = XMLGenerator.createMarkupContent(elementDeclaration, request);
item.setDocumentation(documentation);
String xml = generator.generate(elementDeclaration, prefix);
String xml = generator.generate(elementDeclaration, prefix,
isGenerateEndTag(request.getNode(), request.getOffset(), label));
item.setTextEdit(new TextEdit(request.getReplaceRange(), xml));
item.setInsertTextFormat(InsertTextFormat.Snippet);
response.addCompletionItem(item, true);
}

private static boolean isGenerateEndTag(DOMNode node, int offset, String tagName) {
if (node == null) {
return true;
}
if (node.isText()) {
DOMNode next = node.getNextSibling();
if (next == null || !next.isElement()) {
return true;
}
DOMElement nextElement = (DOMElement) next;
if (nextElement.hasStartTag()) {
return true;
}
if (nextElement.isSameTag(tagName) && !nextElement.isClosed() && nextElement.hasEndTag()
&& !nextElement.hasStartTag()) {
return false;
}
return true;
}
if (!node.isElement()) {
return true;
}
DOMElement element = (DOMElement) node;
if (!element.isInStartTag(offset) && !element.isInEndTag(offset)) {
// completion inside element content
// <employee>|</employee>
// <employee> |</employee>
// <employee> | </employee>
return true;
}
if (element.getEnd() <= offset) {
// <employee />|
// <employee /> |
return true;
}

// (element.isEndTagClosed() && element.getEnd() <= offset)

if (element.isClosed()) {
// <employe|e></employee>
return false;
}
// element is not
List<DOMNode> children = element.getChildren();
for (DOMNode child : children) {
if (child.isElement()) {
DOMElement childElement = (DOMElement) child;
if (childElement.isSameTag(tagName) && !childElement.isClosed() && childElement.hasEndTag()
&& !childElement.hasStartTag()) {
return false;
}
}
}
return true;
}

@Override
public void onAttributeName(boolean generateValue, ICompletionRequest request, ICompletionResponse response)
throws Exception {
Expand Down Expand Up @@ -356,8 +415,7 @@ public void onXMLContent(ICompletionRequest request, ICompletionResponse respons
end = document.positionAt(endOffset);
}
int completionOffset = request.getOffset();
String tokenStart = StringUtils.getWhitespaces(document.getText(), startOffset,
completionOffset);
String tokenStart = StringUtils.getWhitespaces(document.getText(), startOffset, completionOffset);
Range fullRange = new Range(start, end);
values.forEach(value -> {
CompletionItem item = new CompletionItem();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,31 +65,28 @@ public XMLGenerator(XMLFormattingOptions formattingOptions, boolean autoCloseTag
this.canSupportSnippets = canSupportSnippets;
}

public String generate(CMElementDeclaration elementDeclaration) {
return generate(elementDeclaration, null);
}

/**
* Returns the XML generated from the given element declaration.
*
* @param elementDeclaration
* @param prefix
* @return the XML generated from the given element declaration.
*/
public String generate(CMElementDeclaration elementDeclaration, String prefix) {
public String generate(CMElementDeclaration elementDeclaration, String prefix, boolean generateEndTag) {
XMLBuilder xml = new XMLBuilder(formattingOptions, whitespacesIndent, lineDelimiter);
generate(elementDeclaration, prefix, 0, 0, xml, new ArrayList<CMElementDeclaration>());
generate(elementDeclaration, prefix, generateEndTag, 0, 0, xml, new ArrayList<CMElementDeclaration>());
if (canSupportSnippets) {
xml.addContent(SnippetsBuilder.tabstops(0)); // "$0"
}
return xml.toString();
}

private int generate(CMElementDeclaration elementDeclaration, String prefix, int level, int snippetIndex,
private int generate(CMElementDeclaration elementDeclaration, String prefix, boolean generateEndTag, int level, int snippetIndex,
XMLBuilder xml, List<CMElementDeclaration> generatedElements) {
if (generatedElements.contains(elementDeclaration)) {
return snippetIndex;
}
boolean autoCloseTags = this.autoCloseTags && generateEndTag;
generatedElements.add(elementDeclaration);
if (level > 0) {
xml.linefeed();
Expand All @@ -106,7 +103,7 @@ private int generate(CMElementDeclaration elementDeclaration, String prefix, int
if ((level > maxLevel)) {
level++;
for (CMElementDeclaration child : children) {
snippetIndex = generate(child, prefix, level, snippetIndex, xml, generatedElements);
snippetIndex = generate(child, prefix, true, level, snippetIndex, xml, generatedElements);
}
level--;
xml.linefeed();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ private void collectOpenTagSuggestions(boolean hasOpenBracket, Range replaceRang
LOGGER.log(Level.SEVERE, "While performing ICompletionParticipant#onTagOpen", e);
}
}
DOMNode currentElement = completionRequest.getNode();
DOMElement parentNode = completionRequest.getParentElement();
if (parentNode != null && !parentNode.getOwnerDocument().hasGrammar()) {
// no grammar, collect similar tags from the parent node
Expand Down Expand Up @@ -522,7 +523,7 @@ private void collectOpenTagSuggestions(boolean hasOpenBracket, Range replaceRang
if (completionRequest.isCompletionSnippetsSupported()) {
xml.append("$0");
}
if (completionRequest.isAutoCloseTags()) {
if (!currentElement.isClosed() && completionRequest.isAutoCloseTags()) {
xml.append("</").append(tag).append(">");
}
}
Expand Down

0 comments on commit eafa172

Please sign in to comment.