Content assists for application properties
This commit is contained in:
@@ -11,8 +11,22 @@
|
|||||||
package org.springframework.ide.vscode.application.properties.metadata;
|
package org.springframework.ide.vscode.application.properties.metadata;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.springframework.ide.vscode.application.properties.metadata.ValueProviderRegistry.ValueProviderStrategy;
|
import org.springframework.ide.vscode.application.properties.metadata.ValueProviderRegistry.ValueProviderStrategy;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.hints.StsValueHint;
|
||||||
|
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||||
|
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
|
||||||
|
import org.springframework.ide.vscode.commons.util.Log;
|
||||||
|
|
||||||
|
import com.google.common.cache.Cache;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
import reactor.util.function.Tuple2;
|
||||||
|
import reactor.util.function.Tuples;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A abstract {@link ValueProviderStrategy} that is mean to help speedup successive invocations of
|
* A abstract {@link ValueProviderStrategy} that is mean to help speedup successive invocations of
|
||||||
@@ -53,74 +67,79 @@ public abstract class CachingValueProvider implements ValueProviderStrategy {
|
|||||||
*/
|
*/
|
||||||
private int MAX_RESULTS = 500;
|
private int MAX_RESULTS = 500;
|
||||||
|
|
||||||
// private Cache<Tuple2<String,String>, CacheEntry> cache = createCache();
|
private Cache<Tuple2<String,String>, CacheEntry> cache = createCache();
|
||||||
//
|
|
||||||
// private class CacheEntry {
|
private class CacheEntry {
|
||||||
// boolean isComplete = false;
|
boolean isComplete = false;
|
||||||
// int count = 0;
|
int count = 0;
|
||||||
// Flux<StsValueHint> values;
|
Flux<StsValueHint> values;
|
||||||
//
|
|
||||||
// public CacheEntry(String query, Flux<StsValueHint> producer) {
|
public CacheEntry(String query, Flux<StsValueHint> producer) {
|
||||||
// values = producer
|
values = producer
|
||||||
// .take(MAX_RESULTS)
|
.take(MAX_RESULTS)
|
||||||
// .cache(MAX_RESULTS);
|
.cache(MAX_RESULTS);
|
||||||
// values.subscribe(); // create infinite demand so that we actually force cache entries to be fetched upto the max.
|
values.subscribe(); // create infinite demand so that we actually force cache entries to be fetched upto the max.
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @Override
|
@Override
|
||||||
// public String toString() {
|
public String toString() {
|
||||||
// return "CacheEntry [isComplete=" + isComplete + ", count=" + count + "]";
|
return "CacheEntry [isComplete=" + isComplete + ", count=" + count + "]";
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @Override
|
@Override
|
||||||
// public final Flux<StsValueHint> getValues(IJavaProject javaProject, String query) {
|
public final Flux<StsValueHint> getValues(IJavaProject javaProject, String query) {
|
||||||
//// debug("CA query: "+query);
|
Tuple2<String, String> key = key(javaProject, query);
|
||||||
// Tuple2<String, String> key = key(javaProject, query);
|
CacheEntry cached = null;
|
||||||
// CacheEntry cached = cache.get(key);
|
try {
|
||||||
// if (cached==null) {
|
cached = cache.get(key, () -> new CacheEntry(query, getValuesIncremental(javaProject, query)));
|
||||||
// cache.put(key, cached = new CacheEntry(query, getValuesIncremental(javaProject, query)));
|
} catch (ExecutionException e) {
|
||||||
// }
|
Log.log(e);
|
||||||
// return cached.values;
|
}
|
||||||
// }
|
return cached.values;
|
||||||
//
|
}
|
||||||
// /**
|
|
||||||
// * Tries to use an already cached, complete result for a query that is a prefix of the current query to speed things up.
|
/**
|
||||||
// * <p>
|
* Tries to use an already cached, complete result for a query that is a prefix of the current query to speed things up.
|
||||||
// * Falls back on doing a full-blown search if there's no usable 'prefix-query' in the cache.
|
* <p>
|
||||||
// */
|
* Falls back on doing a full-blown search if there's no usable 'prefix-query' in the cache.
|
||||||
// private Flux<StsValueHint> getValuesIncremental(IJavaProject javaProject, String query) {
|
*/
|
||||||
//// debug("trying to solve "+query+" incrementally");
|
private Flux<StsValueHint> getValuesIncremental(IJavaProject javaProject, String query) {
|
||||||
// String subquery = query;
|
// debug("trying to solve "+query+" incrementally");
|
||||||
// while (subquery.length()>=1) {
|
String subquery = query;
|
||||||
// subquery = subquery.substring(0, subquery.length()-1);
|
while (subquery.length()>=1) {
|
||||||
// CacheEntry cached = cache.get(key(javaProject, subquery));
|
subquery = subquery.substring(0, subquery.length()-1);
|
||||||
// if (cached!=null) {
|
CacheEntry cached = null;
|
||||||
// System.out.println("cached "+subquery+": "+cached);
|
try {
|
||||||
// if (cached.isComplete) {
|
cached = cache.get(key(javaProject, subquery), () -> null);
|
||||||
//// debug("filtering "+subquery+" -> "+query);
|
} catch (ExecutionException | InvalidCacheLoadException e) {
|
||||||
// return cached.values
|
// Log.log(e);
|
||||||
//// .doOnNext((hint) -> debug("filter["+query+"]: "+hint.getValue()))
|
}
|
||||||
// .filter((hint) -> 0!=FuzzyMatcher.matchScore(query, hint.getValue().toString()));
|
if (cached!=null) {
|
||||||
// } else {
|
System.out.println("cached "+subquery+": "+cached);
|
||||||
//// debug("subquery "+subquery+" cached but is incomplete");
|
if (cached.isComplete) {
|
||||||
// }
|
return cached.values
|
||||||
// }
|
// .doOnNext((hint) -> debug("filter["+query+"]: "+hint.getValue()))
|
||||||
// }
|
.filter((hint) -> 0!=FuzzyMatcher.matchScore(query, hint.getValue().toString()));
|
||||||
//// debug("full search for: "+query);
|
} else {
|
||||||
// return getValuesAsycn(javaProject, query);
|
// debug("subquery "+subquery+" cached but is incomplete");
|
||||||
// }
|
}
|
||||||
//
|
}
|
||||||
// protected abstract Flux<StsValueHint> getValuesAsycn(IJavaProject javaProject, String query);
|
}
|
||||||
//
|
// debug("full search for: "+query);
|
||||||
// private Tuple2<String,String> key(IJavaProject javaProject, String query) {
|
return getValuesAsycn(javaProject, query);
|
||||||
// return Tuples.of(javaProject==null?null:javaProject.getElementName(), query);
|
}
|
||||||
// }
|
|
||||||
//
|
protected abstract Flux<StsValueHint> getValuesAsycn(IJavaProject javaProject, String query);
|
||||||
// protected <K,V> Cache<K,V> createCache() {
|
|
||||||
// return new LimitedTimeCache<>(Duration.ofMinutes(1));
|
private Tuple2<String,String> key(IJavaProject javaProject, String query) {
|
||||||
// }
|
return Tuples.of(javaProject==null?null:javaProject.getElementName(), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <K,V> Cache<K,V> createCache() {
|
||||||
|
return CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build();
|
||||||
|
}
|
||||||
|
|
||||||
public static void restoreDefaults() {
|
public static void restoreDefaults() {
|
||||||
TIMEOUT = DEFAULT_TIMEOUT;
|
TIMEOUT = DEFAULT_TIMEOUT;
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package org.springframework.ide.vscode.application.properties.metadata;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.ValueProviderRegistry.ValueProviderStrategy;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.hints.StsValueHint;
|
||||||
|
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kris De Volder
|
||||||
|
*/
|
||||||
|
public class ResourceHintProvider implements ValueProviderStrategy {
|
||||||
|
|
||||||
|
private static String[] CLASSPATH_PREFIXES = {
|
||||||
|
"classpath:",
|
||||||
|
"classpath*:"
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final String[] URL_PREFIXES = new String[] {
|
||||||
|
"classpath:",
|
||||||
|
"classpath*:",
|
||||||
|
"file:",
|
||||||
|
"http://",
|
||||||
|
"https://"
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Flux<StsValueHint> getValues(IJavaProject javaProject, String query) {
|
||||||
|
for (String prefix : CLASSPATH_PREFIXES) {
|
||||||
|
if (query.startsWith(prefix)) {
|
||||||
|
return classpathHints
|
||||||
|
.getValues(javaProject, query.substring(prefix.length()))
|
||||||
|
.map((hint) -> hint.prefixWith(prefix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Flux.fromIterable(urlPrefixHints);
|
||||||
|
}
|
||||||
|
|
||||||
|
final private ImmutableList<StsValueHint> urlPrefixHints = ImmutableList.copyOf(
|
||||||
|
Arrays.stream(URL_PREFIXES)
|
||||||
|
.map(StsValueHint::create)
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
);
|
||||||
|
|
||||||
|
private ClasspathHints classpathHints = new ClasspathHints();
|
||||||
|
|
||||||
|
private static class ClasspathHints extends CachingValueProvider {
|
||||||
|
@Override
|
||||||
|
protected Flux<StsValueHint> getValuesAsycn(IJavaProject javaProject, String query) {
|
||||||
|
return Flux.fromStream(javaProject.getClasspath().getClasspathResources().distinct().map(StsValueHint::create));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -97,6 +97,11 @@ public class PropertyCompletionFactory {
|
|||||||
return typeUtil.niceTypeName((Type) type);
|
return typeUtil.niceTypeName((Type) type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLabel() {
|
||||||
|
return getBaseDisplayString() + " : " + typeUtil.niceTypeName(getType());
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
if (property.isDeprecated()) {
|
if (property.isDeprecated()) {
|
||||||
proposal.deprecate();
|
proposal.deprecate();
|
||||||
@@ -157,6 +162,12 @@ public class PropertyCompletionFactory {
|
|||||||
protected String niceTypeName(YType type) {
|
protected String niceTypeName(YType type) {
|
||||||
return typeUtil.niceTypeName(((Type)type));
|
return typeUtil.niceTypeName(((Type)type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLabel() {
|
||||||
|
return getBaseDisplayString() + " : " + typeUtil.niceTypeName(getType());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.util.stream.Stream;
|
|||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
|
|
||||||
import org.springframework.boot.configurationmetadata.Deprecation;
|
import org.springframework.boot.configurationmetadata.Deprecation;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.ResourceHintProvider;
|
||||||
import org.springframework.ide.vscode.application.properties.metadata.ValueProviderRegistry.ValueProviderStrategy;
|
import org.springframework.ide.vscode.application.properties.metadata.ValueProviderRegistry.ValueProviderStrategy;
|
||||||
import org.springframework.ide.vscode.application.properties.metadata.hints.StsValueHint;
|
import org.springframework.ide.vscode.application.properties.metadata.hints.StsValueHint;
|
||||||
import org.springframework.ide.vscode.application.properties.metadata.util.DeprecationUtil;
|
import org.springframework.ide.vscode.application.properties.metadata.util.DeprecationUtil;
|
||||||
@@ -577,7 +578,7 @@ public class TypeUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// valueHints("org.springframework.core.io.Resource", new ResourceHintProvider());
|
valueHints("org.springframework.core.io.Resource", new ResourceHintProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -90,6 +90,12 @@ public class PropertiesMetadataTestData {
|
|||||||
public Stream<Path> getClasspathEntries() throws Exception {
|
public Stream<Path> getClasspathEntries() throws Exception {
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> getClasspathResources() {
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
for (ConfigurationMetadataProperty propertyInfo : datas.values()) {
|
for (ConfigurationMetadataProperty propertyInfo : datas.values()) {
|
||||||
index.add(propertyInfo);
|
index.add(propertyInfo);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import org.jboss.jandex.MethodInfo;
|
|||||||
import org.jboss.jandex.PrimitiveType;
|
import org.jboss.jandex.PrimitiveType;
|
||||||
import org.jboss.jandex.Type;
|
import org.jboss.jandex.Type;
|
||||||
import org.jboss.jandex.Type.Kind;
|
import org.jboss.jandex.Type.Kind;
|
||||||
|
import org.springframework.ide.vscode.commons.java.Flags;
|
||||||
import org.springframework.ide.vscode.commons.java.IAnnotation;
|
import org.springframework.ide.vscode.commons.java.IAnnotation;
|
||||||
import org.springframework.ide.vscode.commons.java.IField;
|
import org.springframework.ide.vscode.commons.java.IField;
|
||||||
import org.springframework.ide.vscode.commons.java.IJavaType;
|
import org.springframework.ide.vscode.commons.java.IJavaType;
|
||||||
@@ -28,8 +29,6 @@ import org.springframework.ide.vscode.commons.util.HtmlSnippet;
|
|||||||
|
|
||||||
public class Wrappers {
|
public class Wrappers {
|
||||||
|
|
||||||
private static final int AccEnum = 0x4000;
|
|
||||||
|
|
||||||
public static IType wrap(IndexView index, ClassInfo info) {
|
public static IType wrap(IndexView index, ClassInfo info) {
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -75,7 +74,7 @@ public class Wrappers {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnum() {
|
public boolean isEnum() {
|
||||||
return (info.flags() & AccEnum) != 0;
|
return Flags.isEnum(info.flags());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -161,7 +160,7 @@ public class Wrappers {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnumConstant() {
|
public boolean isEnumConstant() {
|
||||||
return (field.flags() & AccEnum) != 0;
|
return Flags.isEnum(field.flags());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -30,4 +30,10 @@ public interface IClasspath {
|
|||||||
*/
|
*/
|
||||||
Stream<Path> getClasspathEntries() throws Exception;
|
Stream<Path> getClasspathEntries() throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classpath resources paths relative to the source folder path
|
||||||
|
* @return classpath resource relative paths
|
||||||
|
*/
|
||||||
|
Stream<String> getClasspathResources();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
package org.springframework.ide.vscode.application.yaml.completions;
|
package org.springframework.ide.vscode.commons.languageserver.completion;
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
|
||||||
import org.springframework.ide.vscode.commons.util.Log;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Temprary placeholder which sort of replaces the LazyProposalApplier from old STS.
|
* Temprary placeholder which sort of replaces the LazyProposalApplier from old STS.
|
||||||
* It really does nothing right now. Somehow this should be tied into LS protocol so
|
* It really does nothing right now. Somehow this should be tied into LS protocol so
|
||||||
@@ -13,7 +10,7 @@ import org.springframework.ide.vscode.commons.util.Log;
|
|||||||
* Right now this is not lazy at all and the completion edits are just computed immediatly.
|
* Right now this is not lazy at all and the completion edits are just computed immediatly.
|
||||||
*/
|
*/
|
||||||
public class LazyProposalApplier {
|
public class LazyProposalApplier {
|
||||||
|
|
||||||
public static DocumentEdits from(Callable<DocumentEdits> createEdits) throws Exception {
|
public static DocumentEdits from(Callable<DocumentEdits> createEdits) throws Exception {
|
||||||
return createEdits.call();
|
return createEdits.call();
|
||||||
}
|
}
|
||||||
@@ -27,6 +27,8 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
|
|||||||
|
|
||||||
private final static int MAX_COMPLETIONS = 20;
|
private final static int MAX_COMPLETIONS = 20;
|
||||||
|
|
||||||
|
private int maxCompletions = MAX_COMPLETIONS;
|
||||||
|
|
||||||
final static Logger logger = LoggerFactory.getLogger(VscodeCompletionEngineAdapter.class);
|
final static Logger logger = LoggerFactory.getLogger(VscodeCompletionEngineAdapter.class);
|
||||||
|
|
||||||
public static final String VS_CODE_CURSOR_MARKER = "{{}}";
|
public static final String VS_CODE_CURSOR_MARKER = "{{}}";
|
||||||
@@ -39,6 +41,10 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
|
|||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMaxCompletionsNumber(int maxCompletions) {
|
||||||
|
this.maxCompletions = maxCompletions;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<CompletionList> getCompletions(TextDocumentPositionParams params) {
|
public CompletableFuture<CompletionList> getCompletions(TextDocumentPositionParams params) {
|
||||||
//TODO: This returns a CompletableFuture which suggests we should try to do expensive work asyncly.
|
//TODO: This returns a CompletableFuture which suggests we should try to do expensive work asyncly.
|
||||||
@@ -58,7 +64,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
for (ICompletionProposal c : completions) {
|
for (ICompletionProposal c : completions) {
|
||||||
count++;
|
count++;
|
||||||
if (count>MAX_COMPLETIONS) {
|
if (maxCompletions > 0 && count>maxCompletions) {
|
||||||
list.setIsIncomplete(true);
|
list.setIsIncomplete(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,11 @@ package org.springframework.ide.vscode.commons.maven.java;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.apache.maven.project.MavenProject;
|
import org.apache.maven.project.MavenProject;
|
||||||
|
import org.codehaus.plexus.util.DirectoryScanner;
|
||||||
import org.springframework.ide.vscode.commons.jandex.JandexIndex;
|
import org.springframework.ide.vscode.commons.jandex.JandexIndex;
|
||||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||||
import org.springframework.ide.vscode.commons.java.IType;
|
import org.springframework.ide.vscode.commons.java.IType;
|
||||||
@@ -70,5 +72,22 @@ public class MavenProjectClasspath implements IClasspath {
|
|||||||
private File findIndexFile(File jarFile) {
|
private File findIndexFile(File jarFile) {
|
||||||
return new File(maven.getIndexFolder().toString(), jarFile.getName() + "-" + jarFile.lastModified() + ".jdx");
|
return new File(maven.getIndexFolder().toString(), jarFile.getName() + "-" + jarFile.lastModified() + ".jdx");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> getClasspathResources() {
|
||||||
|
return project.getBuild().getResources().stream().flatMap(resource -> {
|
||||||
|
DirectoryScanner scanner = new DirectoryScanner();
|
||||||
|
scanner.setBasedir(resource.getDirectory());
|
||||||
|
if (resource.getIncludes() != null && !resource.getIncludes().isEmpty()) {
|
||||||
|
scanner.setIncludes(resource.getIncludes().toArray(new String[resource.getIncludes().size()]));
|
||||||
|
}
|
||||||
|
if (resource.getExcludes() != null && !resource.getExcludes().isEmpty()) {
|
||||||
|
scanner.setExcludes(resource.getExcludes().toArray(new String[resource.getExcludes().size()]));
|
||||||
|
}
|
||||||
|
scanner.setCaseSensitive(false);
|
||||||
|
scanner.scan();
|
||||||
|
return Arrays.stream(scanner.getIncludedFiles());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,4 +37,9 @@ public class FileClasspath implements IClasspath {
|
|||||||
classpathFilePath.getParent().resolve("target/test-classes")));
|
classpathFilePath.getParent().resolve("target/test-classes")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> getClasspathResources() {
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ keyChar
|
|||||||
;
|
;
|
||||||
|
|
||||||
separatorAndValue
|
separatorAndValue
|
||||||
: (Space | Colon | Equals) valueChar+
|
: (Space | Colon | Equals) valueChar*
|
||||||
;
|
;
|
||||||
|
|
||||||
valueChar
|
valueChar
|
||||||
|
|||||||
@@ -12,10 +12,12 @@ package org.springframework.ide.vscode.java.properties.antlr.parser;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.antlr.v4.runtime.ANTLRErrorListener;
|
import org.antlr.v4.runtime.ANTLRErrorListener;
|
||||||
import org.antlr.v4.runtime.ANTLRInputStream;
|
import org.antlr.v4.runtime.ANTLRInputStream;
|
||||||
import org.antlr.v4.runtime.CommonTokenStream;
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
|
import org.antlr.v4.runtime.ConsoleErrorListener;
|
||||||
import org.antlr.v4.runtime.ParserRuleContext;
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
import org.antlr.v4.runtime.RecognitionException;
|
import org.antlr.v4.runtime.RecognitionException;
|
||||||
import org.antlr.v4.runtime.Recognizer;
|
import org.antlr.v4.runtime.Recognizer;
|
||||||
@@ -23,6 +25,7 @@ import org.antlr.v4.runtime.Token;
|
|||||||
import org.antlr.v4.runtime.atn.ATNConfigSet;
|
import org.antlr.v4.runtime.atn.ATNConfigSet;
|
||||||
import org.antlr.v4.runtime.dfa.DFA;
|
import org.antlr.v4.runtime.dfa.DFA;
|
||||||
import org.springframework.ide.vscode.java.properties.antlr.parser.JavaPropertiesParser.CommentLineContext;
|
import org.springframework.ide.vscode.java.properties.antlr.parser.JavaPropertiesParser.CommentLineContext;
|
||||||
|
import org.springframework.ide.vscode.java.properties.antlr.parser.JavaPropertiesParser.EmptyLineContext;
|
||||||
import org.springframework.ide.vscode.java.properties.antlr.parser.JavaPropertiesParser.KeyContext;
|
import org.springframework.ide.vscode.java.properties.antlr.parser.JavaPropertiesParser.KeyContext;
|
||||||
import org.springframework.ide.vscode.java.properties.antlr.parser.JavaPropertiesParser.PropertyLineContext;
|
import org.springframework.ide.vscode.java.properties.antlr.parser.JavaPropertiesParser.PropertyLineContext;
|
||||||
import org.springframework.ide.vscode.java.properties.antlr.parser.JavaPropertiesParser.SeparatorAndValueContext;
|
import org.springframework.ide.vscode.java.properties.antlr.parser.JavaPropertiesParser.SeparatorAndValueContext;
|
||||||
@@ -53,6 +56,9 @@ public class AntlrParser implements Parser {
|
|||||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||||
JavaPropertiesParser parser = new JavaPropertiesParser(tokens);
|
JavaPropertiesParser parser = new JavaPropertiesParser(tokens);
|
||||||
|
|
||||||
|
// To avoid printing parse errors in the console
|
||||||
|
parser.removeErrorListener(ConsoleErrorListener.INSTANCE);
|
||||||
|
|
||||||
// Add listener to collect various parser errors
|
// Add listener to collect various parser errors
|
||||||
parser.addErrorListener(new ANTLRErrorListener() {
|
parser.addErrorListener(new ANTLRErrorListener() {
|
||||||
|
|
||||||
@@ -90,7 +96,9 @@ public class AntlrParser implements Parser {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exitPropertyLine(PropertyLineContext ctx) {
|
public void exitPropertyLine(PropertyLineContext ctx) {
|
||||||
astNodes.add(new KeyValuePair(ctx, key, value));
|
KeyValuePair pair = new KeyValuePair(ctx, key, value);
|
||||||
|
key.parent = value.parent = pair;
|
||||||
|
astNodes.add(pair);
|
||||||
key = null;
|
key = null;
|
||||||
value = null;
|
value = null;
|
||||||
}
|
}
|
||||||
@@ -110,8 +118,13 @@ public class AntlrParser implements Parser {
|
|||||||
value = new Value(ctx);
|
value = new Value(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exitEmptyLine(EmptyLineContext ctx) {
|
||||||
|
astNodes.add(new EmptyLine(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
parser.parse();
|
parser.parse();
|
||||||
|
|
||||||
// Collect and return parse results
|
// Collect and return parse results
|
||||||
@@ -156,6 +169,9 @@ public class AntlrParser implements Parser {
|
|||||||
|
|
||||||
private static abstract class Node implements PropertiesAst.Node {
|
private static abstract class Node implements PropertiesAst.Node {
|
||||||
|
|
||||||
|
Node parent;
|
||||||
|
List<Node> children;
|
||||||
|
|
||||||
abstract protected ParserRuleContext getContext();
|
abstract protected ParserRuleContext getContext();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -167,14 +183,40 @@ public class AntlrParser implements Parser {
|
|||||||
public int getLength() {
|
public int getLength() {
|
||||||
return getContext().getStop().getStartIndex() - getOffset() + 1;
|
return getContext().getStop().getStartIndex() - getOffset() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Node> getChildren() {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Comment implements PropertiesAst.Comment {
|
private static class EmptyLine extends Node implements PropertiesAst.EmptyLine {
|
||||||
|
|
||||||
|
private EmptyLineContext context;
|
||||||
|
|
||||||
|
public EmptyLine(EmptyLineContext context) {
|
||||||
|
super();
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected EmptyLineContext getContext() {
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Comment extends Node implements PropertiesAst.Comment {
|
||||||
|
|
||||||
private CommentLineContext context;
|
private CommentLineContext context;
|
||||||
|
|
||||||
public Comment(CommentLineContext context) {
|
public Comment(CommentLineContext context) {
|
||||||
|
super();
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,6 +232,11 @@ public class AntlrParser implements Parser {
|
|||||||
public int getLength() {
|
public int getLength() {
|
||||||
return context.getStop().getStartIndex() - getOffset() + 1;
|
return context.getStop().getStartIndex() - getOffset() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CommentLineContext getContext() {
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,9 +247,11 @@ public class AntlrParser implements Parser {
|
|||||||
private Value value;
|
private Value value;
|
||||||
|
|
||||||
public KeyValuePair(PropertyLineContext context, Key key, Value value) {
|
public KeyValuePair(PropertyLineContext context, Key key, Value value) {
|
||||||
|
super();
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
this.children = ImmutableList.of(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PropertyLineContext getContext() {
|
protected PropertyLineContext getContext() {
|
||||||
@@ -218,6 +267,18 @@ public class AntlrParser implements Parser {
|
|||||||
public Value getValue() {
|
public Value getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLength() {
|
||||||
|
// Exclude the line break at the end
|
||||||
|
int length = super.getLength();
|
||||||
|
String text = getContext().getText();
|
||||||
|
if (text.charAt(getContext().getStop().getStartIndex() - getOffset()) == '\n') {
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Key extends Node implements PropertiesAst.Key {
|
private static class Key extends Node implements PropertiesAst.Key {
|
||||||
@@ -241,6 +302,11 @@ public class AntlrParser implements Parser {
|
|||||||
return context.getText().replace("\\:", ":").replace("\\=", "=");
|
return context.getText().replace("\\:", ":").replace("\\=", "=");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeyValuePair getParent() {
|
||||||
|
return (KeyValuePair) super.getParent();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,9 +323,9 @@ public class AntlrParser implements Parser {
|
|||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
// Remove the separator, if it exists
|
// Remove the separator, if it exists
|
||||||
value = context.getText().replaceAll("^\\s*[:=]?\\s*", "");
|
value = context.getText().replaceAll("^\\s*[:=]?", "");
|
||||||
// Remove all escaped line breaks with trailing spaces
|
// Remove all escaped line breaks with trailing spaces
|
||||||
decoded = value.replaceAll("\\\\(\r?\n|\r)[ \t\f]*", "");
|
decoded = value.replaceAll("^\\s*", "").replaceAll("\\\\(\r?\n|\r)[ \t\f]*", "");
|
||||||
try {
|
try {
|
||||||
decoded = PropertiesFileEscapes.unescape(decoded);
|
decoded = PropertiesFileEscapes.unescape(decoded);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -283,6 +349,10 @@ public class AntlrParser implements Parser {
|
|||||||
return context.getStart().getStartIndex() + (context.getText().length() - value.length());
|
return context.getStart().getStartIndex() + (context.getText().length() - value.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeyValuePair getParent() {
|
||||||
|
return (KeyValuePair) super.getParent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -623,20 +623,20 @@ public class JavaPropertiesParser extends Parser {
|
|||||||
} else {
|
} else {
|
||||||
consume();
|
consume();
|
||||||
}
|
}
|
||||||
setState(80);
|
setState(82);
|
||||||
_errHandler.sync(this);
|
_errHandler.sync(this);
|
||||||
_la = _input.LA(1);
|
_la = _input.LA(1);
|
||||||
do {
|
while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << Backslash) | (1L << Colon) | (1L << Equals) | (1L << Exclamation) | (1L << Number) | (1L << Space) | (1L << IdentifierChar))) != 0)) {
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
setState(79);
|
setState(79);
|
||||||
valueChar();
|
valueChar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setState(82);
|
setState(84);
|
||||||
_errHandler.sync(this);
|
_errHandler.sync(this);
|
||||||
_la = _input.LA(1);
|
_la = _input.LA(1);
|
||||||
} while ( (((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << Backslash) | (1L << Colon) | (1L << Equals) | (1L << Exclamation) | (1L << Number) | (1L << Space) | (1L << IdentifierChar))) != 0) );
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (RecognitionException re) {
|
catch (RecognitionException re) {
|
||||||
@@ -677,56 +677,56 @@ public class JavaPropertiesParser extends Parser {
|
|||||||
ValueCharContext _localctx = new ValueCharContext(_ctx, getState());
|
ValueCharContext _localctx = new ValueCharContext(_ctx, getState());
|
||||||
enterRule(_localctx, 18, RULE_valueChar);
|
enterRule(_localctx, 18, RULE_valueChar);
|
||||||
try {
|
try {
|
||||||
setState(92);
|
setState(93);
|
||||||
switch (_input.LA(1)) {
|
switch (_input.LA(1)) {
|
||||||
case IdentifierChar:
|
case IdentifierChar:
|
||||||
enterOuterAlt(_localctx, 1);
|
enterOuterAlt(_localctx, 1);
|
||||||
{
|
{
|
||||||
setState(84);
|
setState(85);
|
||||||
match(IdentifierChar);
|
match(IdentifierChar);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Exclamation:
|
case Exclamation:
|
||||||
enterOuterAlt(_localctx, 2);
|
enterOuterAlt(_localctx, 2);
|
||||||
{
|
{
|
||||||
setState(85);
|
setState(86);
|
||||||
match(Exclamation);
|
match(Exclamation);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Number:
|
case Number:
|
||||||
enterOuterAlt(_localctx, 3);
|
enterOuterAlt(_localctx, 3);
|
||||||
{
|
{
|
||||||
setState(86);
|
setState(87);
|
||||||
match(Number);
|
match(Number);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Space:
|
case Space:
|
||||||
enterOuterAlt(_localctx, 4);
|
enterOuterAlt(_localctx, 4);
|
||||||
{
|
{
|
||||||
setState(87);
|
setState(88);
|
||||||
match(Space);
|
match(Space);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Backslash:
|
case Backslash:
|
||||||
enterOuterAlt(_localctx, 5);
|
enterOuterAlt(_localctx, 5);
|
||||||
{
|
{
|
||||||
setState(88);
|
|
||||||
match(Backslash);
|
|
||||||
setState(89);
|
setState(89);
|
||||||
|
match(Backslash);
|
||||||
|
setState(90);
|
||||||
match(LineBreak);
|
match(LineBreak);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Equals:
|
case Equals:
|
||||||
enterOuterAlt(_localctx, 6);
|
enterOuterAlt(_localctx, 6);
|
||||||
{
|
{
|
||||||
setState(90);
|
setState(91);
|
||||||
match(Equals);
|
match(Equals);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Colon:
|
case Colon:
|
||||||
enterOuterAlt(_localctx, 7);
|
enterOuterAlt(_localctx, 7);
|
||||||
{
|
{
|
||||||
setState(91);
|
setState(92);
|
||||||
match(Colon);
|
match(Colon);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -746,31 +746,31 @@ public class JavaPropertiesParser extends Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static final String _serializedATN =
|
public static final String _serializedATN =
|
||||||
"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3\na\4\2\t\2\4\3\t"+
|
"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3\nb\4\2\t\2\4\3\t"+
|
||||||
"\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\3"+
|
"\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\3"+
|
||||||
"\2\7\2\30\n\2\f\2\16\2\33\13\2\3\2\3\2\3\3\3\3\3\3\5\3\"\n\3\3\4\7\4%"+
|
"\2\7\2\30\n\2\f\2\16\2\33\13\2\3\2\3\2\3\3\3\3\3\3\5\3\"\n\3\3\4\7\4%"+
|
||||||
"\n\4\f\4\16\4(\13\4\3\4\3\4\3\5\7\5-\n\5\f\5\16\5\60\13\5\3\5\3\5\7\5"+
|
"\n\4\f\4\16\4(\13\4\3\4\3\4\3\5\7\5-\n\5\f\5\16\5\60\13\5\3\5\3\5\7\5"+
|
||||||
"\64\n\5\f\5\16\5\67\13\5\3\5\3\5\3\6\7\6<\n\6\f\6\16\6?\13\6\3\6\3\6\3"+
|
"\64\n\5\f\5\16\5\67\13\5\3\5\3\5\3\6\7\6<\n\6\f\6\16\6?\13\6\3\6\3\6\3"+
|
||||||
"\7\3\7\3\7\3\7\3\b\6\bH\n\b\r\b\16\bI\3\t\3\t\3\t\5\tO\n\t\3\n\3\n\6\n"+
|
"\7\3\7\3\7\3\7\3\b\6\bH\n\b\r\b\16\bI\3\t\3\t\3\t\5\tO\n\t\3\n\3\n\7\n"+
|
||||||
"S\n\n\r\n\16\nT\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\5\13_\n\13\3\13"+
|
"S\n\n\f\n\16\nV\13\n\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\5\13`\n\13"+
|
||||||
"\2\2\f\2\4\6\b\n\f\16\20\22\24\2\7\3\2\6\7\3\2\b\b\3\3\b\b\3\2\4\5\4\2"+
|
"\3\13\2\2\f\2\4\6\b\n\f\16\20\22\24\2\7\3\2\6\7\3\2\b\b\3\3\b\b\3\2\4"+
|
||||||
"\4\5\t\tf\2\31\3\2\2\2\4!\3\2\2\2\6&\3\2\2\2\b.\3\2\2\2\n=\3\2\2\2\fB"+
|
"\5\4\2\4\5\t\tg\2\31\3\2\2\2\4!\3\2\2\2\6&\3\2\2\2\b.\3\2\2\2\n=\3\2\2"+
|
||||||
"\3\2\2\2\16G\3\2\2\2\20N\3\2\2\2\22P\3\2\2\2\24^\3\2\2\2\26\30\5\4\3\2"+
|
"\2\fB\3\2\2\2\16G\3\2\2\2\20N\3\2\2\2\22P\3\2\2\2\24_\3\2\2\2\26\30\5"+
|
||||||
"\27\26\3\2\2\2\30\33\3\2\2\2\31\27\3\2\2\2\31\32\3\2\2\2\32\34\3\2\2\2"+
|
"\4\3\2\27\26\3\2\2\2\30\33\3\2\2\2\31\27\3\2\2\2\31\32\3\2\2\2\32\34\3"+
|
||||||
"\33\31\3\2\2\2\34\35\7\2\2\3\35\3\3\2\2\2\36\"\5\6\4\2\37\"\5\b\5\2 \""+
|
"\2\2\2\33\31\3\2\2\2\34\35\7\2\2\3\35\3\3\2\2\2\36\"\5\6\4\2\37\"\5\b"+
|
||||||
"\5\n\6\2!\36\3\2\2\2!\37\3\2\2\2! \3\2\2\2\"\5\3\2\2\2#%\7\t\2\2$#\3\2"+
|
"\5\2 \"\5\n\6\2!\36\3\2\2\2!\37\3\2\2\2! \3\2\2\2\"\5\3\2\2\2#%\7\t\2"+
|
||||||
"\2\2%(\3\2\2\2&$\3\2\2\2&\'\3\2\2\2\')\3\2\2\2(&\3\2\2\2)*\5\f\7\2*\7"+
|
"\2$#\3\2\2\2%(\3\2\2\2&$\3\2\2\2&\'\3\2\2\2\')\3\2\2\2(&\3\2\2\2)*\5\f"+
|
||||||
"\3\2\2\2+-\7\t\2\2,+\3\2\2\2-\60\3\2\2\2.,\3\2\2\2./\3\2\2\2/\61\3\2\2"+
|
"\7\2*\7\3\2\2\2+-\7\t\2\2,+\3\2\2\2-\60\3\2\2\2.,\3\2\2\2./\3\2\2\2/\61"+
|
||||||
"\2\60.\3\2\2\2\61\65\t\2\2\2\62\64\n\3\2\2\63\62\3\2\2\2\64\67\3\2\2\2"+
|
"\3\2\2\2\60.\3\2\2\2\61\65\t\2\2\2\62\64\n\3\2\2\63\62\3\2\2\2\64\67\3"+
|
||||||
"\65\63\3\2\2\2\65\66\3\2\2\2\668\3\2\2\2\67\65\3\2\2\289\t\4\2\29\t\3"+
|
"\2\2\2\65\63\3\2\2\2\65\66\3\2\2\2\668\3\2\2\2\67\65\3\2\2\289\t\4\2\2"+
|
||||||
"\2\2\2:<\7\t\2\2;:\3\2\2\2<?\3\2\2\2=;\3\2\2\2=>\3\2\2\2>@\3\2\2\2?=\3"+
|
"9\t\3\2\2\2:<\7\t\2\2;:\3\2\2\2<?\3\2\2\2=;\3\2\2\2=>\3\2\2\2>@\3\2\2"+
|
||||||
"\2\2\2@A\7\b\2\2A\13\3\2\2\2BC\5\16\b\2CD\5\22\n\2DE\t\4\2\2E\r\3\2\2"+
|
"\2?=\3\2\2\2@A\7\b\2\2A\13\3\2\2\2BC\5\16\b\2CD\5\22\n\2DE\t\4\2\2E\r"+
|
||||||
"\2FH\5\20\t\2GF\3\2\2\2HI\3\2\2\2IG\3\2\2\2IJ\3\2\2\2J\17\3\2\2\2KO\7"+
|
"\3\2\2\2FH\5\20\t\2GF\3\2\2\2HI\3\2\2\2IG\3\2\2\2IJ\3\2\2\2J\17\3\2\2"+
|
||||||
"\n\2\2LM\7\3\2\2MO\t\5\2\2NK\3\2\2\2NL\3\2\2\2O\21\3\2\2\2PR\t\6\2\2Q"+
|
"\2KO\7\n\2\2LM\7\3\2\2MO\t\5\2\2NK\3\2\2\2NL\3\2\2\2O\21\3\2\2\2PT\t\6"+
|
||||||
"S\5\24\13\2RQ\3\2\2\2ST\3\2\2\2TR\3\2\2\2TU\3\2\2\2U\23\3\2\2\2V_\7\n"+
|
"\2\2QS\5\24\13\2RQ\3\2\2\2SV\3\2\2\2TR\3\2\2\2TU\3\2\2\2U\23\3\2\2\2V"+
|
||||||
"\2\2W_\7\6\2\2X_\7\7\2\2Y_\7\t\2\2Z[\7\3\2\2[_\7\b\2\2\\_\7\5\2\2]_\7"+
|
"T\3\2\2\2W`\7\n\2\2X`\7\6\2\2Y`\7\7\2\2Z`\7\t\2\2[\\\7\3\2\2\\`\7\b\2"+
|
||||||
"\4\2\2^V\3\2\2\2^W\3\2\2\2^X\3\2\2\2^Y\3\2\2\2^Z\3\2\2\2^\\\3\2\2\2^]"+
|
"\2]`\7\5\2\2^`\7\4\2\2_W\3\2\2\2_X\3\2\2\2_Y\3\2\2\2_Z\3\2\2\2_[\3\2\2"+
|
||||||
"\3\2\2\2_\25\3\2\2\2\f\31!&.\65=INT^";
|
"\2_]\3\2\2\2_^\3\2\2\2`\25\3\2\2\2\f\31!&.\65=INT_";
|
||||||
public static final ATN _ATN =
|
public static final ATN _ATN =
|
||||||
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
|
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
|
||||||
static {
|
static {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public final class PropertiesAst {
|
|||||||
* Retrieves all AST nodes
|
* Retrieves all AST nodes
|
||||||
* @return List of AST nodes sorted by line number
|
* @return List of AST nodes sorted by line number
|
||||||
*/
|
*/
|
||||||
public List<? extends Node> getAllNodes() {
|
public List<Node> getAllNodes() {
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,6 +48,52 @@ public final class PropertiesAst {
|
|||||||
return (List<T>) l;
|
return (List<T>) l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find node in AST corresponding to offset position
|
||||||
|
* @param offset Position in the text
|
||||||
|
* @return AST node corresponding to the offset position
|
||||||
|
*/
|
||||||
|
public Node findNode(int offset) {
|
||||||
|
return findNode(nodes, offset, 0, nodes.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node findNode(List<? extends Node> nodes, int offset, int start, int end) {
|
||||||
|
if (nodes == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (start == end) {
|
||||||
|
Node node = nodes.get(start);
|
||||||
|
if (node.getOffset() <= offset && offset <= node.getOffset() + node.getLength()) {
|
||||||
|
Node found = findChildNode(node, offset);
|
||||||
|
return found == null ? node : found;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else if (start < end ) {
|
||||||
|
int pivotIndex = (start + end) / 2;
|
||||||
|
Node node = nodes.get(pivotIndex);
|
||||||
|
if (node.getOffset() > offset) {
|
||||||
|
return findNode(nodes, offset, start, pivotIndex - 1);
|
||||||
|
} else if (offset > node.getOffset() + node.getLength()) {
|
||||||
|
return findNode(nodes, offset, pivotIndex + 1, end);
|
||||||
|
} else {
|
||||||
|
Node found = findChildNode(node, offset);
|
||||||
|
return found == null ? node : found;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node findChildNode(Node node, int offset) {
|
||||||
|
if (node.getChildren() == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return findNode(node.getChildren(), offset, 0, node.getChildren().size() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Java Properties AST node
|
* Java Properties AST node
|
||||||
*/
|
*/
|
||||||
@@ -65,6 +111,18 @@ public final class PropertiesAst {
|
|||||||
*/
|
*/
|
||||||
int getLength();
|
int getLength();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node's parent
|
||||||
|
* @return parent node
|
||||||
|
*/
|
||||||
|
Node getParent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node's children
|
||||||
|
* @return children nodes
|
||||||
|
*/
|
||||||
|
List<? extends Node> getChildren();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,6 +130,13 @@ public final class PropertiesAst {
|
|||||||
*/
|
*/
|
||||||
public interface Comment extends Node {
|
public interface Comment extends Node {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AST node for empty line
|
||||||
|
*/
|
||||||
|
public interface EmptyLine extends Node {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -103,6 +168,8 @@ public final class PropertiesAst {
|
|||||||
* @return Decoded property name
|
* @return Decoded property name
|
||||||
*/
|
*/
|
||||||
String decode();
|
String decode();
|
||||||
|
|
||||||
|
KeyValuePair getParent();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +184,7 @@ public final class PropertiesAst {
|
|||||||
*/
|
*/
|
||||||
String decode();
|
String decode();
|
||||||
|
|
||||||
|
KeyValuePair getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,34 +83,6 @@ public class PropertiesAntlrParserTest {
|
|||||||
testCommentLine(" # This is comment = ", "# This is comment = ");
|
testCommentLine(" # This is comment = ", "# This is comment = ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLines1() throws Exception {
|
|
||||||
ParseResults results = parser.parse("# Comment\n\n \t \t \n\t\t\n");
|
|
||||||
assertTrue(results.syntaxErrors.isEmpty());
|
|
||||||
assertTrue(results.problems.isEmpty());
|
|
||||||
assertEquals(1, results.ast.getAllNodes().size());
|
|
||||||
assertEquals(1, results.ast.getNodes(Comment.class).size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLines2() throws Exception {
|
|
||||||
ParseResults results = parser.parse("\n\n \t \t \n# Comment\n\t\t\n");
|
|
||||||
assertTrue(results.syntaxErrors.isEmpty());
|
|
||||||
assertTrue(results.problems.isEmpty());
|
|
||||||
assertEquals(1, results.ast.getAllNodes().size());
|
|
||||||
assertEquals(1, results.ast.getNodes(Comment.class).size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLines3() throws Exception {
|
|
||||||
ParseResults results = parser.parse("# Comment\n\nkey = value 1 \n \t \t \n\t\t\n");
|
|
||||||
assertTrue(results.syntaxErrors.isEmpty());
|
|
||||||
assertTrue(results.problems.isEmpty());
|
|
||||||
assertEquals(2, results.ast.getAllNodes().size());
|
|
||||||
assertEquals(1, results.ast.getNodes(Comment.class).size());
|
|
||||||
assertEquals(1, results.ast.getNodes(KeyValuePair.class).size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPropertyWithEqualsSeparator() throws Exception {
|
public void testPropertyWithEqualsSeparator() throws Exception {
|
||||||
testPropertyLine("key=value", "key", "key", "value", "value");
|
testPropertyLine("key=value", "key", "key", "value", "value");
|
||||||
@@ -118,7 +90,7 @@ public class PropertiesAntlrParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPropertyWithEqualsSeparatorAndSpaces() throws Exception {
|
public void testPropertyWithEqualsSeparatorAndSpaces() throws Exception {
|
||||||
testPropertyLine("key \t = \t \tvalue", "key", "key", "value", "value");
|
testPropertyLine("key \t = \t \tvalue", "key", "key", "value", " \t \tvalue");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -128,7 +100,7 @@ public class PropertiesAntlrParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPropertyWithColonSeparatorAndSpaces() throws Exception {
|
public void testPropertyWithColonSeparatorAndSpaces() throws Exception {
|
||||||
testPropertyLine("key \t : \t \tvalue", "key", "key", "value", "value");
|
testPropertyLine("key \t : \t \tvalue", "key", "key", "value", " \t \tvalue");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -168,17 +140,17 @@ public class PropertiesAntlrParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEqualsValueSeparatedWithEqualsAndSpace() throws Exception {
|
public void testEqualsValueSeparatedWithEqualsAndSpace() throws Exception {
|
||||||
testPropertyLine("key7 = =", "key7", "key7", "=", "=");
|
testPropertyLine("key7 = =", "key7", "key7", "=", " =");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValueWithTrailingSpaces() throws Exception {
|
public void testValueWithTrailingSpaces() throws Exception {
|
||||||
testPropertyLine("key = value 1 ", "key", "key", "value 1 ", "value 1 ");
|
testPropertyLine("key = value 1 ", "key", "key", "value 1 ", " value 1 ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUnodeCharKeyAndValue() throws Exception {
|
public void testUnodeCharKeyAndValue() throws Exception {
|
||||||
testPropertyLine("k\u2b22ey\u2b28 = val\u2b24ue 1\u2b24 ", "k\u2b22ey\u2b28", "k\u2b22ey\u2b28", "val\u2b24ue 1\u2b24 ", "val\u2b24ue 1\u2b24 ");
|
testPropertyLine("k\u2b22ey\u2b28 = val\u2b24ue 1\u2b24 ", "k\u2b22ey\u2b28", "k\u2b22ey\u2b28", "val\u2b24ue 1\u2b24 ", " val\u2b24ue 1\u2b24 ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
package org.springframework.ide.vscode.java.properties.parser.test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.ide.vscode.java.properties.antlr.parser.AntlrParser;
|
||||||
|
import org.springframework.ide.vscode.java.properties.parser.ParseResults;
|
||||||
|
import org.springframework.ide.vscode.java.properties.parser.Parser;
|
||||||
|
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Comment;
|
||||||
|
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.EmptyLine;
|
||||||
|
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Key;
|
||||||
|
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.KeyValuePair;
|
||||||
|
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Node;
|
||||||
|
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Value;
|
||||||
|
|
||||||
|
public class PropertiesAstTest {
|
||||||
|
|
||||||
|
Parser parser = new AntlrParser();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLines1() throws Exception {
|
||||||
|
ParseResults results = parser.parse("# Comment\n\n \t \t \n\t\t\n");
|
||||||
|
assertTrue(results.syntaxErrors.isEmpty());
|
||||||
|
assertTrue(results.problems.isEmpty());
|
||||||
|
assertEquals(4, results.ast.getAllNodes().size());
|
||||||
|
assertEquals(1, results.ast.getNodes(Comment.class).size());
|
||||||
|
assertEquals(3, results.ast.getNodes(EmptyLine.class).size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLines2() throws Exception {
|
||||||
|
ParseResults results = parser.parse("\n\n \t \t \n# Comment\n\t\t\n");
|
||||||
|
assertTrue(results.syntaxErrors.isEmpty());
|
||||||
|
assertTrue(results.problems.isEmpty());
|
||||||
|
assertEquals(5, results.ast.getAllNodes().size());
|
||||||
|
assertEquals(1, results.ast.getNodes(Comment.class).size());
|
||||||
|
assertEquals(4, results.ast.getNodes(EmptyLine.class).size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLines3() throws Exception {
|
||||||
|
ParseResults results = parser.parse("# Comment\n\nkey = value 1 \n \t \t \n\t\t\n");
|
||||||
|
assertTrue(results.syntaxErrors.isEmpty());
|
||||||
|
assertTrue(results.problems.isEmpty());
|
||||||
|
assertEquals(5, results.ast.getAllNodes().size());
|
||||||
|
assertEquals(1, results.ast.getNodes(Comment.class).size());
|
||||||
|
assertEquals(1, results.ast.getNodes(KeyValuePair.class).size());
|
||||||
|
assertEquals(3, results.ast.getNodes(EmptyLine.class).size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLines4() throws Exception {
|
||||||
|
ParseResults results = parser.parse("# Comment-1\n\nkey = value 1 \n# Comment-2");
|
||||||
|
assertEquals(4, results.ast.getAllNodes().size());
|
||||||
|
assertEquals(2, results.ast.getNodes(Comment.class).size());
|
||||||
|
assertEquals(1, results.ast.getNodes(KeyValuePair.class).size());
|
||||||
|
assertEquals(1, results.ast.getNodes(EmptyLine.class).size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLines5() throws Exception {
|
||||||
|
ParseResults results = parser.parse("#comment\nliquibase.enabled=\n#comment");
|
||||||
|
assertEquals(3, results.ast.getAllNodes().size());
|
||||||
|
assertEquals(2, results.ast.getNodes(Comment.class).size());
|
||||||
|
assertEquals(1, results.ast.getNodes(KeyValuePair.class).size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void positionComment() throws Exception {
|
||||||
|
ParseResults results = parser.parse("# Comment\n" + "key = value\n");
|
||||||
|
|
||||||
|
Node node = results.ast.findNode(7);
|
||||||
|
assertTrue(node instanceof Comment);
|
||||||
|
assertTrue(node.getOffset() <= 7 && 7 <= node.getOffset() + node.getLength());
|
||||||
|
|
||||||
|
node = results.ast.findNode(9);
|
||||||
|
assertTrue(node instanceof Comment);
|
||||||
|
assertTrue(node.getOffset() <= 9 && 9 <= node.getOffset() + node.getLength());
|
||||||
|
|
||||||
|
node = results.ast.findNode(0);
|
||||||
|
assertTrue(node instanceof Comment);
|
||||||
|
assertTrue(node.getOffset() <= 0 && 0 <= node.getOffset() + node.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void positionEmptyLine() throws Exception {
|
||||||
|
ParseResults results = parser.parse("# Comment\n" + "key = value\n" + "\t\n");
|
||||||
|
Node node = results.ast.findNode(23);
|
||||||
|
assertTrue(node instanceof EmptyLine);
|
||||||
|
assertTrue(node.getOffset() <= 23 && 23 <= node.getOffset() + node.getLength());
|
||||||
|
|
||||||
|
node = results.ast.findNode(24);
|
||||||
|
assertTrue(node instanceof EmptyLine);
|
||||||
|
assertTrue(node.getOffset() <= 24 && 24 <= node.getOffset() + node.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void positionKey() throws Exception {
|
||||||
|
ParseResults results = parser.parse("# Comment\n" + "key = value\n" + "\t\n");
|
||||||
|
Node node = results.ast.findNode(10);
|
||||||
|
assertTrue(node instanceof Key);
|
||||||
|
assertTrue(node.getOffset() <= 10 && 10 <= node.getOffset() + node.getLength());
|
||||||
|
|
||||||
|
node = results.ast.findNode(12);
|
||||||
|
assertTrue(node instanceof Key);
|
||||||
|
assertTrue(node.getOffset() <= 12 && 12 <= node.getOffset() + node.getLength());
|
||||||
|
|
||||||
|
node = results.ast.findNode(13);
|
||||||
|
assertTrue(node instanceof Key);
|
||||||
|
assertTrue(node.getOffset() <= 13 && 13 <= node.getOffset() + node.getLength());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void positionPair() throws Exception {
|
||||||
|
ParseResults results = parser.parse("# Comment\n" + "key = value\n" + "\t\n");
|
||||||
|
Node node = results.ast.findNode(15);
|
||||||
|
assertTrue(node instanceof KeyValuePair);
|
||||||
|
assertTrue(node.getOffset() <= 15 && 15 <= node.getOffset() + node.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void positionValue() throws Exception {
|
||||||
|
ParseResults results = parser.parse("# Comment\n" + "key = value\n");
|
||||||
|
Node node = results.ast.findNode(17);
|
||||||
|
assertTrue(node instanceof Value);
|
||||||
|
assertTrue(node.getOffset() <= 17 && 17 <= node.getOffset() + node.getLength());
|
||||||
|
|
||||||
|
node = results.ast.findNode(22);
|
||||||
|
assertTrue(node instanceof Value);
|
||||||
|
assertTrue(node.getOffset() <= 22 && 22 <= node.getOffset() + node.getLength());
|
||||||
|
|
||||||
|
node = results.ast.findNode(16);
|
||||||
|
assertTrue(node instanceof Value);
|
||||||
|
assertTrue(node.getOffset() <= 16 && 16 <= node.getOffset() + node.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void positionValueEofAtEnd() throws Exception {
|
||||||
|
ParseResults results = parser.parse("# Comment\n" + "key = value");
|
||||||
|
Node node = results.ast.findNode(22);
|
||||||
|
assertTrue(node instanceof Value);
|
||||||
|
assertTrue(node.getOffset() <= 22 && 22 <= node.getOffset() + node.getLength());
|
||||||
|
|
||||||
|
node = results.ast.findNode(16);
|
||||||
|
assertTrue(node instanceof Value);
|
||||||
|
assertTrue(node.getOffset() <= 16 && 16 <= node.getOffset() + node.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void positionEmptyValue() throws Exception {
|
||||||
|
ParseResults results = parser.parse("# Comment\n" + "key =");
|
||||||
|
Node node = results.ast.findNode(16);
|
||||||
|
assertTrue(node instanceof Value);
|
||||||
|
assertTrue(node.getOffset() <= 16 && 16 <= node.getOffset() + node.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -12,10 +12,12 @@ package org.springframework.ide.vscode.application.properties;
|
|||||||
|
|
||||||
import org.eclipse.lsp4j.ServerCapabilities;
|
import org.eclipse.lsp4j.ServerCapabilities;
|
||||||
import org.eclipse.lsp4j.TextDocumentSyncKind;
|
import org.eclipse.lsp4j.TextDocumentSyncKind;
|
||||||
|
import org.springframework.ide.vscode.application.properties.completions.SpringPropertiesCompletionEngine;
|
||||||
import org.springframework.ide.vscode.application.properties.metadata.SpringPropertyIndexProvider;
|
import org.springframework.ide.vscode.application.properties.metadata.SpringPropertyIndexProvider;
|
||||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtilProvider;
|
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtilProvider;
|
||||||
import org.springframework.ide.vscode.application.properties.reconcile.SpringPropertiesReconcileEngine;
|
import org.springframework.ide.vscode.application.properties.reconcile.SpringPropertiesReconcileEngine;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
|
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.util.TextDocument;
|
import org.springframework.ide.vscode.commons.languageserver.util.TextDocument;
|
||||||
@@ -30,18 +32,38 @@ public class ApplicationPropertiesLanguageServer extends SimpleLanguageServer {
|
|||||||
|
|
||||||
private SpringPropertyIndexProvider indexProvider;
|
private SpringPropertyIndexProvider indexProvider;
|
||||||
private TypeUtilProvider typeUtilProvider;
|
private TypeUtilProvider typeUtilProvider;
|
||||||
|
private VscodeCompletionEngineAdapter completionEngine;
|
||||||
|
private SpringPropertiesReconcileEngine reconcileEngine;
|
||||||
|
|
||||||
|
|
||||||
public ApplicationPropertiesLanguageServer(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider) {
|
public ApplicationPropertiesLanguageServer(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider, JavaProjectFinder javaProjectFinder) {
|
||||||
this.indexProvider = indexProvider;
|
this.indexProvider = indexProvider;
|
||||||
this.typeUtilProvider = typeUtilProvider;
|
this.typeUtilProvider = typeUtilProvider;
|
||||||
SimpleTextDocumentService documents = getTextDocumentService();
|
SimpleTextDocumentService documents = getTextDocumentService();
|
||||||
|
|
||||||
IReconcileEngine reconcileEngine = getReconcileEngine();
|
reconcileEngine = getReconcileEngine();
|
||||||
documents.onDidChangeContent(params -> {
|
documents.onDidChangeContent(params -> {
|
||||||
TextDocument doc = params.getDocument();
|
TextDocument doc = params.getDocument();
|
||||||
validateWith(doc, reconcileEngine);
|
validateWith(doc, reconcileEngine);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
SpringPropertiesCompletionEngine propertiesCompletionEngine = new SpringPropertiesCompletionEngine(
|
||||||
|
indexProvider,
|
||||||
|
typeUtilProvider,
|
||||||
|
javaProjectFinder
|
||||||
|
);
|
||||||
|
completionEngine = new VscodeCompletionEngineAdapter(this, propertiesCompletionEngine);
|
||||||
|
documents.onCompletion(completionEngine::getCompletions);
|
||||||
|
documents.onCompletionResolve(completionEngine::resolveCompletion);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxCompletionsNumber(int number) {
|
||||||
|
completionEngine.setMaxCompletionsNumber(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecordSyntaxErrors(boolean record) {
|
||||||
|
reconcileEngine.setRecordSyntaxErrors(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -53,7 +75,7 @@ public class ApplicationPropertiesLanguageServer extends SimpleLanguageServer {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IReconcileEngine getReconcileEngine() {
|
protected SpringPropertiesReconcileEngine getReconcileEngine() {
|
||||||
return new SpringPropertiesReconcileEngine(indexProvider, typeUtilProvider);
|
return new SpringPropertiesReconcileEngine(indexProvider, typeUtilProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
package org.springframework.ide.vscode.application.properties;
|
package org.springframework.ide.vscode.application.properties;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import org.eclipse.lsp4j.services.LanguageServer;
|
import org.eclipse.lsp4j.services.LanguageServer;
|
||||||
import org.springframework.ide.vscode.application.properties.metadata.DefaultSpringPropertyIndexProvider;
|
import org.springframework.ide.vscode.application.properties.metadata.DefaultSpringPropertyIndexProvider;
|
||||||
@@ -36,7 +35,7 @@ public class Main {
|
|||||||
JavaProjectFinder javaProjectFinder = JavaProjectFinder.DEFAULT;
|
JavaProjectFinder javaProjectFinder = JavaProjectFinder.DEFAULT;
|
||||||
SpringPropertyIndexProvider indexProvider = new DefaultSpringPropertyIndexProvider(javaProjectFinder);
|
SpringPropertyIndexProvider indexProvider = new DefaultSpringPropertyIndexProvider(javaProjectFinder);
|
||||||
TypeUtilProvider typeUtilProvider = (IDocument doc) -> new TypeUtil(javaProjectFinder.find(doc));
|
TypeUtilProvider typeUtilProvider = (IDocument doc) -> new TypeUtil(javaProjectFinder.find(doc));
|
||||||
LanguageServer server = new ApplicationPropertiesLanguageServer(indexProvider, typeUtilProvider);
|
LanguageServer server = new ApplicationPropertiesLanguageServer(indexProvider, typeUtilProvider, javaProjectFinder);
|
||||||
return server;
|
return server;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,582 @@
|
|||||||
|
package org.springframework.ide.vscode.application.properties.completions;
|
||||||
|
|
||||||
|
import static org.springframework.ide.vscode.commons.util.StringUtil.camelCaseToHyphens;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.PropertyInfo;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.completions.PropertyCompletionFactory;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.hints.HintProvider;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.hints.HintProviders;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.hints.StsValueHint;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.hints.ValueHintHoverInfo;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.types.Type;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.types.TypeParser;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil.BeanPropertyNameMode;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil.EnumCaseMode;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.types.TypedProperty;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.util.FuzzyMap;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.util.FuzzyMap.Match;
|
||||||
|
import org.springframework.ide.vscode.application.properties.reconcile.PropertyNavigator;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.completion.LazyProposalApplier;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.util.BadLocationException;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.util.IDocument;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.util.PrefixFinder;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.util.TextDocument;
|
||||||
|
import org.springframework.ide.vscode.commons.util.CollectionUtil;
|
||||||
|
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
|
||||||
|
import org.springframework.ide.vscode.commons.util.Log;
|
||||||
|
import org.springframework.ide.vscode.java.properties.antlr.parser.AntlrParser;
|
||||||
|
import org.springframework.ide.vscode.java.properties.parser.ParseResults;
|
||||||
|
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.EmptyLine;
|
||||||
|
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Key;
|
||||||
|
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Node;
|
||||||
|
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Value;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
class PropertiesCompletionProposalsCalculator {
|
||||||
|
|
||||||
|
private static final Pattern SPACES = Pattern.compile(
|
||||||
|
"(\\s|\\\\\\s)*"
|
||||||
|
);
|
||||||
|
|
||||||
|
private static boolean isValuePrefixChar(char c) {
|
||||||
|
return !Character.isWhitespace(c) && c!=',';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final PrefixFinder valuePrefixFinder = new PrefixFinder() {
|
||||||
|
protected boolean isPrefixChar(char c) {
|
||||||
|
return isValuePrefixChar(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final PrefixFinder fuzzySearchPrefix = new PrefixFinder() {
|
||||||
|
protected boolean isPrefixChar(char c) {
|
||||||
|
return !Character.isWhitespace(c);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final PrefixFinder navigationPrefixFinder = new PrefixFinder() {
|
||||||
|
public String getPrefix(IDocument doc, int offset) {
|
||||||
|
String prefix = super.getPrefix(doc, offset);
|
||||||
|
//Check if character before looks like 'navigation'.. otherwise don't
|
||||||
|
// return a navigationPrefix.
|
||||||
|
char charBefore = getCharBefore(doc, prefix, offset);
|
||||||
|
if (charBefore=='.' || charBefore==']') {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
private char getCharBefore(IDocument doc, String prefix, int offset) {
|
||||||
|
try {
|
||||||
|
if (prefix!=null) {
|
||||||
|
int offsetBefore = offset-prefix.length()-1;
|
||||||
|
if (offsetBefore>=0) {
|
||||||
|
return doc.getChar(offsetBefore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
protected boolean isPrefixChar(char c) {
|
||||||
|
return !Character.isWhitespace(c) && c!=']' && c!=']' && c!='.';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private FuzzyMap<PropertyInfo> index;
|
||||||
|
private TypeUtil typeUtil;
|
||||||
|
private PropertyCompletionFactory completionFactory;
|
||||||
|
private IDocument doc;
|
||||||
|
private int offset;
|
||||||
|
private boolean preferLowerCaseEnums;
|
||||||
|
private AntlrParser parser;
|
||||||
|
|
||||||
|
PropertiesCompletionProposalsCalculator(FuzzyMap<PropertyInfo> index, TypeUtil typeUtil, PropertyCompletionFactory completionFactory, IDocument doc, int offset, boolean preferLowerCaseEnums) {
|
||||||
|
this.index = index;
|
||||||
|
this.typeUtil = typeUtil;
|
||||||
|
this.completionFactory = completionFactory;
|
||||||
|
this.doc = doc;
|
||||||
|
this.offset = offset;
|
||||||
|
this.preferLowerCaseEnums = preferLowerCaseEnums;
|
||||||
|
this.parser = new AntlrParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create completions proposals in the context of a properties text editor.
|
||||||
|
*/
|
||||||
|
public Collection<ICompletionProposal> calculate() throws BadLocationException {
|
||||||
|
ParseResults parseResults = parser.parse(doc.get());
|
||||||
|
Node node = parseResults.ast.findNode(offset);
|
||||||
|
if (node instanceof Value) {
|
||||||
|
return getValueCompletions((Value)node);
|
||||||
|
} else if (node instanceof Key || node instanceof EmptyLine || node == null) {
|
||||||
|
return getPropertyCompletions();
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<ICompletionProposal> getNavigationProposals() {
|
||||||
|
String navPrefix = navigationPrefixFinder.getPrefix(doc, offset);
|
||||||
|
try {
|
||||||
|
if (navPrefix!=null) {
|
||||||
|
int navOffset = offset-navPrefix.length()-1; //offset of 'nav' operator char (i.e. '.' or ']').
|
||||||
|
navPrefix = fuzzySearchPrefix.getPrefix(doc, navOffset);
|
||||||
|
if (navPrefix!=null && !navPrefix.isEmpty()) {
|
||||||
|
PropertyInfo prop = findLongestValidProperty(index, navPrefix);
|
||||||
|
if (prop!=null) {
|
||||||
|
int regionStart = navOffset-navPrefix.length();
|
||||||
|
Collection<ICompletionProposal> hintProposals = getKeyHintProposals(prop, navOffset);
|
||||||
|
if (CollectionUtil.hasElements(hintProposals)) {
|
||||||
|
return hintProposals;
|
||||||
|
}
|
||||||
|
PropertyNavigator navigator = new PropertyNavigator(doc, null, typeUtil, new DocumentRegion(doc, regionStart, navOffset));
|
||||||
|
Type type = navigator.navigate(regionStart+prop.getId().length(), TypeParser.parse(prop.getType()));
|
||||||
|
if (type!=null) {
|
||||||
|
return getNavigationProposals(type, navOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.log(e);
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<ICompletionProposal> getKeyHintProposals(PropertyInfo prop, int navOffset) {
|
||||||
|
HintProvider hintProvider = prop.getHints(typeUtil, false);
|
||||||
|
if (!HintProviders.isNull(hintProvider)) {
|
||||||
|
String query = textBetween(doc, navOffset+1, offset);
|
||||||
|
List<TypedProperty> hintProperties = hintProvider.getPropertyHints(query);
|
||||||
|
if (CollectionUtil.hasElements(hintProperties)) {
|
||||||
|
return createPropertyProposals(TypeParser.parse(prop.getType()), navOffset, query, hintProperties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ImmutableList.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String textBetween(IDocument doc, int start, int end) {
|
||||||
|
if (end > doc.getLength()) {
|
||||||
|
end = doc.getLength();
|
||||||
|
}
|
||||||
|
if (start>doc.getLength()) {
|
||||||
|
start = doc.getLength();
|
||||||
|
}
|
||||||
|
if (start<0) {
|
||||||
|
start = 0;
|
||||||
|
}
|
||||||
|
if (end < 0) {
|
||||||
|
end = 0;
|
||||||
|
}
|
||||||
|
if (start<end) {
|
||||||
|
try {
|
||||||
|
return doc.get(start, end-start);
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type Type of the expression leading upto the 'nav' operator
|
||||||
|
* @param navOffset Offset of the nav operator (either ']' or '.'
|
||||||
|
* @param offset Offset of the cursor where CA was requested.
|
||||||
|
*/
|
||||||
|
private Collection<ICompletionProposal> getNavigationProposals(Type type, int navOffset) {
|
||||||
|
try {
|
||||||
|
char navOp = doc.getChar(navOffset);
|
||||||
|
if (navOp=='.') {
|
||||||
|
String prefix = doc.get(navOffset+1, offset-(navOffset+1));
|
||||||
|
EnumCaseMode caseMode = caseMode(prefix);
|
||||||
|
List<TypedProperty> objectProperties = typeUtil.getProperties(type, caseMode, BeanPropertyNameMode.HYPHENATED);
|
||||||
|
//Note: properties editor itself deals with relaxed names. So it expects the properties here to be returned in hyphenated form only.
|
||||||
|
if (objectProperties!=null && !objectProperties.isEmpty()) {
|
||||||
|
return createPropertyProposals(type, navOffset, prefix, objectProperties);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//TODO: other cases ']' or '[' ?
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.log(e);
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Collection<ICompletionProposal> createPropertyProposals(Type type, int navOffset,
|
||||||
|
String prefix, List<TypedProperty> objectProperties) {
|
||||||
|
ArrayList<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
|
||||||
|
for (TypedProperty prop : objectProperties) {
|
||||||
|
double score = FuzzyMatcher.matchScore(prefix, prop.getName());
|
||||||
|
if (score!=0) {
|
||||||
|
Type valueType = prop.getType();
|
||||||
|
String postFix = propertyCompletionPostfix(typeUtil, valueType);
|
||||||
|
DocumentEdits edits = new DocumentEdits(doc);
|
||||||
|
edits.delete(navOffset+1, offset);
|
||||||
|
edits.insert(offset, prop.getName()+postFix);
|
||||||
|
proposals.add(
|
||||||
|
completionFactory.beanProperty(doc, null, type, prefix, prop, score, edits, typeUtil)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return proposals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the EnumCaseMode used to generate completion candidates based on prefix.
|
||||||
|
*/
|
||||||
|
protected EnumCaseMode caseMode(String prefix) {
|
||||||
|
EnumCaseMode caseMode;
|
||||||
|
if ("".equals(prefix)) {
|
||||||
|
caseMode = preferLowerCaseEnums?EnumCaseMode.LOWER_CASE:EnumCaseMode.ORIGNAL;
|
||||||
|
} else {
|
||||||
|
caseMode = Character.isLowerCase(prefix.charAt(0))?EnumCaseMode.LOWER_CASE:EnumCaseMode.ORIGNAL;
|
||||||
|
}
|
||||||
|
return caseMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String propertyCompletionPostfix(TypeUtil typeUtil, Type type) {
|
||||||
|
String postfix = "";
|
||||||
|
if (type!=null) {
|
||||||
|
if (typeUtil.isAssignableType(type)) {
|
||||||
|
postfix = "=";
|
||||||
|
} else if (TypeUtil.isBracketable(type)) {
|
||||||
|
postfix = "[";
|
||||||
|
} else if (typeUtil.isDotable(type)) {
|
||||||
|
postfix = ".";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return postfix;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static boolean isAssign(char assign) {
|
||||||
|
// return assign==':'||assign=='=';
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private KeyValuePair getAstNodeLine(IDocument doc, int offset) {
|
||||||
|
// List<KeyValuePair> pairs = parser.parse(doc.get()).ast.getNodes(KeyValuePair.class);
|
||||||
|
// return findPair(pairs, offset, 0, pairs.size() - 1);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private KeyValuePair findPair(List<KeyValuePair> pairs, int offset, int start, int end) {
|
||||||
|
// if (start == end) {
|
||||||
|
// KeyValuePair pair = pairs.get(start);
|
||||||
|
// if (pair.getOffset() <= offset && offset <= pair.getOffset() + pair.getLength()) {
|
||||||
|
// return pair;
|
||||||
|
// } else {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// } else if (start < end ) {
|
||||||
|
// int pivotIndex = (start + end) / 2;
|
||||||
|
// KeyValuePair pair = pairs.get(pivotIndex);
|
||||||
|
// if (pair.getOffset() > offset) {
|
||||||
|
// return findPair(pairs, offset, start, pivotIndex - 1);
|
||||||
|
// } else if (offset > pair.getOffset() + pair.getLength()) {
|
||||||
|
// return findPair(pairs, offset, pivotIndex + 1, end);
|
||||||
|
// } else {
|
||||||
|
// return pair;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// private HoverInfo getValueHoverInfo(DocumentRegion value) {
|
||||||
|
// try {
|
||||||
|
// String valueString = value.toString();
|
||||||
|
// IDocument doc = value.getDocument();
|
||||||
|
// ITypedRegion valuePartition = getPartition(value.getDocument(), value.getStart());
|
||||||
|
// int valuePartitionStart = valuePartition.getOffset();
|
||||||
|
// String propertyName = fuzzySearchPrefix.getPrefix(doc, valuePartitionStart); //note: no need to skip whitespace backwards.
|
||||||
|
// //because value partition includes whitespace around the assignment
|
||||||
|
//
|
||||||
|
// Type type = getValueType(propertyName);
|
||||||
|
// if (TypeUtil.isArray(type) || TypeUtil.isList(type)) {
|
||||||
|
// //It is useful to provide content assist for the values in the list when entering a list
|
||||||
|
// type = TypeUtil.getDomainType(type);
|
||||||
|
// }
|
||||||
|
// if (TypeUtil.isClass(type)) {
|
||||||
|
// //Special case. We want to provide hoverinfos more liberally than what's suggested for completions (i.e. even class names
|
||||||
|
// //that are not suggested by the hints because they do not meet subtyping constraints should be hoverable and linkable!
|
||||||
|
// StsValueHint hint = StsValueHint.className(valueString, typeUtil);
|
||||||
|
// if (hint!=null) {
|
||||||
|
// return new ValueHintHoverInfo(hint);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// //Hack: pretend to invoke content-assist at the end of the value text. This should provide hints applicable to that value
|
||||||
|
// // then show hoverinfo based on that. That way we can avoid duplication a lot of similar logic to compute hoverinfos and hyperlinks.
|
||||||
|
// Collection<StsValueHint> hints = getValueHints(valueString, propertyName, EnumCaseMode.ALIASED);
|
||||||
|
// if (hints!=null) {
|
||||||
|
// for (StsValueHint h : hints) {
|
||||||
|
// if (valueString.equals(h.getValue())) {
|
||||||
|
// return new ValueHintHoverInfo(h);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } catch (BadLocationException e) {
|
||||||
|
// Log.log(e);
|
||||||
|
// }
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
private Collection<ICompletionProposal> getValueCompletions(Value value) {
|
||||||
|
DocumentRegion valueRegion = createRegion(doc, value).trimStart(SPACES).trimEnd(SPACES);
|
||||||
|
String query = valuePrefixFinder.getPrefix(doc, offset, valueRegion.getStart());
|
||||||
|
int startOfValue = offset - query.length();
|
||||||
|
EnumCaseMode caseMode = caseMode(query);
|
||||||
|
|
||||||
|
// note: no need to skip whitespace backwards.
|
||||||
|
String propertyName = /*fuzzySearchPrefix.getPrefix(doc, pair.getOffset())*/value.getParent().getKey().decode();
|
||||||
|
// because value partition includes whitespace around the assignment
|
||||||
|
if (propertyName != null) {
|
||||||
|
Collection<StsValueHint> valueCompletions = getValueHints(query, propertyName, caseMode);
|
||||||
|
if (valueCompletions != null && !valueCompletions.isEmpty()) {
|
||||||
|
ArrayList<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
|
||||||
|
for (StsValueHint hint : valueCompletions) {
|
||||||
|
String valueCandidate = hint.getValue();
|
||||||
|
double score = FuzzyMatcher.matchScore(query, valueCandidate);
|
||||||
|
if (score != 0) {
|
||||||
|
DocumentEdits edits = new DocumentEdits(doc);
|
||||||
|
edits.delete(startOfValue, offset);
|
||||||
|
edits.insert(offset, valueCandidate);
|
||||||
|
proposals.add(completionFactory.valueProposal(valueCandidate, query, getValueType(propertyName),
|
||||||
|
score, edits, new ValueHintHoverInfo(hint))
|
||||||
|
// new ValueProposal(startOfValue, valuePrefix,
|
||||||
|
// valueCandidate, i)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return proposals;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DocumentRegion createRegion(IDocument doc, Node value) {
|
||||||
|
// Trim trailing spaces (there is no leading white space already)
|
||||||
|
int length = value.getLength();
|
||||||
|
try {
|
||||||
|
length = doc.get(value.getOffset(), value.getLength()).trim().length();
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
return new DocumentRegion(doc, value.getOffset(), value.getOffset() + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<StsValueHint> getValueHints(String query, String propertyName, EnumCaseMode caseMode) {
|
||||||
|
Type type = getValueType(propertyName);
|
||||||
|
if (TypeUtil.isArray(type) || TypeUtil.isList(type)) {
|
||||||
|
//It is useful to provide content assist for the values in the list when entering a list
|
||||||
|
type = TypeUtil.getDomainType(type);
|
||||||
|
}
|
||||||
|
List<StsValueHint> allHints = new ArrayList<>();
|
||||||
|
{
|
||||||
|
Collection<StsValueHint> hints = typeUtil.getHintValues(type, query, caseMode);
|
||||||
|
if (CollectionUtil.hasElements(hints)) {
|
||||||
|
allHints.addAll(hints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
PropertyInfo prop = index.findLongestCommonPrefixEntry(propertyName);
|
||||||
|
if (prop!=null) {
|
||||||
|
HintProvider hintProvider = prop.getHints(typeUtil, false);
|
||||||
|
if (!HintProviders.isNull(hintProvider)) {
|
||||||
|
allHints.addAll(hintProvider.getValueHints(query));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allHints;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the value type for a give propertyName.
|
||||||
|
*/
|
||||||
|
protected Type getValueType(String propertyName) {
|
||||||
|
try {
|
||||||
|
PropertyInfo prop = index.get(propertyName);
|
||||||
|
if (prop!=null) {
|
||||||
|
return TypeParser.parse(prop.getType());
|
||||||
|
} else {
|
||||||
|
prop = findLongestValidProperty(index, propertyName);
|
||||||
|
if (prop!=null) {
|
||||||
|
TextDocument doc = new TextDocument(null);
|
||||||
|
doc.setText(propertyName);
|
||||||
|
PropertyNavigator navigator = new PropertyNavigator(doc, null, typeUtil, new DocumentRegion(doc, 0, doc.getLength()));
|
||||||
|
return navigator.navigate(prop.getId().length(), TypeParser.parse(prop.getType()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.log(e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Match<PropertyInfo>> findMatches(String prefix) {
|
||||||
|
List<Match<PropertyInfo>> matches = index.find(camelCaseToHyphens(prefix));
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<ICompletionProposal> getPropertyCompletions() throws BadLocationException {
|
||||||
|
Collection<ICompletionProposal> navProposals = getNavigationProposals();
|
||||||
|
if (!navProposals.isEmpty()) {
|
||||||
|
return navProposals;
|
||||||
|
}
|
||||||
|
return getFuzzyCompletions();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Collection<ICompletionProposal> getFuzzyCompletions() {
|
||||||
|
final String prefix = fuzzySearchPrefix.getPrefix(doc, offset);
|
||||||
|
if (prefix != null) {
|
||||||
|
Collection<Match<PropertyInfo>> matches = findMatches(prefix);
|
||||||
|
if (matches!=null && !matches.isEmpty()) {
|
||||||
|
ArrayList<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>(matches.size());
|
||||||
|
for (final Match<PropertyInfo> match : matches) {
|
||||||
|
DocumentEdits docEdits;
|
||||||
|
try {
|
||||||
|
docEdits = LazyProposalApplier.from(() -> {
|
||||||
|
Type type = TypeParser.parse(match.data.getType());
|
||||||
|
DocumentEdits edits = new DocumentEdits(doc);
|
||||||
|
edits.delete(offset-prefix.length(), offset);
|
||||||
|
edits.insert(offset, match.data.getId() + propertyCompletionPostfix(typeUtil, type));
|
||||||
|
return edits;
|
||||||
|
});
|
||||||
|
proposals.add(completionFactory.property(doc, docEdits, match, typeUtil));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return proposals;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// public HoverInfo getHoverInfo(IDocument doc, IRegion _region) {
|
||||||
|
// debug("getHoverInfo("+_region+")");
|
||||||
|
//
|
||||||
|
// //The delegate 'getHoverRegion' for spring propery editor will return smaller word regions.
|
||||||
|
// // we must ensure to use our own region finder to identify correct property name.
|
||||||
|
// ITypedRegion region = getHoverRegion(doc, _region.getOffset());
|
||||||
|
// if (region!=null) {
|
||||||
|
// String contentType = region.getType();
|
||||||
|
// try {
|
||||||
|
// if (contentType.equals(IDocument.DEFAULT_CONTENT_TYPE)) {
|
||||||
|
// debug("hoverRegion = "+region);
|
||||||
|
// PropertyInfo best = findBestHoverMatch(doc.get(region.getOffset(), region.getLength()).trim());
|
||||||
|
// if (best!=null) {
|
||||||
|
// return new SpringPropertyHoverInfo(documentContextFinder.getJavaProject(doc), best);
|
||||||
|
// }
|
||||||
|
// } else if (contentType.equals(IPropertiesFilePartitions.PROPERTY_VALUE)) {
|
||||||
|
// return getValueHoverInfo(new DocumentRegion(doc, region));
|
||||||
|
// }
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// SpringPropertiesEditorPlugin.log(e);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public ITypedRegion getHoverRegion(IDocument document, int offset) {
|
||||||
|
// try {
|
||||||
|
// ITypedRegion candidate = getPartition(document, offset);
|
||||||
|
// if (candidate!=null) {
|
||||||
|
// String type = candidate.getType();
|
||||||
|
// if (IDocument.DEFAULT_CONTENT_TYPE.equals(type)) {
|
||||||
|
// return candidate;
|
||||||
|
// } else if (IPropertiesFilePartitions.PROPERTY_VALUE.equals(type)) {
|
||||||
|
// DocumentRegion valueRegion = new DocumentRegion(document, candidate).trimStart(ASSIGN);
|
||||||
|
// return getValueHoverRegion(valueRegion, valueRegion.toRelative(offset));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// SpringPropertiesEditorPlugin.log(e);
|
||||||
|
// }
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private ITypedRegion getValueHoverRegion(DocumentRegion r, int offset) {
|
||||||
|
// int len = r.length();
|
||||||
|
// if (offset>=0 && offset<=len) {
|
||||||
|
// int start = offset;
|
||||||
|
// while (start>0 && isValuePrefixChar(r.charAt(start-1))) {
|
||||||
|
// start--;
|
||||||
|
// }
|
||||||
|
// int end = offset;
|
||||||
|
// while (end<len && isValuePrefixChar(r.charAt(end))) {
|
||||||
|
// end++;
|
||||||
|
// }
|
||||||
|
// r = r.subSequence(start, end);
|
||||||
|
// if (!r.isEmpty()) {
|
||||||
|
// return r.asTypedRegion(IPropertiesFilePartitions.PROPERTY_VALUE);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Search known properties for the best 'match' to show as hover data.
|
||||||
|
// */
|
||||||
|
// private PropertyInfo findBestHoverMatch(String propName) {
|
||||||
|
// //TODO: optimize, should be able to use index's treemap to find this without iterating all entries.
|
||||||
|
// PropertyInfo best = null;
|
||||||
|
// int bestCommonPrefixLen = 0; //We try to pick property with longest common prefix
|
||||||
|
// int bestExtraLen = Integer.MAX_VALUE;
|
||||||
|
// for (PropertyInfo candidate : index) {
|
||||||
|
// int commonPrefixLen = StringUtil.commonPrefixLength(propName, candidate.getId());
|
||||||
|
// int extraLen = candidate.getId().length()-commonPrefixLen;
|
||||||
|
// if (commonPrefixLen==propName.length() && extraLen==0) {
|
||||||
|
// //exact match found, can stop searching for better matches
|
||||||
|
// return candidate;
|
||||||
|
// }
|
||||||
|
// //candidate is better if...
|
||||||
|
// if (commonPrefixLen>bestCommonPrefixLen // it has a longer common prefix
|
||||||
|
// || commonPrefixLen==bestCommonPrefixLen && extraLen<bestExtraLen //or same common prefix but fewer extra chars
|
||||||
|
// ) {
|
||||||
|
// bestCommonPrefixLen = commonPrefixLen;
|
||||||
|
// bestExtraLen = extraLen;
|
||||||
|
// best = candidate;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return best;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the longest known property that is a prefix of the given name. Here prefix does not mean
|
||||||
|
* 'string prefix' but a prefix in the sense of treating '.' as a kind of separators. So
|
||||||
|
* 'prefix' is not allowed to end in the middle of a 'segment'.
|
||||||
|
*/
|
||||||
|
public static PropertyInfo findLongestValidProperty(FuzzyMap<PropertyInfo> index, String name) {
|
||||||
|
int bracketPos = name.indexOf('[');
|
||||||
|
int endPos = bracketPos>=0?bracketPos:name.length();
|
||||||
|
PropertyInfo prop = null;
|
||||||
|
String prefix = null;
|
||||||
|
while (endPos>0 && prop==null) {
|
||||||
|
prefix = name.substring(0, endPos);
|
||||||
|
String canonicalPrefix = camelCaseToHyphens(prefix);
|
||||||
|
prop = index.get(canonicalPrefix);
|
||||||
|
if (prop==null) {
|
||||||
|
endPos = name.lastIndexOf('.', endPos-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prop!=null) {
|
||||||
|
//We should meet caller's expectation that matched properties returned by this method
|
||||||
|
// match the names exactly even if we found them using relaxed name matching.
|
||||||
|
return prop.withId(prefix);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package org.springframework.ide.vscode.application.properties.completions;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.SpringPropertyIndexProvider;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.completions.PropertyCompletionFactory;
|
||||||
|
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtilProvider;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.util.BadLocationException;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.util.IDocument;;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kris De Volder
|
||||||
|
*/
|
||||||
|
public class SpringPropertiesCompletionEngine implements ICompletionEngine {
|
||||||
|
|
||||||
|
private boolean preferLowerCaseEnums = true; //might make sense to make this user configurable
|
||||||
|
|
||||||
|
private SpringPropertyIndexProvider indexProvider;
|
||||||
|
private TypeUtilProvider typeUtilProvider;
|
||||||
|
private PropertyCompletionFactory completionFactory = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor used in 'production'. Wires up stuff properly for running inside a normal
|
||||||
|
* Eclipse runtime.
|
||||||
|
*/
|
||||||
|
public SpringPropertiesCompletionEngine(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider, JavaProjectFinder projectFinder) {
|
||||||
|
this.indexProvider = indexProvider;
|
||||||
|
this.typeUtilProvider = typeUtilProvider;
|
||||||
|
this.completionFactory = new PropertyCompletionFactory(projectFinder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create completions proposals in the context of a properties text editor.
|
||||||
|
*/
|
||||||
|
public Collection<ICompletionProposal> getCompletions(IDocument doc, int offset) throws BadLocationException {
|
||||||
|
return new PropertiesCompletionProposalsCalculator(indexProvider.getIndex(doc),
|
||||||
|
typeUtilProvider.getTypeUtil(doc), completionFactory, doc, offset, preferLowerCaseEnums).calculate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getPreferLowerCaseEnums() {
|
||||||
|
return preferLowerCaseEnums;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPreferLowerCaseEnums(boolean preferLowerCaseEnums) {
|
||||||
|
this.preferLowerCaseEnums = preferLowerCaseEnums;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -69,7 +69,7 @@ public class SpringPropertiesReconcileEngine implements IReconcileEngine {
|
|||||||
private final DelimitedListReconciler commaListReconciler = new DelimitedListReconciler(COMMA, this::reconcileType);
|
private final DelimitedListReconciler commaListReconciler = new DelimitedListReconciler(COMMA, this::reconcileType);
|
||||||
private Parser parser = new AntlrParser();
|
private Parser parser = new AntlrParser();
|
||||||
|
|
||||||
private boolean recordSyntaxErrors = false;
|
private boolean recordSyntaxErrors;
|
||||||
|
|
||||||
public SpringPropertiesReconcileEngine(SpringPropertyIndexProvider provider, TypeUtilProvider typeUtilProvider) {
|
public SpringPropertiesReconcileEngine(SpringPropertyIndexProvider provider, TypeUtilProvider typeUtilProvider) {
|
||||||
this(provider, typeUtilProvider, true);
|
this(provider, typeUtilProvider, true);
|
||||||
@@ -103,8 +103,6 @@ public class SpringPropertiesReconcileEngine implements IReconcileEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
results.ast.getNodes(KeyValuePair.class).forEach(pair -> {
|
results.ast.getNodes(KeyValuePair.class).forEach(pair -> {
|
||||||
// Key fullName = pair.getKey();
|
|
||||||
// String keyName = fullName.decode();
|
|
||||||
try {
|
try {
|
||||||
DocumentRegion propertyNameRegion = createRegion(doc, pair.getKey());
|
DocumentRegion propertyNameRegion = createRegion(doc, pair.getKey());
|
||||||
String keyName = PropertiesFileEscapes.unescape(propertyNameRegion.toString());
|
String keyName = PropertiesFileEscapes.unescape(propertyNameRegion.toString());
|
||||||
@@ -184,7 +182,7 @@ public class SpringPropertiesReconcileEngine implements IReconcileEngine {
|
|||||||
// Trim trailing spaces (there is no leading white space already)
|
// Trim trailing spaces (there is no leading white space already)
|
||||||
int length = value.getLength();
|
int length = value.getLength();
|
||||||
try {
|
try {
|
||||||
length = doc.get(value.getOffset(), value.getLength()).trim().length();
|
length = doc.get(value.getOffset(), value.getLength()).length();
|
||||||
} catch (BadLocationException e) {
|
} catch (BadLocationException e) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.springframework.ide.vscode.application.properties.metadata.CachingVal
|
|||||||
import org.springframework.ide.vscode.application.properties.metadata.PropertiesLoader;
|
import org.springframework.ide.vscode.application.properties.metadata.PropertiesLoader;
|
||||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||||
import org.springframework.ide.vscode.commons.java.IType;
|
import org.springframework.ide.vscode.commons.java.IType;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||||
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
|
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
|
||||||
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||||
@@ -47,6 +48,8 @@ import org.eclipse.lsp4j.Diagnostic;
|
|||||||
*/
|
*/
|
||||||
public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
||||||
|
|
||||||
|
private JavaProjectFinder javaProjectFinder;
|
||||||
|
|
||||||
@Test public void testReconcileCatchesParseError() throws Exception {
|
@Test public void testReconcileCatchesParseError() throws Exception {
|
||||||
Editor editor = newEditor("key\n");
|
Editor editor = newEditor("key\n");
|
||||||
editor.assertProblems("key|extraneous input");
|
editor.assertProblems("key|extraneous input");
|
||||||
@@ -66,28 +69,28 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
editor.assertProblems("problem|extraneous input", "another|mismatched input");
|
editor.assertProblems("problem|extraneous input", "another|mismatched input");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testServerPortCompletion() throws Exception {
|
@Test public void testServerPortCompletion() throws Exception {
|
||||||
data("server.port", INTEGER, 8080, "Port where server listens for http.");
|
data("server.port", INTEGER, 8080, "Port where server listens for http.");
|
||||||
assertCompletion("ser<*>", "server.port=<*>");
|
assertCompletion("ser<*>", "server.port=<*>");
|
||||||
assertCompletionDisplayString("ser<*>", "server.port : int");
|
assertCompletionDisplayString("ser<*>", "server.port : int");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testLoggingLevelCompletion() throws Exception {
|
@Test public void testLoggingLevelCompletion() throws Exception {
|
||||||
data("logging.level", "java.util.Map<java.lang.String,java.lang.Object>", null, "Logging level per package.");
|
data("logging.level", "java.util.Map<java.lang.String,java.lang.Object>", null, "Logging level per package.");
|
||||||
assertCompletion("lolev<*>","logging.level.<*>");
|
assertCompletion("lolev<*>","logging.level.<*>");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testListCompletion() throws Exception {
|
@Test public void testListCompletion() throws Exception {
|
||||||
data("foo.bars", "java.util.List<java.lang.String>", null, "List of bars in foo.");
|
data("foo.bars", "java.util.List<java.lang.String>", null, "List of bars in foo.");
|
||||||
assertCompletion("foba<*>","foo.bars=<*>");
|
assertCompletion("foba<*>","foo.bars=<*>");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testInetAddresCompletion() throws Exception {
|
@Test public void testInetAddresCompletion() throws Exception {
|
||||||
defaultTestData();
|
defaultTestData();
|
||||||
assertCompletion("server.add<*>", "server.address=<*>");
|
assertCompletion("server.add<*>", "server.address=<*>");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testStringArrayCompletion() throws Exception {
|
@Test public void testStringArrayCompletion() throws Exception {
|
||||||
data("spring.freemarker.view-names", "java.lang.String[]", null, "White list of view names that can be resolved.");
|
data("spring.freemarker.view-names", "java.lang.String[]", null, "White list of view names that can be resolved.");
|
||||||
data("some.defaulted.array", "java.lang.String[]", new String[] {"a", "b", "c"} , "Stuff.");
|
data("some.defaulted.array", "java.lang.String[]", new String[] {"a", "b", "c"} , "Stuff.");
|
||||||
|
|
||||||
@@ -95,7 +98,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
assertCompletion("some.d.a<*>", "some.defaulted.array=<*>");
|
assertCompletion("some.d.a<*>", "some.defaulted.array=<*>");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testEmptyPrefixProposalsSortedAlpabetically() throws Exception {
|
@Test public void testEmptyPrefixProposalsSortedAlpabetically() throws Exception {
|
||||||
defaultTestData();
|
defaultTestData();
|
||||||
Editor editor = newEditor("");
|
Editor editor = newEditor("");
|
||||||
List<CompletionItem> completions = editor.getCompletions();
|
List<CompletionItem> completions = editor.getCompletions();
|
||||||
@@ -110,7 +113,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testValueCompletion() throws Exception {
|
@Test public void testValueCompletion() throws Exception {
|
||||||
defaultTestData();
|
defaultTestData();
|
||||||
assertCompletionsVariations("liquibase.enabled=<*>",
|
assertCompletionsVariations("liquibase.enabled=<*>",
|
||||||
"liquibase.enabled=false<*>",
|
"liquibase.enabled=false<*>",
|
||||||
@@ -310,7 +313,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testPojoArrayCompletions() throws Exception {
|
@Test public void testPojoArrayCompletions() throws Exception {
|
||||||
IJavaProject p = createPredefinedMavenProject("boot-1.2.1-app-properties-list-of-pojo");
|
IJavaProject p = createPredefinedMavenProject("boot-1.2.1-app-properties-list-of-pojo");
|
||||||
|
|
||||||
useProject(p);
|
useProject(p);
|
||||||
@@ -395,7 +398,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testRelaxedNameContentAssist() throws Exception {
|
@Test public void testRelaxedNameContentAssist() throws Exception {
|
||||||
data("foo-bar-zor.enabled", "java.lang.Boolean", null, null);
|
data("foo-bar-zor.enabled", "java.lang.Boolean", null, null);
|
||||||
assertCompletion("fooBar<*>", "foo-bar-zor.enabled=<*>");
|
assertCompletion("fooBar<*>", "foo-bar-zor.enabled=<*>");
|
||||||
}
|
}
|
||||||
@@ -458,7 +461,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testEnumPropertyCompletionInsideCommaSeparateList() throws Exception {
|
@Test public void testEnumPropertyCompletionInsideCommaSeparateList() throws Exception {
|
||||||
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
||||||
|
|
||||||
useProject(p);
|
useProject(p);
|
||||||
@@ -481,7 +484,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
assertCompletion("foo.colors=RED,B<*>", "foo.colors=RED,BLUE<*>");
|
assertCompletion("foo.colors=RED,B<*>", "foo.colors=RED,BLUE<*>");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testEnumPropertyCompletion() throws Exception {
|
@Test public void testEnumPropertyCompletion() throws Exception {
|
||||||
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
||||||
|
|
||||||
useProject(p);
|
useProject(p);
|
||||||
@@ -523,7 +526,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testEnumMapValueCompletion() throws Exception {
|
@Test public void testEnumMapValueCompletion() throws Exception {
|
||||||
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
||||||
|
|
||||||
useProject(p);
|
useProject(p);
|
||||||
@@ -559,7 +562,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testEnumMapKeyCompletion() throws Exception {
|
@Test public void testEnumMapKeyCompletion() throws Exception {
|
||||||
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
||||||
|
|
||||||
useProject(p);
|
useProject(p);
|
||||||
@@ -617,7 +620,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testPojoCompletions() throws Exception {
|
@Test public void testPojoCompletions() throws Exception {
|
||||||
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
||||||
|
|
||||||
useProject(p);
|
useProject(p);
|
||||||
@@ -629,11 +632,11 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
assertCompletionsDisplayString("foo.data.",
|
assertCompletionsDisplayString("foo.data.",
|
||||||
"wavelen : double",
|
"wavelen : double",
|
||||||
"name : String",
|
"name : String",
|
||||||
"next : demo.Color[RED, GREEN, BLUE]",
|
"next : demo.Color[BLUE, GREEN, RED]",
|
||||||
"nested : demo.ColorData",
|
"nested : demo.ColorData",
|
||||||
"children : List<demo.ColorData>",
|
"children : List<demo.ColorData>",
|
||||||
"mapped-children : Map<String, demo.ColorData>",
|
"mapped-children : Map<String, demo.ColorData>",
|
||||||
"color-children : Map<demo.Color[RED, GREEN, BLUE], demo.ColorData>",
|
"color-children : Map<demo.Color[BLUE, GREEN, RED], demo.ColorData>",
|
||||||
"tags : List<String>",
|
"tags : List<String>",
|
||||||
"funky : boolean"
|
"funky : boolean"
|
||||||
);
|
);
|
||||||
@@ -675,7 +678,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testListOfAtomicCompletions() throws Exception {
|
@Test public void testListOfAtomicCompletions() throws Exception {
|
||||||
data("foo.slist", "java.util.List<java.lang.String>", null, "list of strings");
|
data("foo.slist", "java.util.List<java.lang.String>", null, "list of strings");
|
||||||
data("foo.ulist", "java.util.List<Unknown>", null, "list of strings");
|
data("foo.ulist", "java.util.List<Unknown>", null, "list of strings");
|
||||||
data("foo.dlist", "java.util.List<java.lang.Double>", null, "list of doubles");
|
data("foo.dlist", "java.util.List<java.lang.Double>", null, "list of doubles");
|
||||||
@@ -684,7 +687,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
assertCompletionsVariations("foo.sl<*>", "foo.slist=<*>");
|
assertCompletionsVariations("foo.sl<*>", "foo.slist=<*>");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testMapKeyDotInterpretation() throws Exception {
|
@Test public void testMapKeyDotInterpretation() throws Exception {
|
||||||
//Interpretation of '.' changes depending on the domain type (i.e. when domain type is
|
//Interpretation of '.' changes depending on the domain type (i.e. when domain type is
|
||||||
//is a simple type got which '.' navigation is invalid then the '.' is 'eaten' by the key.
|
//is a simple type got which '.' navigation is invalid then the '.' is 'eaten' by the key.
|
||||||
|
|
||||||
@@ -724,7 +727,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testMapKeyDotInterpretationInPojo() throws Exception {
|
@Test public void testMapKeyDotInterpretationInPojo() throws Exception {
|
||||||
//Similar to testMapKeyDotInterpretation but this time maps are not attached to property
|
//Similar to testMapKeyDotInterpretation but this time maps are not attached to property
|
||||||
// directly but via a pojo property
|
// directly but via a pojo property
|
||||||
|
|
||||||
@@ -797,7 +800,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testEnumsInLowerCaseContentAssist() throws Exception {
|
@Test public void testEnumsInLowerCaseContentAssist() throws Exception {
|
||||||
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
||||||
|
|
||||||
useProject(p);
|
useProject(p);
|
||||||
@@ -840,7 +843,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
assertCompletionsVariations("foo.color-data.red.na<*>", "foo.color-data.red.name=<*>");
|
assertCompletionsVariations("foo.color-data.red.na<*>", "foo.color-data.red.name=<*>");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testNavigationProposalAfterRelaxedPropertyName() throws Exception {
|
@Test public void testNavigationProposalAfterRelaxedPropertyName() throws Exception {
|
||||||
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
||||||
|
|
||||||
useProject(p);
|
useProject(p);
|
||||||
@@ -849,7 +852,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
assertCompletionsVariations("foo.colorData.red.na<*>", "foo.colorData.red.name=<*>");
|
assertCompletionsVariations("foo.colorData.red.na<*>", "foo.colorData.red.name=<*>");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testValueProposalAssignedToRelaxedPropertyName() throws Exception {
|
@Test public void testValueProposalAssignedToRelaxedPropertyName() throws Exception {
|
||||||
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
IJavaProject p = createPredefinedMavenProject("enums-boot-1.3.2-app");
|
||||||
|
|
||||||
useProject(p);
|
useProject(p);
|
||||||
@@ -983,7 +986,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testCharsetCompletions() throws Exception {
|
@Test public void testCharsetCompletions() throws Exception {
|
||||||
data("foobar.encoding", "java.nio.charset.Charset", null, "The charset-encoding to use for foobars");
|
data("foobar.encoding", "java.nio.charset.Charset", null, "The charset-encoding to use for foobars");
|
||||||
|
|
||||||
assertCompletions(
|
assertCompletions(
|
||||||
@@ -1001,7 +1004,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testLocaleCompletions() throws Exception {
|
@Test public void testLocaleCompletions() throws Exception {
|
||||||
data("foobar.locale", "java.util.Locale", null, "Yada yada");
|
data("foobar.locale", "java.util.Locale", null, "Yada yada");
|
||||||
|
|
||||||
assertCompletions(
|
assertCompletions(
|
||||||
@@ -1019,7 +1022,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testPropertyValueHintCompletions() throws Exception {
|
@Test public void testPropertyValueHintCompletions() throws Exception {
|
||||||
//Test that 'value hints' work when property name is associated with 'value' hints.
|
//Test that 'value hints' work when property name is associated with 'value' hints.
|
||||||
// via boot metadata.
|
// via boot metadata.
|
||||||
|
|
||||||
@@ -1037,7 +1040,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testPropertyListHintCompletions() throws Exception {
|
@Test public void testPropertyListHintCompletions() throws Exception {
|
||||||
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
||||||
|
|
||||||
assertCompletion(
|
assertCompletion(
|
||||||
@@ -1065,7 +1068,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testPropertyMapValueCompletions() throws Exception {
|
@Test public void testPropertyMapValueCompletions() throws Exception {
|
||||||
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
||||||
|
|
||||||
assertCompletionsDisplayString(
|
assertCompletionsDisplayString(
|
||||||
@@ -1093,7 +1096,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testPropertyMapKeyCompletions() throws Exception {
|
@Test public void testPropertyMapKeyCompletions() throws Exception {
|
||||||
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
||||||
assertCompletionWithLabel(
|
assertCompletionWithLabel(
|
||||||
"logging.level.<*>"
|
"logging.level.<*>"
|
||||||
@@ -1120,7 +1123,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testHandleAsResourceContentAssist() throws Exception {
|
@Test public void testHandleAsResourceContentAssist() throws Exception {
|
||||||
//"name": "my.terms-and-conditions",
|
//"name": "my.terms-and-conditions",
|
||||||
// "providers": [
|
// "providers": [
|
||||||
// {
|
// {
|
||||||
@@ -1144,7 +1147,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testHandleAsListContentAssist() throws Exception {
|
@Test public void testHandleAsListContentAssist() throws Exception {
|
||||||
data("my.tosses", "String[]", null, "A sequence of coin tosses")
|
data("my.tosses", "String[]", null, "A sequence of coin tosses")
|
||||||
.provider("handle-as", "target", "java.lang.Boolean[]");
|
.provider("handle-as", "target", "java.lang.Boolean[]");
|
||||||
|
|
||||||
@@ -1179,7 +1182,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Ignore @Test public void test_STS_3335_completions_list_nested_in_Map_of_String() throws Exception {
|
@Test public void test_STS_3335_completions_list_nested_in_Map_of_String() throws Exception {
|
||||||
useProject(createPredefinedMavenProject("boot-1.3.3-sts-4335"));
|
useProject(createPredefinedMavenProject("boot-1.3.3-sts-4335"));
|
||||||
|
|
||||||
assertCompletions(
|
assertCompletions(
|
||||||
@@ -1201,7 +1204,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testSimpleResourceCompletion() throws Exception {
|
@Test public void testSimpleResourceCompletion() throws Exception {
|
||||||
CachingValueProvider.TIMEOUT = Duration.ofSeconds(20);
|
CachingValueProvider.TIMEOUT = Duration.ofSeconds(20);
|
||||||
|
|
||||||
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
||||||
@@ -1225,7 +1228,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testClasspathResourceCompletion() throws Exception {
|
@Test public void testClasspathResourceCompletion() throws Exception {
|
||||||
CachingValueProvider.TIMEOUT = Duration.ofSeconds(20);
|
CachingValueProvider.TIMEOUT = Duration.ofSeconds(20);
|
||||||
|
|
||||||
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
||||||
@@ -1295,7 +1298,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testClasspathResourceCompletionInCommaList() throws Exception {
|
@Test public void testClasspathResourceCompletionInCommaList() throws Exception {
|
||||||
CachingValueProvider.TIMEOUT = Duration.ofSeconds(20);
|
CachingValueProvider.TIMEOUT = Duration.ofSeconds(20);
|
||||||
|
|
||||||
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
||||||
@@ -1490,7 +1493,7 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void test_PT_119352965() throws Exception {
|
@Test public void test_PT_119352965() throws Exception {
|
||||||
data("some.property", "java.lang.String", null, "Some property to test stuff")
|
data("some.property", "java.lang.String", null, "Some property to test stuff")
|
||||||
.valueHint("SOMETHING", "A value for something")
|
.valueHint("SOMETHING", "A value for something")
|
||||||
.valueHint("ALTERNATE", "An alternative value");
|
.valueHint("ALTERNATE", "An alternative value");
|
||||||
@@ -1558,17 +1561,9 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SimpleLanguageServer newLanguageServer() {
|
protected SimpleLanguageServer newLanguageServer() {
|
||||||
return new ApplicationPropertiesLanguageServer(md.getIndexProvider(), typeUtilProvider);
|
ApplicationPropertiesLanguageServer server = new ApplicationPropertiesLanguageServer(md.getIndexProvider(), typeUtilProvider, javaProjectFinder);
|
||||||
// return new ApplicationPropertiesLanguageServer(md.getIndexProvider(), typeUtilProvider) {
|
server.setMaxCompletionsNumber(-1);
|
||||||
//
|
return server;
|
||||||
// @Override
|
|
||||||
// protected IReconcileEngine getReconcileEngine() {
|
|
||||||
// SpringPropertiesReconcileEngine reconcileEngine = (SpringPropertiesReconcileEngine) super.getReconcileEngine();
|
|
||||||
// reconcileEngine.setRecordSyntaxErrors(false);
|
|
||||||
// return reconcileEngine;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class ApplicationPropertiesLanguageServerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private LanguageServerHarness newHarness() throws Exception {
|
private LanguageServerHarness newHarness() throws Exception {
|
||||||
Callable<? extends LanguageServer> f = () -> new ApplicationPropertiesLanguageServer((d) -> null, (d) -> null);
|
Callable<? extends LanguageServer> f = () -> new ApplicationPropertiesLanguageServer((d) -> null, (d) -> null, (d) -> null);
|
||||||
return new LanguageServerHarness(f);
|
return new LanguageServerHarness(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public class ApplicationYamlLanguageServer extends SimpleLanguageServer {
|
|||||||
private YamlASTProvider parser = new YamlParser(yaml);
|
private YamlASTProvider parser = new YamlParser(yaml);
|
||||||
private SpringPropertyIndexProvider indexProvider;
|
private SpringPropertyIndexProvider indexProvider;
|
||||||
private TypeUtilProvider typeUtilProvider;
|
private TypeUtilProvider typeUtilProvider;
|
||||||
|
private VscodeCompletionEngineAdapter completionEngine;
|
||||||
|
|
||||||
public ApplicationYamlLanguageServer(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider, JavaProjectFinder javaProjectFinder) {
|
public ApplicationYamlLanguageServer(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider, JavaProjectFinder javaProjectFinder) {
|
||||||
this.indexProvider = indexProvider;
|
this.indexProvider = indexProvider;
|
||||||
@@ -57,10 +58,14 @@ public class ApplicationYamlLanguageServer extends SimpleLanguageServer {
|
|||||||
typeUtilProvider,
|
typeUtilProvider,
|
||||||
RelaxedNameConfig.COMPLETION_DEFAULTS
|
RelaxedNameConfig.COMPLETION_DEFAULTS
|
||||||
);
|
);
|
||||||
VscodeCompletionEngine completionEngine = new VscodeCompletionEngineAdapter(this, yamlCompletionEngine);
|
completionEngine = new VscodeCompletionEngineAdapter(this, yamlCompletionEngine);
|
||||||
documents.onCompletion(completionEngine::getCompletions);
|
documents.onCompletion(completionEngine::getCompletions);
|
||||||
documents.onCompletionResolve(completionEngine::resolveCompletion);
|
documents.onCompletionResolve(completionEngine::resolveCompletion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMaxCompletionsNumber(int number) {
|
||||||
|
completionEngine.setMaxCompletionsNumber(number);
|
||||||
|
}
|
||||||
|
|
||||||
protected IReconcileEngine getReconcileEngine() {
|
protected IReconcileEngine getReconcileEngine() {
|
||||||
return new ApplicationYamlReconcileEngine(parser, indexProvider, typeUtilProvider);
|
return new ApplicationYamlReconcileEngine(parser, indexProvider, typeUtilProvider);
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import org.springframework.ide.vscode.application.properties.metadata.util.Fuzzy
|
|||||||
import org.springframework.ide.vscode.application.properties.metadata.util.FuzzyMap.Match;
|
import org.springframework.ide.vscode.application.properties.metadata.util.FuzzyMap.Match;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||||
|
import org.springframework.ide.vscode.commons.languageserver.completion.LazyProposalApplier;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.completion.ProposalApplier;
|
import org.springframework.ide.vscode.commons.languageserver.completion.ProposalApplier;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
|
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
|
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
|
||||||
|
|||||||
@@ -2987,7 +2987,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testPropertyMapKeyCompletions() throws Exception {
|
@Test public void testPropertyMapKeyCompletions() throws Exception {
|
||||||
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
||||||
assertCompletionWithLabel(
|
assertCompletionWithLabel(
|
||||||
"logging:\n" +
|
"logging:\n" +
|
||||||
@@ -3090,7 +3090,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testSimpleResourceCompletion() throws Exception {
|
@Test public void testSimpleResourceCompletion() throws Exception {
|
||||||
CachingValueProvider.TIMEOUT = Duration.ofSeconds(20);
|
CachingValueProvider.TIMEOUT = Duration.ofSeconds(20);
|
||||||
|
|
||||||
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
||||||
@@ -3134,7 +3134,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testClasspathResourceCompletion() throws Exception {
|
@Test public void testClasspathResourceCompletion() throws Exception {
|
||||||
CachingValueProvider.TIMEOUT = Duration.ofSeconds(20);
|
CachingValueProvider.TIMEOUT = Duration.ofSeconds(20);
|
||||||
|
|
||||||
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));
|
||||||
@@ -3388,7 +3388,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testHandleAsResourceContentAssist() throws Exception {
|
@Test public void testHandleAsResourceContentAssist() throws Exception {
|
||||||
//"name": "my.terms-and-conditions",
|
//"name": "my.terms-and-conditions",
|
||||||
// "providers": [
|
// "providers": [
|
||||||
// {
|
// {
|
||||||
@@ -3413,7 +3413,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test public void testBootBug5905() throws Exception {
|
@Test public void testBootBug5905() throws Exception {
|
||||||
useProject(createPredefinedMavenProject("boot-1.3.3-app-with-resource-prop"));
|
useProject(createPredefinedMavenProject("boot-1.3.3-app-with-resource-prop"));
|
||||||
|
|
||||||
//Check the metadata reflects the 'handle-as':
|
//Check the metadata reflects the 'handle-as':
|
||||||
@@ -3542,7 +3542,9 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SimpleLanguageServer newLanguageServer() {
|
protected SimpleLanguageServer newLanguageServer() {
|
||||||
return new ApplicationYamlLanguageServer(md.getIndexProvider(), typeUtilProvider, javaProjectFinder);
|
ApplicationYamlLanguageServer server = new ApplicationYamlLanguageServer(md.getIndexProvider(), typeUtilProvider, javaProjectFinder);
|
||||||
|
server.setMaxCompletionsNumber(-1);
|
||||||
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user