Skip to content

Commit

Permalink
Do not complete paths in attr unless beginning of value looks like a
Browse files Browse the repository at this point in the history
path

Fixes redhat-developer/vscode-xml#668

Signed-off-by: David Thompson <davthomp@redhat.com>
  • Loading branch information
datho7561 authored and angelozerr committed Oct 4, 2022
1 parent d8a9870 commit 4f794cf
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,20 @@ public class FilePathCompletionParticipant extends CompletionParticipantAdapter
public void onAttributeValue(String value, ICompletionRequest request, ICompletionResponse response,
CancelChecker cancelChecker) throws Exception {
// File path completion on attribute value
addCompletionItems(value, request, response);
addCompletionItems(value, request, response, false);
}

@Override
public void onDTDSystemId(String value, ICompletionRequest request, ICompletionResponse response,
CancelChecker cancelChecker) throws Exception {
// File path completion on DTD DOCTYPE SYSTEM
addCompletionItems(value, request, response);
addCompletionItems(value, request, response, true);
}

private static void addCompletionItems(String value, ICompletionRequest request, ICompletionResponse response)
private static void addCompletionItems(String value, ICompletionRequest request, ICompletionResponse response, boolean isInDoctype)
throws Exception {
String fullValue = value;
if (isEmpty(fullValue)) {
if (isEmpty(fullValue) && !isInDoctype) {
return;
}

Expand All @@ -101,7 +101,7 @@ private static void addCompletionItems(String value, ICompletionRequest request,
// ex value="file:///C:/fold|er"
int valuePathStartOffset = xmlDocument.offsetAt(request.getReplaceRange().getStart());
int endPathOffset = request.getOffset(); // offset after the typed character
int startPathOffset = StringUtils.getOffsetAfterWhitespace(fullValue, endPathOffset - valuePathStartOffset)
int startPathOffset = (fullValue.length() == 0 ? 0 : StringUtils.getOffsetAfterWhitespace(fullValue, endPathOffset - valuePathStartOffset))
+ valuePathStartOffset; // first character of URI
Range filePathRange = XMLPositionUtility.createRange(startPathOffset, endPathOffset, xmlDocument);
String originalValuePath = text.substring(startPathOffset, endPathOffset);
Expand Down Expand Up @@ -132,6 +132,9 @@ private static void addCompletionItems(String value, ICompletionRequest request,
return;
}
}
} else if (!hasPathBeginning(valuePath) && !isInDoctype) {
// the user probably didn't intend to complete a path
return;
}
// On Linux, Mac OS replace '\\' with '/'
if (!isWindows) {
Expand Down Expand Up @@ -259,4 +262,25 @@ private static void createFilePathCompletionItem(File f, Range replaceRange, ICo
response.addCompletionItem(item);
}

private static boolean hasPathBeginning(String currentText) {
if (currentText.startsWith("/")
|| currentText.startsWith("./")
|| currentText.startsWith("../")
|| currentText.startsWith("..\\")
|| currentText.startsWith(".\\")) {
return true;
}
return isAbsoluteWindowsPath(currentText);
}

private static boolean isAbsoluteWindowsPath(String currentText) {
if (currentText.length() < 3) {
return false;
}
if (!Character.isLetter(currentText.charAt(0))) {
return false;
}
return currentText.charAt(1) == ':' && (currentText.charAt(2) == '\\' || currentText.charAt(2) == '/');
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ public abstract class AbstractCacheBasedTest {

@BeforeEach
public final void setupCache() throws Exception {
System.out.println(this.getClass().getName() + ": " + uuid);
clearCache();
FilesUtils.resetDeployPath();
Assertions.assertNotNull(parentDir);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.eclipse.lemminx.XMLAssert;
import org.eclipse.lemminx.commons.BadLocationException;
import org.eclipse.lemminx.utils.FilesUtils;
import org.eclipse.lemminx.utils.platform.Platform;
import org.eclipse.lsp4j.CompletionItem;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -66,15 +67,13 @@ public void testFilePathCompletionFolderABackSlash() throws BadLocationException
@Test
public void testFilePathCompletionFolderB() throws BadLocationException {
String xml = "<a path=\"folderB/|\">";
CompletionItem[] items = getCompletionItemList("/", 0, 16, 17, "xsdB1.xsd", "xmlB1.xml");
testCompletionFor(xml, 2, items);
testCompletionFor(xml, 0);
}

@Test
public void testFilePathCompletionFolderBBackSlash() throws BadLocationException {
String xml = "<a path=\"folderB\\|\">";
CompletionItem[] items = getCompletionItemList("\\", 0, 16, 17, "xsdB1.xsd", "xmlB1.xml");
testCompletionFor(xml, 2, items);
testCompletionFor(xml, 0);
}

@Test
Expand Down Expand Up @@ -113,44 +112,42 @@ public void testFilePathCompletionFolderBAbsolutePathWithFileScheme() throws Bad

@Test
public void testFilePathCompletionNestedA() throws BadLocationException {
String xml = "<a path=\"NestedA/|\">";
CompletionItem[] items = getCompletionItemList("/", 0, 16, 17, "NestedB");
String xml = "<a path=\"./NestedA/|\">";
CompletionItem[] items = getCompletionItemList("/", 0, 18, 19, "NestedB");
testCompletionFor(xml, 1, items);
}

@Test
public void testFilePathCompletionNestedABackSlash() throws BadLocationException {
String xml = "<a path=\"NestedA\\|\">";
CompletionItem[] items = getCompletionItemList("\\", 0, 16, 17, "NestedB");
String xml = "<a path=\"./NestedA\\|\">";
CompletionItem[] items = getCompletionItemList("\\", 0, 18, 19, "NestedB");
testCompletionFor(xml, 1, items);
}

@Test
public void testFilePathCompletionNestedBIncomplete() throws BadLocationException {
String xml = "<a path=\"NestedA/NestedB/ZZZ|\">";
CompletionItem[] items = getCompletionItemList("/", 0, 24, 28, "nestedXSD.xsd");
String xml = "<a path=\"./NestedA/NestedB/ZZZ|\">";
CompletionItem[] items = getCompletionItemList("/", 0, 26, 30, "nestedXSD.xsd");
testCompletionFor(xml, 1, items);
}

@Test
public void testFilePathCompletionNestedBIncompleteBackSlash() throws BadLocationException {
String xml = "<a path=\"NestedA\\NestedB\\ZZZ|\">";
CompletionItem[] items = getCompletionItemList("\\", 0, 24, 28, "nestedXSD.xsd");
String xml = "<a path=\".\\NestedA\\NestedB\\ZZZ|\">";
CompletionItem[] items = getCompletionItemList("\\", 0, 26, 30, "nestedXSD.xsd");
testCompletionFor(xml, 1, items);
}

@Test
public void testFilePathCompletionExtraTextInValue() throws BadLocationException {
String xml = "<a path=\"NAMESPACE_IGNORE_ME NestedA/NestedB/|\">";
CompletionItem[] items = getCompletionItemList("/", 0, 44, 45, "nestedXSD.xsd");
testCompletionFor(xml, 1, items);
testCompletionFor(xml, 0);
}

@Test
public void testFilePathCompletionExtraTextInValueBackSlash() throws BadLocationException {
String xml = "<a path=\"NAMESPACE_IGNORE_ME NestedA\\NestedB\\|\">";
CompletionItem[] items = getCompletionItemList("\\", 0, 44, 45, "nestedXSD.xsd");
testCompletionFor(xml, 1, items);
testCompletionFor(xml, 0);
}

@Test
Expand All @@ -166,11 +163,8 @@ public void testFilePathCompletionExtraTextInValueAbsolute() throws BadLocationE
@Test
public void testFilePathCompletionExtraTextInValueAbsoluteBackSlash() throws BadLocationException {
String filePath = userDirBackSlash + "\\src\\test\\resources\\filePathCompletion\\NestedA\\NestedB\\";
int filePathLength = filePath.length();
String xml = "<a path=\"NAMESPACE_IGNORE_ME " + filePath + "|\">";
CompletionItem[] items = getCompletionItemList("\\", 0, 29 + filePathLength - 1, 29 + filePathLength,
"nestedXSD.xsd");
testCompletionFor(xml, 1, items);
testCompletionFor(xml, Platform.isWindows ? 1 : 0);
}

@Test
Expand Down Expand Up @@ -262,22 +256,22 @@ public void testFilePathCompletionDTDFolderABackSlash() throws BadLocationExcept

@Test
public void testFilePathCompletionDTDFolderB() throws BadLocationException {
String xml = "<!DOCTYPE foo SYSTEM \"folderB/|\">";
CompletionItem[] items = getCompletionItemList("/", 0, 29, 30, "xsdB1.xsd", "xmlB1.xml");
String xml = "<!DOCTYPE foo SYSTEM \"./folderB/|\">";
CompletionItem[] items = getCompletionItemList("/", 0, 31, 32, "xsdB1.xsd", "xmlB1.xml");
testCompletionFor(xml, 2, items);
}

@Test
public void testFilePathCompletionDTDFolderBBackSlash() throws BadLocationException {
String xml = "<!DOCTYPE foo SYSTEM \"folderB\\|\">";
CompletionItem[] items = getCompletionItemList("\\", 0, 29, 30, "xsdB1.xsd", "xmlB1.xml");
String xml = "<!DOCTYPE foo SYSTEM \"./folderB\\|\">";
CompletionItem[] items = getCompletionItemList("\\", 0, 31, 32, "xsdB1.xsd", "xmlB1.xml");
testCompletionFor(xml, 2, items);
}

@Test
public void testFilePathNoCompletion() throws BadLocationException {
public void testFilePathCompletionForEmptyDoctype() throws BadLocationException {
String xml = "<!DOCTYPE foo SYSTEM \"|\">";
testCompletionFor(xml, 0);
testCompletionFor(xml, 8);
}

@Test
Expand All @@ -288,8 +282,8 @@ public void testFilePathNoCompletionMissingSystemId() throws BadLocationExceptio

@Test
public void testFilePathCompletionWithSpacesFolder() throws BadLocationException {
String xml = "<a path=\"folderC/|\">";
CompletionItem[] items = getCompletionItemList("/", 0, 16, 17, "a@b", "with%20spaces");
String xml = "<a path=\"./folderC/|\">";
CompletionItem[] items = getCompletionItemList("/", 0, 18, 19, "a@b", "with%20spaces");
testCompletionFor(xml, 2, items);
}

Expand All @@ -301,6 +295,18 @@ public void testFilePathCompletionInsideSpecialChars() throws BadLocationExcepti
XMLAssert.testCompletionFor(xml, null, fileURI, 2, items);
}

@Test
public void testFilePathCompletionWithBrokenAbsoluteWindowsPath() throws BadLocationException {
String xml = "<a path=\"C|\">";
testCompletionFor(xml, 0);
xml = "<a path=\"C:|\">";
testCompletionFor(xml, 0);
xml = "<a path=\"C\\\\|\">";
testCompletionFor(xml, 0);
xml = "<a path=\"C::|\">";
testCompletionFor(xml, 0);
}

private static void testCompletionFor(String xml, CompletionItem... expectedItems) throws BadLocationException {
testCompletionFor(xml, null, expectedItems);
}
Expand Down

0 comments on commit 4f794cf

Please sign in to comment.