Make snippets fully subsume property completions in bosh editor
This commit is contained in:
@@ -257,7 +257,7 @@ public class BoshDeploymentManifestSchema extends SchemaSupport implements YamlS
|
||||
}
|
||||
);
|
||||
|
||||
addProp(t_stemcell, "alias", t_stemcell_alias_def).isRequired(true);
|
||||
addProp(t_stemcell, "alias", t_stemcell_alias_def).isPrimary(true);
|
||||
addProp(t_stemcell, "version", t_stemcell_version_ref).isRequired(true);
|
||||
addProp(t_stemcell, "name", t_stemcell_name_ref);
|
||||
addProp(t_stemcell, "os", t_stemcell_os_ref);
|
||||
|
||||
@@ -29,7 +29,6 @@ import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* An implementation of {@link TypeBasedSnippetProvider} that generates snippets
|
||||
@@ -46,7 +45,9 @@ public class SchemaBasedSnippetGenerator implements TypeBasedSnippetProvider {
|
||||
this.snippetBuilderFactory = snippetBuilderFactory;
|
||||
}
|
||||
|
||||
private Cache<YType, Collection<Snippet>> cache = CacheBuilder.newBuilder().build();
|
||||
private Cache<YType, Collection<Snippet>> cache = CacheBuilder.newBuilder()
|
||||
.weakKeys()
|
||||
.build();
|
||||
private int maxNesting = Integer.MAX_VALUE;
|
||||
|
||||
@Override
|
||||
@@ -60,24 +61,9 @@ public class SchemaBasedSnippetGenerator implements TypeBasedSnippetProvider {
|
||||
}
|
||||
|
||||
private Collection<Snippet> generateSnippets(YType type) {
|
||||
ImmutableList.Builder<Snippet> snippets = ImmutableList.builder();
|
||||
//Generate a 'full' snippet that defines all required properties of the current type.
|
||||
Snippet snippet = generateFullSnippet(type, 0);
|
||||
if (snippet!=null) {
|
||||
snippets.add(snippet);
|
||||
}
|
||||
//Generate single property snippets that only define a single properties (with 'mega snippets' for nested types)
|
||||
for (YTypedProperty p : typeUtil.getProperties(type)) {
|
||||
String propName = p.getName();
|
||||
SnippetBuilder builder = snippetBuilderFactory.get();
|
||||
generateBeanSnippet(ImmutableList.of(p), builder, 0, maxNesting);
|
||||
if (builder.getPlaceholderCount()>=2) {
|
||||
snippets.add(new Snippet(p.getName()+" Snippet", builder.toString(), (dc) ->
|
||||
!dc.getDefinedProperties().contains(propName)
|
||||
));
|
||||
}
|
||||
}
|
||||
return snippets.build();
|
||||
return snippet==null ? ImmutableList.of() : ImmutableList.of(snippet);
|
||||
}
|
||||
|
||||
private Snippet generateFullSnippet(YType type, int indent) {
|
||||
@@ -116,6 +102,16 @@ public class SchemaBasedSnippetGenerator implements TypeBasedSnippetProvider {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Snippet getSnippet(YType contextType, YTypedProperty p) {
|
||||
//TODO: cache?
|
||||
SnippetBuilder builder = snippetBuilderFactory.get();
|
||||
generateBeanSnippet(ImmutableList.of(p), builder, 0, maxNesting);
|
||||
String propName = p.getName();
|
||||
return new Snippet(propName, builder.toString(), (dc) ->
|
||||
!dc.getDefinedProperties().contains(propName)
|
||||
);
|
||||
}
|
||||
|
||||
private void generateNestedSnippet(boolean parentIsSeq, YType type, SnippetBuilder builder, int indent, int nestingLimit) {
|
||||
if (type==null) {
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
package org.springframework.ide.vscode.bosh;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.ide.vscode.languageserver.testharness.Editor.*;
|
||||
import static org.springframework.ide.vscode.languageserver.testharness.Editor.DEDENTED_COMPLETION;
|
||||
import static org.springframework.ide.vscode.languageserver.testharness.Editor.PLAIN_COMPLETION;
|
||||
import static org.springframework.ide.vscode.languageserver.testharness.Editor.SNIPPET_COMPLETION;
|
||||
import static org.springframework.ide.vscode.languageserver.testharness.TestAsserts.assertContains;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -26,7 +27,6 @@ import org.eclipse.lsp4j.CompletionItem;
|
||||
import org.eclipse.lsp4j.Diagnostic;
|
||||
import org.eclipse.lsp4j.DiagnosticSeverity;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.bosh.mocks.MockCloudConfigProvider;
|
||||
import org.springframework.ide.vscode.bosh.models.BoshCommandReleasesProvider;
|
||||
@@ -158,11 +158,10 @@ public class BoshEditorTest {
|
||||
}
|
||||
|
||||
@Test public void toplevelPropertyCompletions() throws Exception {
|
||||
harness.getServer().enableSnippets(false);
|
||||
Editor editor = harness.newEditor(
|
||||
"<*>"
|
||||
);
|
||||
editor.assertCompletions(
|
||||
editor.assertCompletions(SNIPPET_COMPLETION.negate(),
|
||||
"name: <*>"
|
||||
);
|
||||
|
||||
@@ -174,24 +173,42 @@ public class BoshEditorTest {
|
||||
editor.assertCompletions(
|
||||
"name: blah\n" +
|
||||
"instance_groups:\n" +
|
||||
"- name: <*>"
|
||||
"- name: $1\n" +
|
||||
" azs:\n" +
|
||||
" - $2\n" +
|
||||
" instances: $3\n" +
|
||||
" jobs:\n" +
|
||||
" - name: $4\n" +
|
||||
" release: $5\n" +
|
||||
" vm_type: $6\n" +
|
||||
" stemcell: $7\n" +
|
||||
" networks:\n" +
|
||||
" - name: $8<*>"
|
||||
, // ============
|
||||
"name: blah\n" +
|
||||
"releases:\n" +
|
||||
"- name: <*>"
|
||||
"- name: $1\n" +
|
||||
" version: $2<*>"
|
||||
, // ============
|
||||
"name: blah\n" +
|
||||
"stemcells:\n- <*>"
|
||||
"stemcells:\n" +
|
||||
"- alias: $1\n" +
|
||||
" version: $2<*>"
|
||||
, // ============
|
||||
"name: blah\n" +
|
||||
"tags:\n <*>"
|
||||
, // ============
|
||||
"name: blah\n" +
|
||||
"update:\n <*>"
|
||||
"update:\n" +
|
||||
" canaries: $1\n" +
|
||||
" max_in_flight: $2\n" +
|
||||
" canary_watch_time: $3\n" +
|
||||
" update_watch_time: $4<*>"
|
||||
, // ============
|
||||
"name: blah\n" +
|
||||
"variables:\n" +
|
||||
"- name: <*>"
|
||||
"- name: $1\n" +
|
||||
" type: $2<*>"
|
||||
// Below completions are suppressed because they are deprecated
|
||||
// , // ============
|
||||
// "name: blah\n" +
|
||||
@@ -203,29 +220,32 @@ public class BoshEditorTest {
|
||||
}
|
||||
|
||||
@Test public void stemcellCompletions() throws Exception {
|
||||
harness.getServer().enableSnippets(false);
|
||||
Editor editor = harness.newEditor(
|
||||
"stemcells:\n" +
|
||||
"- <*>"
|
||||
);
|
||||
editor.assertCompletions(
|
||||
editor.assertCompletions(PLAIN_COMPLETION,
|
||||
"stemcells:\n" +
|
||||
"- alias: $1\n" +
|
||||
" version: $2<*>"
|
||||
, // ==========
|
||||
"stemcells:\n" +
|
||||
"- alias: <*>"
|
||||
, // ==========
|
||||
"stemcells:\n" +
|
||||
"- name: <*>"
|
||||
, // ==========
|
||||
"stemcells:\n" +
|
||||
"- os: <*>"
|
||||
, // ==========
|
||||
"stemcells:\n" +
|
||||
"- version: <*>"
|
||||
);
|
||||
|
||||
editor = harness.newEditor(
|
||||
"stemcells:\n" +
|
||||
"- alias<*>"
|
||||
"- alias: blah\n" +
|
||||
" <*>"
|
||||
);
|
||||
editor.assertContextualCompletions(PLAIN_COMPLETION,
|
||||
"<*>"
|
||||
, // =>
|
||||
"name: <*>",
|
||||
"os: <*>",
|
||||
"version: <*>"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Test public void stemcellReconciling() throws Exception {
|
||||
@@ -1636,37 +1656,6 @@ public class BoshEditorTest {
|
||||
" stemcell: $16\n" +
|
||||
" networks:\n" +
|
||||
" - name: $17<*>"
|
||||
, // ------------------
|
||||
"instance_groups:\n" +
|
||||
"- name: $1\n" +
|
||||
" azs:\n" +
|
||||
" - $2\n" +
|
||||
" instances: $3\n" +
|
||||
" jobs:\n" +
|
||||
" - name: $4\n" +
|
||||
" release: $5\n" +
|
||||
" vm_type: $6\n" +
|
||||
" stemcell: $7\n" +
|
||||
" networks:\n" +
|
||||
" - name: $8<*>"
|
||||
, // ----------------
|
||||
"releases:\n" +
|
||||
"- name: $1\n" +
|
||||
" version: $2<*>"
|
||||
, // ----------------
|
||||
"stemcells:\n" +
|
||||
"- alias: $1\n" +
|
||||
" version: $2<*>"
|
||||
, // ----------------
|
||||
"update:\n" +
|
||||
" canaries: $1\n" +
|
||||
" max_in_flight: $2\n" +
|
||||
" canary_watch_time: $3\n" +
|
||||
" update_watch_time: $4<*>"
|
||||
, // -----------------
|
||||
"variables:\n" +
|
||||
"- name: $1\n" +
|
||||
" type: $2<*>"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1678,14 +1667,16 @@ public class BoshEditorTest {
|
||||
"<*>"
|
||||
);
|
||||
|
||||
editor.assertCompletionLabels(SNIPPET_COMPLETION,
|
||||
editor.assertCompletionLabels(
|
||||
//"BoshDeploymentManifest Snippet",
|
||||
"instance_groups Snippet",
|
||||
"instance_groups",
|
||||
// "releases Snippet",
|
||||
// "stemcells Snippet"
|
||||
"update Snippet",
|
||||
"variables Snippet",
|
||||
"- Stemcell Snippet"
|
||||
"tags",
|
||||
"update",
|
||||
"variables",
|
||||
"- Stemcell Snippet",
|
||||
"- alias"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1697,14 +1688,14 @@ public class BoshEditorTest {
|
||||
"- name: blah\n" +
|
||||
" <*>"
|
||||
);
|
||||
editor.assertContextualCompletions(c -> c.getLabel().equals("jobs Snippet"),
|
||||
editor.assertContextualCompletions(c -> c.getLabel().equals("jobs"),
|
||||
"jo<*>"
|
||||
, // ------
|
||||
"jobs:\n" +
|
||||
" - name: $1\n" +
|
||||
" release: $2<*>"
|
||||
);
|
||||
editor.assertCompletionWithLabel("jobs Snippet",
|
||||
editor.assertCompletionWithLabel("jobs",
|
||||
"instance_groups:\n" +
|
||||
"- name: blah\n" +
|
||||
" jobs:\n" +
|
||||
@@ -1721,14 +1712,14 @@ public class BoshEditorTest {
|
||||
"- name: blah\n" +
|
||||
"<*>"
|
||||
);
|
||||
editor.assertCompletionWithLabel("→ jobs Snippet",
|
||||
editor.assertCompletionWithLabel("→ jobs",
|
||||
"instance_groups:\n" +
|
||||
"- name: blah\n" +
|
||||
" jobs:\n" +
|
||||
" - name: $1\n" +
|
||||
" release: $2<*>"
|
||||
);
|
||||
editor.assertContextualCompletions(c -> c.getLabel().equals("→ jobs Snippet"),
|
||||
editor.assertContextualCompletions(c -> c.getLabel().equals("→ jobs"),
|
||||
"jo<*>"
|
||||
, // ------
|
||||
" jobs:\n" +
|
||||
@@ -1746,7 +1737,7 @@ public class BoshEditorTest {
|
||||
" type: aaa\n" +
|
||||
"<*>"
|
||||
);
|
||||
editor.assertContextualCompletions(DEDENTED_COMPLETION.and(SNIPPET_COMPLETION),
|
||||
editor.assertContextualCompletions(DEDENTED_COMPLETION,
|
||||
" <*>"
|
||||
, // ==>
|
||||
"instance_groups:\n" +
|
||||
@@ -1770,6 +1761,9 @@ public class BoshEditorTest {
|
||||
"- alias: $1\n" +
|
||||
" version: $2<*>"
|
||||
, //========
|
||||
"tags:\n" +
|
||||
" <*>"
|
||||
, //========
|
||||
"update:\n" +
|
||||
" canaries: $1\n" +
|
||||
" max_in_flight: $2\n" +
|
||||
@@ -1778,6 +1772,8 @@ public class BoshEditorTest {
|
||||
, //========
|
||||
"- name: $1\n" +
|
||||
" type: $2<*>"
|
||||
, //========
|
||||
"- name: <*>"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1794,19 +1790,34 @@ public class BoshEditorTest {
|
||||
" <*>"
|
||||
, //==>
|
||||
"instance_groups:\n" +
|
||||
"- name: <*>"
|
||||
"- name: $1\n" +
|
||||
" azs:\n" +
|
||||
" - $2\n" +
|
||||
" instances: $3\n" +
|
||||
" jobs:\n" +
|
||||
" - name: $4\n" +
|
||||
" release: $5\n" +
|
||||
" vm_type: $6\n" +
|
||||
" stemcell: $7\n" +
|
||||
" networks:\n" +
|
||||
" - name: $8<*>"
|
||||
, //----
|
||||
"releases:\n" +
|
||||
"- name: <*>"
|
||||
"- name: $1\n" +
|
||||
" version: $2<*>"
|
||||
, //----
|
||||
"stemcells:\n" +
|
||||
"- <*>"
|
||||
"- alias: $1\n" +
|
||||
" version: $2<*>"
|
||||
, //---
|
||||
"tags:\n" +
|
||||
" <*>"
|
||||
, //---
|
||||
"update:\n" +
|
||||
" <*>"
|
||||
" canaries: $1\n" +
|
||||
" max_in_flight: $2\n" +
|
||||
" canary_watch_time: $3\n" +
|
||||
" update_watch_time: $4<*>"
|
||||
, //---
|
||||
"- name: <*>"
|
||||
);
|
||||
@@ -1823,7 +1834,8 @@ public class BoshEditorTest {
|
||||
"jo<*>"
|
||||
, // ==>
|
||||
" jobs:\n" +
|
||||
" - <*>"
|
||||
" - name: $1\n" +
|
||||
" release: $2<*>"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2121,9 +2133,6 @@ public class BoshEditorTest {
|
||||
editor.assertContextualCompletions(PLAIN_COMPLETION,
|
||||
"<*>"
|
||||
, // =>
|
||||
"subnets:\n" + //non-snippet
|
||||
" - <*>"
|
||||
,
|
||||
"subnets:\n" + //snippet
|
||||
" - range: $1\n" +
|
||||
" gateway: $2<*>"
|
||||
|
||||
@@ -12,7 +12,8 @@ package org.springframework.ide.vscode.commons.languageserver.util;
|
||||
|
||||
public class SnippetBuilder {
|
||||
|
||||
private int nextPlaceHolderId = 1;
|
||||
private static final int FIRST_PLACE_HOLDER_ID = 1;
|
||||
private int nextPlaceHolderId = FIRST_PLACE_HOLDER_ID;
|
||||
private StringBuilder buf = new StringBuilder();
|
||||
|
||||
public SnippetBuilder text(String text) {
|
||||
@@ -43,7 +44,14 @@ public class SnippetBuilder {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return buf.toString();
|
||||
String str = buf.toString();
|
||||
if (getPlaceholderCount()==1 ) {
|
||||
String placeHolder = createPlaceHolder(FIRST_PLACE_HOLDER_ID);
|
||||
if (str.endsWith(placeHolder)) {
|
||||
str = str.substring(0, str.length()-placeHolder.length());
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public void newline(int indent) {
|
||||
|
||||
@@ -101,7 +101,6 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
|
||||
String query = getPrefix(doc, node, offset);
|
||||
List<ICompletionProposal> completions = getValueCompletions(doc, node, offset, query);
|
||||
if (completions.isEmpty()) {
|
||||
completions = getKeyCompletions(doc, node, offset, query);
|
||||
TypeBasedSnippetProvider snippetProvider = typeUtil.getSnippetProvider();
|
||||
if (snippetProvider!=null) {
|
||||
Collection<Snippet> snippets = snippetProvider.getSnippets(type);
|
||||
@@ -110,20 +109,12 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
|
||||
String snippetName = snippet.getName();
|
||||
double score = FuzzyMatcher.matchScore(query, snippetName);
|
||||
if (score!=0.0 && snippet.isApplicable(getSchemaContext())) {
|
||||
DocumentEdits edits = new DocumentEdits(doc.getDocument());
|
||||
int start = offset - query.length();
|
||||
edits.delete(start, query);
|
||||
int referenceIndent = doc.getColumn(start);
|
||||
boolean needsSpace = start > 0 && !Character.isWhitespace(doc.getChar(start-1));
|
||||
if (needsSpace) {
|
||||
referenceIndent++;
|
||||
edits.insert(start, " ");
|
||||
}
|
||||
edits.insert(start, indenter.applyIndentation(snippet.getSnippet(), referenceIndent));
|
||||
DocumentEdits edits = createEditFromSnippet(doc, node, offset, query, indenter, snippet);
|
||||
completions.add(completionFactory().valueProposal(snippetName, query, snippetName, type, null, score, edits, typeUtil));
|
||||
}
|
||||
}
|
||||
}
|
||||
completions.addAll(getKeyCompletions(doc, node, offset, query));
|
||||
}
|
||||
if (typeUtil.isSequencable(type)) {
|
||||
completions = new ArrayList<>(completions);
|
||||
@@ -132,6 +123,26 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
|
||||
return completions;
|
||||
}
|
||||
|
||||
private DocumentEdits createEditFromSnippet(YamlDocument doc, SNode node, int offset, String query, YamlIndentUtil indenter,
|
||||
Snippet _snippet) throws Exception {
|
||||
DocumentEdits edits = new DocumentEdits(doc.getDocument());
|
||||
int start = offset - query.length();
|
||||
edits.delete(start, query);
|
||||
int referenceIndent = doc.getColumn(start);
|
||||
|
||||
boolean needNewline = node.getNodeType()==SNodeType.KEY;
|
||||
String snippet = _snippet.getSnippet();
|
||||
if (needNewline) {
|
||||
snippet = "\n"+snippet;
|
||||
referenceIndent = YamlIndentUtil.getNewChildKeyIndent(node);
|
||||
} else if (start > 0 && !Character.isWhitespace(doc.getChar(start-1))) {
|
||||
referenceIndent++;
|
||||
edits.insert(start, " ");
|
||||
}
|
||||
edits.insert(start, indenter.applyIndentation(snippet, referenceIndent));
|
||||
return edits;
|
||||
}
|
||||
|
||||
public List<ICompletionProposal> getKeyCompletions(YamlDocument doc, SNode node, int offset, String query) throws Exception {
|
||||
int queryOffset = offset - query.length();
|
||||
DynamicSchemaContext dynamicCtxt = getSchemaContext();
|
||||
@@ -151,24 +162,33 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
|
||||
String name = p.getName();
|
||||
double score = FuzzyMatcher.matchScore(query, name);
|
||||
if (score!=0) {
|
||||
DocumentEdits edits = new DocumentEdits(doc.getDocument());
|
||||
YType YType = p.getType();
|
||||
edits.delete(queryOffset, query);
|
||||
int referenceIndent = doc.getColumn(queryOffset);
|
||||
boolean needNewline = node.getNodeType()==SNodeType.KEY;
|
||||
StringBuilder snippet = new StringBuilder();
|
||||
if (needNewline) {
|
||||
snippet.append("\n");
|
||||
referenceIndent = YamlIndentUtil.getNewChildKeyIndent(node);
|
||||
} else if (queryOffset>0 && !Character.isWhitespace(doc.getChar(queryOffset-1))) {
|
||||
//See https://www.pivotaltracker.com/story/show/137722057
|
||||
snippet.append(" ");
|
||||
referenceIndent++;
|
||||
TypeBasedSnippetProvider snippetProvider = typeUtil.getSnippetProvider();
|
||||
DocumentEdits edits;
|
||||
if (snippetProvider!=null) {
|
||||
// Generate edits from snippet
|
||||
Snippet snippet = snippetProvider.getSnippet(type, p);
|
||||
edits = createEditFromSnippet(doc, node, offset, query, indenter, snippet);
|
||||
} else {
|
||||
//Generate edits the old-fashioned way
|
||||
edits = new DocumentEdits(doc.getDocument());
|
||||
YType YType = p.getType();
|
||||
edits.delete(queryOffset, query);
|
||||
int referenceIndent = doc.getColumn(queryOffset);
|
||||
boolean needNewline = node.getNodeType()==SNodeType.KEY;
|
||||
StringBuilder snippet = new StringBuilder();
|
||||
if (needNewline) {
|
||||
snippet.append("\n");
|
||||
referenceIndent = YamlIndentUtil.getNewChildKeyIndent(node);
|
||||
} else if (queryOffset>0 && !Character.isWhitespace(doc.getChar(queryOffset-1))) {
|
||||
//See https://www.pivotaltracker.com/story/show/137722057
|
||||
snippet.append(" ");
|
||||
referenceIndent++;
|
||||
}
|
||||
snippet.append(p.getName());
|
||||
snippet.append(":");
|
||||
snippet.append(appendTextFor(YType));
|
||||
edits.insert(queryOffset, indenter.applyIndentation(snippet.toString(), referenceIndent));
|
||||
}
|
||||
snippet.append(p.getName());
|
||||
snippet.append(":");
|
||||
snippet.append(appendTextFor(YType));
|
||||
edits.insert(queryOffset, indenter.applyIndentation(snippet.toString(), referenceIndent));
|
||||
ICompletionProposal completion = completionFactory().beanProperty(doc.getDocument(),
|
||||
contextPath.toPropString(), getType(),
|
||||
query, p, score, edits, typeUtil);
|
||||
|
||||
@@ -13,6 +13,7 @@ package org.springframework.ide.vscode.commons.yaml.snippet;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty;
|
||||
|
||||
public class Snippet {
|
||||
|
||||
|
||||
@@ -13,9 +13,11 @@ package org.springframework.ide.vscode.commons.yaml.snippet;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YType;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty;
|
||||
|
||||
public interface TypeBasedSnippetProvider {
|
||||
|
||||
Collection<Snippet> getSnippets(YType contextType);
|
||||
Snippet getSnippet(YType contextType, YTypedProperty p);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user