Skip to content

Commit

Permalink
Introduce new snippet templates with appropriate context
Browse files Browse the repository at this point in the history
Signed-off-by: Hope Hadfield <[email protected]>
  • Loading branch information
hopehadfield authored and rgrunber committed Aug 31, 2023
1 parent 3e36308 commit 5f4bd3b
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -289,29 +289,60 @@ private static List<CompletionItem> getGenericSnippets(SnippetCompletionContext
return Collections.emptyList();
}
int tokenLocation = completionContext.getTokenLocation();
JavaContextType contextType = (JavaContextType) JavaLanguageServerPlugin.getInstance().getTemplateContextRegistry().getContextType(JavaContextType.ID_STATEMENTS);
if (contextType == null) {
return Collections.emptyList();
}
JavaContextType contextType = null;
JavaContextType contextTypeAll = (JavaContextType) JavaLanguageServerPlugin.getInstance().getTemplateContextRegistry().getContextType(JavaContextType.ID_ALL);
ICompilationUnit cu = scc.getCompilationUnit();
IDocument document = new Document(cu.getSource());
DocumentTemplateContext javaContext = contextType.createContext(document, completionContext.getOffset(), completionToken.length, cu);
DocumentTemplateContext javaContext;
DocumentTemplateContext javaContextAll;
Template[] templates = null;
Template[] templatesAll = JavaLanguageServerPlugin.getInstance().getTemplateStore().getTemplates(JavaContextType.ID_ALL);
if ((tokenLocation & CompletionContext.TL_STATEMENT_START) != 0) {
contextType = (JavaContextType) JavaLanguageServerPlugin.getInstance().getTemplateContextRegistry().getContextType(JavaContextType.ID_STATEMENTS);
if (contextType != null) {
javaContext = contextType.createContext(document, completionContext.getOffset(), completionToken.length, cu);
} else {
javaContext = null;
}
templates = JavaLanguageServerPlugin.getInstance().getTemplateStore().getTemplates(JavaContextType.ID_STATEMENTS);
if (contextTypeAll != null) {
javaContextAll = contextTypeAll.createContext(document, completionContext.getOffset(), completionToken.length, cu);
} else {
javaContextAll = null;
}
} else if ((tokenLocation & CompletionContext.TL_MEMBER_START) != 0) {
contextType = (JavaContextType) JavaLanguageServerPlugin.getInstance().getTemplateContextRegistry().getContextType(JavaContextType.ID_MEMBERS);
if (contextType != null) {
javaContext = contextType.createContext(document, completionContext.getOffset(), completionToken.length, cu);
} else {
javaContext = null;
}
templates = JavaLanguageServerPlugin.getInstance().getTemplateStore().getTemplates(JavaContextType.ID_MEMBERS);
if (contextTypeAll != null) {
javaContextAll = contextTypeAll.createContext(document, completionContext.getOffset(), completionToken.length, cu);
} else {
javaContextAll = null;
}
} else {
// We only support statement templates for now.
javaContext = null;
javaContextAll = null;
}

