Skip to content

Commit

Permalink
File completion in attribute value
Browse files Browse the repository at this point in the history
Need to still handle ~ (home) and get SortTextHelper from XSDCompletion pr

Fixes eclipse-lemminx#345

Signed-off-by: Nikolas Komonen <[email protected]>
  • Loading branch information
NikolasKomonen committed May 30, 2019
1 parent f9d5253 commit 660caa5
Show file tree
Hide file tree
Showing 5 changed files with 288 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.common.io.Closeables;

import org.eclipse.lsp4j.jsonrpc.MessageConsumer;
import org.eclipse.lsp4j.services.LanguageServer;

import com.google.common.io.Closeables;

/**
* Watches the parent process PID and invokes exit if it is no longer available.
* This implementation waits for periods of inactivity to start querying the PIDs.
Expand All @@ -38,7 +38,7 @@ public final class ParentProcessWatcher implements Runnable, Function<MessageCon
*/
private static final int FORCED_EXIT_CODE = 1;

private static final boolean isWindows = System.getProperty("os.name").toLowerCase().indexOf("win") >= 0;
public static final boolean isWindows = System.getProperty("os.name").toLowerCase().indexOf("win") >= 0;

private static final long INACTIVITY_DELAY_SECS = 30 *1000;
private static final int POLL_DELAY_SECS = 10;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*******************************************************************************
* Copyright (c) 2019 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
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/

package org.eclipse.lsp4xml.extensions.general;

import org.eclipse.lsp4j.InitializeParams;
import org.eclipse.lsp4xml.extensions.general.completion.FilePathCompletionParticipant;
import org.eclipse.lsp4xml.services.extensions.IXMLExtension;
import org.eclipse.lsp4xml.services.extensions.XMLExtensionsRegistry;
import org.eclipse.lsp4xml.services.extensions.save.ISaveContext;

/**
* FilePathPlugin
*/
public class FilePathPlugin implements IXMLExtension {

private final FilePathCompletionParticipant completionParticipant;

public FilePathPlugin() {
completionParticipant = new FilePathCompletionParticipant();
}

@Override
public void start(InitializeParams params, XMLExtensionsRegistry registry) {
registry.registerCompletionParticipant(completionParticipant);
}

@Override
public void stop(XMLExtensionsRegistry registry) {
registry.unregisterCompletionParticipant(completionParticipant);
}

@Override
public void doSave(ISaveContext context) {

}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*******************************************************************************
* Copyright (c) 2019 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
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/

package org.eclipse.lsp4xml.extensions.general.completion;

import static org.eclipse.lsp4xml.utils.StringUtils.getNormalizedPath;

import java.io.File;
import java.io.FilenameFilter;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.CompletionItemKind;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextEdit;
import org.eclipse.lsp4xml.dom.DOMDocument;
import org.eclipse.lsp4xml.services.extensions.ICompletionParticipant;
import org.eclipse.lsp4xml.services.extensions.ICompletionRequest;
import org.eclipse.lsp4xml.services.extensions.ICompletionResponse;
import org.eclipse.lsp4xml.settings.SharedSettings;
import org.eclipse.lsp4xml.utils.StringUtils;

/**
* FilePathCompletionParticipant
*/
public class FilePathCompletionParticipant implements ICompletionParticipant {

private static final FilenameFilter xsdFilter = new FilenameFilter() {

@Override
public boolean accept(File dir, String name) {
if(name.matches(".+\\.[^\\s]+$") == false) {
return true;
}
return name.toLowerCase().endsWith(".xsd");
}
};

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

}

@Override
public void onXMLContent(ICompletionRequest request, ICompletionResponse response) throws Exception {

}

@Override
public void onAttributeName(boolean generateValue, Range fullRange, ICompletionRequest request,
ICompletionResponse response, SharedSettings settings) throws Exception {

}

@Override
public void onAttributeValue(String valuePrefix, Range fullRange, boolean addQuotes, ICompletionRequest request,
ICompletionResponse response, SharedSettings settings) throws Exception {

DOMDocument xmlDocument = request.getXMLDocument();
// +- 1 since it includes the quotations
int startOffset = xmlDocument.offsetAt(fullRange.getStart()) + 1;
int endOffset = xmlDocument.offsetAt(fullRange.getEnd()) - 1;
String currentValue = xmlDocument.getText().substring(startOffset, endOffset);

String uriString = xmlDocument.getTextDocument().getUri();
String directoryOfFile = Paths.get(uriString).getParent().toString();
URI uri = URI.create(directoryOfFile);

String scheme = uri.getScheme();
if(!(scheme == null || "file".equals(scheme))) {
return;
}

directoryOfFile = uri.getPath();

Path parentAttributeValuePath = getNormalizedPath(directoryOfFile, currentValue);

File f = new File(parentAttributeValuePath.toString());
if(parentAttributeValuePath == null || f.isFile()) {
return;
}
String slash = StringUtils.getFilePathSlash(currentValue);

//In the case the currently typed file/directory needs to be overwritten
Position replaceStart = null;
Position currentEnd = fullRange.getEnd();
Position replaceEnd = new Position(currentEnd.getLine(), currentEnd.getCharacter() - 1);
int lastSlashIndex = currentValue.lastIndexOf(slash);
if(lastSlashIndex > -1) {
replaceStart = xmlDocument.positionAt(startOffset + lastSlashIndex);
}
Range replaceRange = new Range();
if(replaceStart != null) {
replaceRange.setStart(replaceStart);
}
else {
replaceRange.setStart(replaceEnd);
}
replaceRange.setEnd(replaceEnd);

createNextValidCompletionPaths(parentAttributeValuePath, currentValue, replaceRange, response, xsdFilter);
}

private void createNextValidCompletionPaths(Path pathToAttributeDirectory, String attributePath, Range replaceRange, ICompletionResponse response,
FilenameFilter filter) {

String slash = StringUtils.getFilePathSlash(attributePath);

File[] proposedFiles = gatherFiles(pathToAttributeDirectory, filter);
if (proposedFiles != null) {
for (File child : proposedFiles) {
if (child != null) {
createFilePathCompletionItem(pathToAttributeDirectory, attributePath, child, replaceRange, response, slash);
}
}
}
}

private File[] gatherFiles(Path pathOfDirectory, FilenameFilter filter) {

File f = new File(pathOfDirectory.toString());
if(f.isDirectory()) {
return f.listFiles(filter);
}
return null;
}

private void createFilePathCompletionItem(Path pathOfDirectory, String attributePath, File f, Range replaceRange, ICompletionResponse response, String slash) {
CompletionItem item = new CompletionItem();
String fName = f.getName();
String insertText;
if(f.isDirectory()) {
insertText = slash + fName + slash;
}
else if(f.isFile()) {
insertText = slash + fName;
}
else {
return;
}

item.setLabel(insertText);
item.setKind(f.isFile()? CompletionItemKind.File : CompletionItemKind.Folder);
Sor
item.setSortText(sortText);
item.setFilterText(insertText);
item.setTextEdit(new TextEdit(replaceRange, insertText));
response.addCompletionItem(item);
}





}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
*/
package org.eclipse.lsp4xml.utils;

