Skip to content

Commit

Permalink
ICompletionParticipant#onXMLContent is not called for CDATA (#1699)
Browse files Browse the repository at this point in the history
* fix: ICompletionParticipant#onXMLContent is not called for CDATA

Signed-off-by: Christoph Läubrich <[email protected]>
  • Loading branch information
laeubi authored Nov 7, 2024
1 parent 830e00d commit 2482d4a
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public CompletionList doComplete(DOMDocument xmlDocument, Position position, Sha
Scanner scanner = XMLScanner.createScanner(text, node.getStart(), isInsideDTDContent(node, xmlDocument));
String currentTag = "";
TokenType token = scanner.scan();
TokenType lastToken = null;
while (token != TokenType.EOS && scanner.getTokenOffset() <= offset) {
cancelChecker.checkCanceled();
switch (token) {
Expand Down Expand Up @@ -249,6 +250,13 @@ public CompletionList doComplete(DOMDocument xmlDocument, Position position, Sha
}
}
break;
case CDATATagOpen:
break;
case CDATATagClose:
if (lastToken != TokenType.CDATATagOpen) {
break;
}
case CDATAContent:
case Content:
if (completionRequest.getXMLDocument().isDTD()
|| completionRequest.getXMLDocument().isWithinInternalDTD(offset)) {
Expand Down Expand Up @@ -284,6 +292,7 @@ public CompletionList doComplete(DOMDocument xmlDocument, Position position, Sha
}
break;
}
lastToken = token;
token = scanner.scan();
}
return completionResponse;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ public void testAutoCloseTagCompletionWithLeadingTextContent() throws BadLocatio
@Test
public void testnoCDATANPE() {
try {
testCompletionFor("<a> <![CDATA[<b>foo</b>]]| </a>", 0);
testCompletionFor("<a> <![CDATA[<b>foo</b>]]| </a>", 1);
} catch (BadLocationException e) {
fail();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*******************************************************************************
* Copyright (c) 2024 Christoph Läubrich 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:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.lemminx.services.extensions;

import org.eclipse.lemminx.AbstractCacheBasedTest;
import org.eclipse.lemminx.XMLAssert;
import org.eclipse.lemminx.commons.BadLocationException;
import org.eclipse.lemminx.dom.DOMElement;
import org.eclipse.lemminx.dom.DOMNode;
import org.eclipse.lemminx.services.XMLLanguageService;
import org.eclipse.lemminx.services.extensions.completion.ICompletionParticipant;
import org.eclipse.lemminx.services.extensions.completion.ICompletionRequest;
import org.eclipse.lemminx.services.extensions.completion.ICompletionResponse;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.junit.jupiter.api.Test;
import org.w3c.dom.CDATASection;

/**
* XML completion tests which uses the {@link ICompletionParticipant}
*/
public class XMLCompletionExtensionTest extends AbstractCacheBasedTest {

private static final CompletionItem HELLO_WORLD_ITEM = XMLAssert.c("World", "World");

private final class TestCompletionParticipant implements ICompletionParticipant {
@Override
public void onXMLContent(ICompletionRequest request, ICompletionResponse response, CancelChecker cancelChecker)
throws Exception {
if ("hello".equals(request.getCurrentTag())) {
response.addCompletionAttribute(HELLO_WORLD_ITEM);
} else {
DOMNode node = request.getNode();
if (node instanceof CDATASection) {
DOMElement element = node.getParentElement();
String tagName = element.getTagName();
if ("hello".equals(tagName)) {
response.addCompletionAttribute(HELLO_WORLD_ITEM);
}
}
}
}

@Override
public void onTagOpen(ICompletionRequest completionRequest, ICompletionResponse completionResponse,
CancelChecker cancelChecker) throws Exception {
}

@Override
public void onDTDSystemId(String valuePrefix, ICompletionRequest request, ICompletionResponse response,
CancelChecker cancelChecker) throws Exception {
}

@Override
public void onAttributeValue(String valuePrefix, ICompletionRequest request, ICompletionResponse response,
CancelChecker cancelChecker) throws Exception {
}

@Override
public void onAttributeName(boolean generateValue, ICompletionRequest request, ICompletionResponse response,
CancelChecker cancelChecker) throws Exception {
}
}

/**
* Test that
* {@link ICompletionParticipant#onXMLContent(ICompletionRequest, ICompletionResponse, CancelChecker)}
* is called for a simple content tag
*
* @throws BadLocationException
*/
@Test
public void testSimpleCompletion() throws BadLocationException {
XMLLanguageService service = new XMLLanguageService();
service.registerCompletionParticipant(new TestCompletionParticipant());
XMLAssert.testCompletionFor(service, "<hello>|</hello>", (String) null, null, null, null, true,
HELLO_WORLD_ITEM);
}

/**
* Test that
* {@link ICompletionParticipant#onXMLContent(ICompletionRequest, ICompletionResponse, CancelChecker)}
* is called for a CDATA content tag
*
* @throws BadLocationException
*/
@Test
public void testCDATACompletion() throws BadLocationException {
XMLLanguageService service = new XMLLanguageService();
service.registerCompletionParticipant(new TestCompletionParticipant());
// check cursor is at the end of cdata section
XMLAssert.testCompletionFor(service, "<hello><![CDATA[ |]]></hello>", (String) null, null, null, null, true,
HELLO_WORLD_ITEM);
// check cursor is at start of section
XMLAssert.testCompletionFor(service, "<hello><![CDATA[| ]]></hello>", (String) null, null, null, null, true,
HELLO_WORLD_ITEM);
// check cursor is inside of section
XMLAssert.testCompletionFor(service, "<hello><![CDATA[ | ]]></hello>", (String) null, null, null, null, true,
HELLO_WORLD_ITEM);
// check cursor is inside completely empty section
XMLAssert.testCompletionFor(service, "<hello><![CDATA[|]]></hello>", (String) null, null, null, null, true,
HELLO_WORLD_ITEM);
}

}

0 comments on commit 2482d4a

Please sign in to comment.