if (templates == null || templates.length == 0) {
if ((javaContext == null && javaContextAll == null) || (templates == null && templatesAll == null) || templates.length == 0) {
return Collections.emptyList();
}

String uri = JDTUtils.toURI(cu);
Template[] availableTemplates = Arrays.stream(templates).filter(t -> javaContext.canEvaluate(t)).toArray(Template[]::new);
Template[] availableTemplatesAll = Arrays.stream(templatesAll).filter(t -> javaContextAll.canEvaluate(t)).toArray(Template[]::new);
List<CompletionProposal> proposals = new ArrayList<>();
for (int i = 0; i < availableTemplates.length; i++) {
Template template = availableTemplates[i];
for (int i = 0; i < availableTemplates.length + availableTemplatesAll.length; i++) {
Template template;
if (i < availableTemplates.length) {
template = availableTemplates[i];
} else {
template = availableTemplatesAll[i - availableTemplates.length];
}
final CompletionItem item = new CompletionItem();
item.setLabel(template.getName());
item.setKind(CompletionItemKind.Snippet);
Expand Down Expand Up @@ -378,7 +409,7 @@ private static boolean isCompletionItemLabelDetailsSupport() {
}

public static String evaluateGenericTemplate(ICompilationUnit cu, CompletionContext completionContext, Template template) {
JavaContextType contextType = (JavaContextType) JavaLanguageServerPlugin.getInstance().getTemplateContextRegistry().getContextType(JavaContextType.ID_STATEMENTS);
JavaContextType contextType = (JavaContextType) JavaLanguageServerPlugin.getInstance().getTemplateContextRegistry().getContextType(template.getContextTypeId());
char[] completionToken = completionContext.getToken();
if (contextType == null || completionToken == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class SnippetUtils {
private static final String MARKDOWN_LANGUAGE = "java";

private static final String TM_SELECTED_TEXT = "\\$TM_SELECTED_TEXT";
private static final String TM_FILENAME_BASE = "\\$TM_FILENAME_BASE";

private SnippetUtils() {
}
Expand All @@ -44,12 +45,14 @@ public static String templateToSnippet(String pattern) {
}

public static Either<String, MarkupContent> beautifyDocument(String raw) {
// remove the list of choices and replace with the first choice (e.g. |public,protected,private| -> public)
String escapedString = raw.replaceAll("\\$\\{\\d\\|(.*?),.*?\\}", "$1");
// remove the placeholder for the plain cursor like: ${0}, ${1:variable}
String escapedString = raw.replaceAll("\\$\\{\\d:?(.*?)\\}", "$1");

escapedString = escapedString.replaceAll("\\$\\{\\d:?(.*?)\\}", "$1");
// Replace the reserved variable with empty string.
// See: https://github.com/eclipse/eclipse.jdt.ls/issues/1220
escapedString = escapedString.replaceAll(TM_SELECTED_TEXT, "");
escapedString = escapedString.replaceAll(TM_FILENAME_BASE, "");

if (JavaLanguageServerPlugin.getPreferencesManager() != null && JavaLanguageServerPlugin.getPreferencesManager().getClientPreferences() != null
&& JavaLanguageServerPlugin.getPreferencesManager().getClientPreferences().isSupportsCompletionDocumentationMarkdown()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,21 @@ public enum CodeSnippetTemplate {
IFELSE(TemplatePreferences.IFELSE_ID, JavaContextType.ID_STATEMENTS, TemplatePreferences.IFELSE_CONTENT, TemplatePreferences.IFELSE_DESCRIPTION),
IFNULL(TemplatePreferences.IFNULL_ID, JavaContextType.ID_STATEMENTS, TemplatePreferences.IFNULL_CONTENT, TemplatePreferences.IFNULL_DESCRIPTION),
IFNOTNULL(TemplatePreferences.IFNOTNULL_ID, JavaContextType.ID_STATEMENTS, TemplatePreferences.IFNOTNULL_CONTENT, TemplatePreferences.IFNOTNULL_DESCRIPTION),

SWITCH(TemplatePreferences.SWITCH_ID, JavaContextType.ID_STATEMENTS, TemplatePreferences.SWITCH_CONTENT, TemplatePreferences.SWITCH_DESCRIPTION),
TRY_CATCH(TemplatePreferences.TRYCATCH_ID, JavaContextType.ID_STATEMENTS, TemplatePreferences.TRYCATCH_CONTENT, TemplatePreferences.TRYCATCH_DESCRIPTION),
TRY_RESOURCES(TemplatePreferences.TRYRESOURCES_ID, JavaContextType.ID_STATEMENTS, TemplatePreferences.TRYRESOURCES_CONTENT, TemplatePreferences.TRYRESOURCES_DESCRIPTION),
CTOR(TemplatePreferences.CTOR_ID, JavaContextType.ID_MEMBERS, TemplatePreferences.CTOR_CONTENT, TemplatePreferences.CTOR_DESCRIPTION),
METHOD(TemplatePreferences.METHOD_ID, JavaContextType.ID_MEMBERS, TemplatePreferences.METHOD_CONTENT, TemplatePreferences.METHOD_DESCRIPTION),
FIELD(TemplatePreferences.FIELD_ID, JavaContextType.ID_MEMBERS, TemplatePreferences.FIELD_CONTENT, TemplatePreferences.FIELD_DESCRIPTION),
MAIN(TemplatePreferences.MAIN_ID, JavaContextType.ID_MEMBERS, TemplatePreferences.MAIN_CONTENT, TemplatePreferences.MAIN_DESCRIPTION),
NEW(TemplatePreferences.NEW_ID, JavaContextType.ID_ALL, TemplatePreferences.NEW_CONTENT, TemplatePreferences.NEW_DESCRIPTION),

// the following snippets are the same as above but with different alias, since users may not easily find them if they come from different IDEs.
SOUT(TemplatePreferences.SOUT_ID, JavaContextType.ID_STATEMENTS, TemplatePreferences.SYSOUT_CONTENT, TemplatePreferences.SYSOUT_DESCRIPTION),
SERR(TemplatePreferences.SERR_ID, JavaContextType.ID_STATEMENTS, TemplatePreferences.SYSERR_CONTENT, TemplatePreferences.SYSERR_DESCRIPTION),
SOUTM(TemplatePreferences.SOUTM_ID, JavaContextType.ID_STATEMENTS, TemplatePreferences.SYSTRACE_CONTENT, TemplatePreferences.SYSTRACE_DESCRIPTION),
ITER(TemplatePreferences.ITER_ID, JavaContextType.ID_STATEMENTS, TemplatePreferences.FOREACH_CONTENT, TemplatePreferences.FOREACH_DESCRIPTION);
ITER(TemplatePreferences.ITER_ID, JavaContextType.ID_STATEMENTS, TemplatePreferences.FOREACH_CONTENT, TemplatePreferences.FOREACH_DESCRIPTION),
PSVM(TemplatePreferences.PSVM_ID, JavaContextType.ID_MEMBERS, TemplatePreferences.MAIN_CONTENT, TemplatePreferences.MAIN_DESCRIPTION);
//@formatter:on

private final String templateId;
Expand Down Expand Up @@ -75,6 +84,15 @@ class TemplatePreferences {
public static final String IFELSE_ID = "org.eclipse.jdt.ls.templates.ifelse";
public static final String IFNULL_ID = "org.eclipse.jdt.ls.templates.ifnull";
public static final String IFNOTNULL_ID = "org.eclipse.jdt.ls.templates.ifnotnull";
public static final String SWITCH_ID = "org.eclipse.jdt.ls.templates.switch";
public static final String TRYCATCH_ID = "org.eclipse.jdt.ls.templates.trycatch";
public static final String TRYRESOURCES_ID = "org.eclipse.jdt.ls.templates.tryresources";
public static final String MAIN_ID = "org.eclipse.jdt.ls.templates.main";
public static final String PSVM_ID = "org.eclipse.jdt.ls.templates.psvm";
public static final String CTOR_ID = "org.eclipse.jdt.ls.templates.ctor";
public static final String METHOD_ID = "org.eclipse.jdt.ls.templates.method";
public static final String NEW_ID = "org.eclipse.jdt.ls.templates.new";
public static final String FIELD_ID = "org.eclipse.jdt.ls.templates.field";

// DefaultContents
public static final String SYSOUT_CONTENT = "System.out.println($${0});";
Expand All @@ -88,6 +106,14 @@ class TemplatePreferences {
public static final String IFELSE_CONTENT = "if ($${1:${condition:var(boolean)}}) {\n" + "\t$${2}\n" + "} else {\n" + "\t$${0}\n" + "}";
public static final String IFNULL_CONTENT = "if ($${1:${name:var}} == null) {\n" + "\t$$TM_SELECTED_TEXT$${0}\n" + "}";
public static final String IFNOTNULL_CONTENT = "if ($${1:${name:var}} != null) {\n" + "\t$$TM_SELECTED_TEXT$${0}\n" + "}";
public static final String SWITCH_CONTENT = "switch ($${1:${key:var}}) {\n" + "\tcase $${2:value}:\n" + "\t\t$${0}\n" + "\t\tbreak;\n\n" + "\tdefault:\n" + "\t\tbreak;\n" + "}";
public static final String TRYCATCH_CONTENT = "try {\n" + "\t$$TM_SELECTED_TEXT$${1}\n" + "} catch ($${2:Exception} $${3:e}) {\n" + "\t$${0}// TODO: handle exception\n" + "}";
public static final String TRYRESOURCES_CONTENT = "try ($${1}) {\n" + "\t$$TM_SELECTED_TEXT$${2}\n" + "} catch ($${3:Exception} $${4:e}) {\n" + "\t$${0}// TODO: handle exception\n" + "}";
public static final String MAIN_CONTENT = "public static void main(String[] args) {\n" + "\t$${0}\n" + "}";
public static final String CTOR_CONTENT = "$${1|public,protected,private|} $${2:$$TM_FILENAME_BASE}($${3}) {\n" + "\t$${4:super();}$${0}\n" + "}";
public static final String METHOD_CONTENT = "$${1|public,protected,private|}$${2| , static |}$${3:void} $${4:name}($${5}) {\n" + "\t$${0}\n" + "}";
public static final String NEW_CONTENT = "$${1:Object} $${2:foo} = new $${1}($${3});\n" + "$${0}";
public static final String FIELD_CONTENT = "$${1|public,protected,private|} $${2:String} $${3:name};";

// Descriptions
public static final String SYSOUT_DESCRIPTION = "print to standard out";
Expand All @@ -101,4 +127,12 @@ class TemplatePreferences {
public static final String IFELSE_DESCRIPTION = "if-else statement";
public static final String IFNULL_DESCRIPTION = "if statement checking for null";
public static final String IFNOTNULL_DESCRIPTION = "if statement checking for not null";
public static final String SWITCH_DESCRIPTION = "switch statement";
public static final String TRYCATCH_DESCRIPTION = "try/catch block";
public static final String TRYRESOURCES_DESCRIPTION = "try/catch block with resources";
public static final String MAIN_DESCRIPTION = "public static main method";
public static final String CTOR_DESCRIPTION = "constructor";
public static final String METHOD_DESCRIPTION = "method";
public static final String NEW_DESCRIPTION = "create new object";
public static final String FIELD_DESCRIPTION = "field";
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ public class JavaContextType extends AbstractJavaContextTypeCore {
*/
public static final String ID_MODULE = "module"; //$NON-NLS-1$

public JavaContextType() {
setId(ID_STATEMENTS);
setName(ID_STATEMENTS);
public JavaContextType(String contextType) {
setId(contextType);
setName(contextType);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,17 @@
public class JavaContextTypeRegistry extends ContextTypeRegistry {

public JavaContextTypeRegistry() {
JavaContextType contextType = new JavaContextType();
contextType.initializeContextTypeResolvers();
addContextType(contextType);
JavaContextType contextTypeStatements = new JavaContextType(JavaContextType.ID_STATEMENTS);
contextTypeStatements.initializeContextTypeResolvers();
addContextType(contextTypeStatements);

JavaContextType contextTypeMembers = new JavaContextType(JavaContextType.ID_MEMBERS);
contextTypeMembers.initializeContextTypeResolvers();
addContextType(contextTypeMembers);

JavaContextType contextTypeAll = new JavaContextType(JavaContextType.ID_ALL);
contextTypeAll.initializeContextTypeResolvers();
addContextType(contextTypeAll);

JavaPostfixContextType postfixContextType = new JavaPostfixContextType();
postfixContextType.initializeContextTypeResolvers();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1348,7 +1348,7 @@ public void testSnippet_nested_inner_interface() throws JavaModelException {
CompletionList list = requestCompletions(unit, "package org.sample;\npublic interface Test {}\npublic interface InnerTest{\n");

assertNotNull(list);
List<CompletionItem> items = new ArrayList<>(list.getItems());
List<CompletionItem> items = list.getItems().stream().filter(item -> item.getSortText() != null).collect(Collectors.toCollection(ArrayList::new));
assertFalse(items.isEmpty());
items.sort((i1, i2) -> (i1.getSortText().compareTo(i2.getSortText())));

Expand Down Expand Up @@ -1473,7 +1473,7 @@ public void testSnippet_nested_inner_class() throws JavaModelException {
CompletionList list = requestCompletions(unit, "package org.sample;\npublic class Test {}\npublic class InnerTest{\n");

assertNotNull(list);
List<CompletionItem> items = new ArrayList<>(list.getItems());
List<CompletionItem> items = list.getItems().stream().filter(item -> item.getSortText() != null).collect(Collectors.toCollection(ArrayList::new));
assertFalse(items.isEmpty());
items.sort((i1, i2) -> (i1.getSortText().compareTo(i2.getSortText())));

Expand Down

0 comments on commit 5f4bd3b

Please sign in to comment.