import static org.eclipse.lsp4xml.commons.ParentProcessWatcher.isWindows;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;

Expand All @@ -24,6 +29,7 @@ public class StringUtils {
public static final String TRUE = "true";
public static final String FALSE = "false";
public static final Collection<String> TRUE_FALSE_ARRAY = Arrays.asList(TRUE, FALSE);
public static String SLASH = isWindows ? "\\" : "/";

private StringUtils() {
}
Expand Down Expand Up @@ -229,4 +235,70 @@ public static String getDefaultString(String text) {
return "";
}

public static Path getNormalizedPath(String parentDirectory, String givenPath) {

Path p;
if(givenPath == null) {
return null;
}
String newPath;
File f;

if(givenPath.startsWith(SLASH)) { //givenPath is already absolute
p = Paths.get(givenPath).normalize();
newPath = p.toString();
f = new File(newPath);
if(f.exists()) {
return p;
}
}
else {
String combinedPath = parentDirectory + SLASH + givenPath;
p = Paths.get(combinedPath).normalize();
newPath = p.toString();
f = new File(newPath);
if(f.exists()) {
return p;
}
}

int lastIndexOfSlash = givenPath.lastIndexOf(SLASH);
if(lastIndexOfSlash != -1) {
//incase the given path is incomplete
givenPath = givenPath.substring(0, lastIndexOfSlash);
}

if(givenPath.startsWith(SLASH)) { //givenPath is already absolute
p = Paths.get(givenPath).normalize();
newPath = p.toString();
f = new File(newPath);
if(f.exists()) {
return p;
}
}
else {
String combinedPath = parentDirectory + SLASH + givenPath;
p = Paths.get(combinedPath).normalize();
newPath = p.toString();
f = new File(newPath);
if(f.exists()) {
return p;
}
}

return null;
}

public static String getFilePathSlash(String text) {
if(text.contains("\\")) {
return "\\";
}
else if(text.contains("/")) {
return "/";
}
else {
return SLASH;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ org.eclipse.lsp4xml.extensions.dtd.DTDPlugin
org.eclipse.lsp4xml.extensions.xsl.XSLPlugin
org.eclipse.lsp4xml.extensions.catalog.XMLCatalogPlugin
org.eclipse.lsp4xml.extensions.xsi.XSISchemaPlugin
org.eclipse.lsp4xml.extensions.prolog.PrologPlugin
org.eclipse.lsp4xml.extensions.prolog.PrologPlugin
org.eclipse.lsp4xml.extensions.general.FilePathPlugin

0 comments on commit 660caa5

Please sign in to comment.