PT 150711216 - Initial implementation

Includes basic completion of a request mapping snippet
This commit is contained in:
nsingh
2017-09-20 13:27:28 -07:00
parent ea046efae8
commit 0a47b7c158
6 changed files with 203 additions and 32 deletions

View File

@@ -13,6 +13,7 @@ package org.springframework.ide.vscode.boot.java;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.lsp4j.CompletionItemKind;
import org.springframework.ide.vscode.boot.java.beans.BeansSymbolProvider;
import org.springframework.ide.vscode.boot.java.beans.ComponentSymbolProvider;
import org.springframework.ide.vscode.boot.java.handlers.BootJavaCodeLensEngine;
@@ -29,6 +30,9 @@ import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
import org.springframework.ide.vscode.boot.java.requestmapping.RequestMappingHoverProvider;
import org.springframework.ide.vscode.boot.java.requestmapping.RequestMappingSymbolProvider;
import org.springframework.ide.vscode.boot.java.scope.ScopeCompletionProcessor;
import org.springframework.ide.vscode.boot.java.snippets.JavaSnippet;
import org.springframework.ide.vscode.boot.java.snippets.JavaSnippetManager;
import org.springframework.ide.vscode.boot.java.snippets.JavaSnippetContext;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexer;
import org.springframework.ide.vscode.boot.java.value.ValueCompletionProcessor;
import org.springframework.ide.vscode.boot.java.value.ValueHoverProvider;
@@ -52,6 +56,8 @@ import org.springframework.ide.vscode.commons.maven.MavenCore;
import org.springframework.ide.vscode.commons.maven.MavenProjectFinderStrategy;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import com.google.common.collect.ImmutableList;
/**
* Language Server for Spring Boot Application Properties files
*
@@ -109,7 +115,22 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
providers.put(org.springframework.ide.vscode.boot.java.scope.Constants.SPRING_SCOPE, new ScopeCompletionProcessor());
providers.put(org.springframework.ide.vscode.boot.java.value.Constants.SPRING_VALUE, new ValueCompletionProcessor(indexProvider));
return new BootJavaCompletionEngine(javaProjectFinder, providers);
JavaSnippetManager snippetManager = new JavaSnippetManager(this::createSnippetBuilder);
snippetManager.add(new JavaSnippet(
"RequestMapping method",
JavaSnippetContext.BOOT_MEMBERS,
CompletionItemKind.Method,
ImmutableList.of(
"org.springframework.web.bind.annotation.RequestMapping",
"org.springframework.web.bind.annotation.RequestMethod",
"org.springframework.web.bind.annotation.RequestParam"
),
"@RequestMapping(value=\"${path}\", method=RequestMethod.${GET})\n" +
"public ${SomeData} ${requestMethodName}(@RequestParam ${String} ${param}) {\n" +
" return new ${SomeData}(${cursor});\n" +
"}\n"
));
return new BootJavaCompletionEngine(javaProjectFinder, providers, snippetManager);
}
protected HoverHandler createHoverHandler(JavaProjectFinder javaProjectFinder) {

View File

@@ -11,6 +11,7 @@
package org.springframework.ide.vscode.boot.java.handlers;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
@@ -24,6 +25,7 @@ import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.springframework.ide.vscode.boot.java.snippets.JavaSnippetManager;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
@@ -38,10 +40,12 @@ public class BootJavaCompletionEngine implements ICompletionEngine {
private JavaProjectFinder projectFinder;
private Map<String, CompletionProvider> completionProviders;
private JavaSnippetManager snippets;
public BootJavaCompletionEngine(JavaProjectFinder projectFinder, Map<String, CompletionProvider> specificProviders) {
public BootJavaCompletionEngine(JavaProjectFinder projectFinder, Map<String, CompletionProvider> specificProviders, JavaSnippetManager snippets) {
this.projectFinder = projectFinder;
this.completionProviders = specificProviders;
this.snippets = snippets;
}
@Override
@@ -69,7 +73,10 @@ public class BootJavaCompletionEngine implements ICompletionEngine {
if (node != null) {
System.out.println("AST node found: " + node.getClass().getName());
return collectCompletionsForAnnotations(node, offset, document);
Collection<ICompletionProposal> completions = new ArrayList<ICompletionProposal>();
completions.addAll(collectCompletionsForAnnotations(node, offset, document));
completions.addAll(snippets.getCompletions(document, offset, node));
return completions;
}
return Collections.emptyList();

View File

@@ -18,34 +18,60 @@ import org.springframework.ide.vscode.commons.util.text.IDocument;
public class SimpleCompletionFactory {
public ICompletionProposal simpleProposal(IDocument doc, int offset, String query, CompletionItemKind kind, String value, String detail, Renderable info) {
public static class SimpleProposal implements ICompletionProposal{
private DocumentEdits edits;
private CompletionItemKind kind;
private Renderable info;
private String detail;
private String label;
public SimpleProposal(DocumentEdits edits, CompletionItemKind kind, Renderable info,
String detail, String label) {
this.edits = edits;
this.kind = kind;
this.info = info;
this.detail = detail;
this.label = label;
}
public SimpleProposal setLabel(String label) {
this.label = label;
return this;
}
@Override
public String getLabel() {
return label;
}
@Override
public DocumentEdits getTextEdit() {
return edits;
}
@Override
public CompletionItemKind getKind() {
return kind;
}
@Override
public Renderable getDocumentation() {
return info;
}
@Override
public String getDetail() {
return detail;
}
}
public static SimpleProposal simpleProposal(IDocument doc, int offset, String query, CompletionItemKind kind, String value, String detail, Renderable info) {
DocumentEdits edits = new DocumentEdits(doc);
edits.replace(offset-query.length(), offset, value);
return new ICompletionProposal() {
@Override
public DocumentEdits getTextEdit() {
return edits;
}
@Override
public String getLabel() {
return value;
}
@Override
public CompletionItemKind getKind() {
return kind;
}
@Override
public Renderable getDocumentation() {
return info;
}
@Override
public String getDetail() {
return detail;
}
};
return new SimpleProposal(edits, kind, info, detail, value);
}
}

View File

@@ -10,8 +10,59 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.snippets;
import java.util.List;
import java.util.Optional;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.lsp4j.CompletionItemKind;
import org.springframework.ide.vscode.boot.java.handlers.SimpleCompletionFactory;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.languageserver.util.SnippetBuilder;
import org.springframework.ide.vscode.commons.util.Renderables;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import com.google.common.base.Supplier;
public class JavaSnippet {
private SnippetContext context;
private JavaSnippetContext context;
private String name;
private String template;
private List<String> imports;
private CompletionItemKind kind;
public JavaSnippet(String name, JavaSnippetContext context, CompletionItemKind kind, List<String> imports,
String template) {
super();
this.context = context;
this.name = name;
this.template = template;
this.imports = imports;
this.kind = kind;
}
public Optional<ICompletionProposal> generateCompletion(Supplier<SnippetBuilder> snippetBuilderFactory,
IDocument doc, int offset, ASTNode node, String query) {
if (context.appliesTo(node)) {
return Optional.of(
SimpleCompletionFactory.simpleProposal(doc,
offset,
query,
kind, template, "Snippet", Renderables.NO_DESCRIPTION
).setLabel(name)
);
}
return Optional.empty();
}
public String getName() {
return this.name;
}
}

View File

@@ -11,7 +11,10 @@
package org.springframework.ide.vscode.boot.java.snippets;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.TypeDeclaration;
public interface JavaSnippetContext {
JavaSnippetContext BOOT_MEMBERS = (node) -> node instanceof TypeDeclaration;
public interface SnippetContext {
boolean appliesTo(ASTNode node);
}

View File

@@ -0,0 +1,63 @@
/*******************************************************************************
* Copyright (c) 2017 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.snippets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.jdt.core.dom.ASTNode;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.languageserver.util.PrefixFinder;
import org.springframework.ide.vscode.commons.languageserver.util.SnippetBuilder;
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import com.google.common.base.Supplier;
public class JavaSnippetManager {
private List<JavaSnippet> snippets = new ArrayList<>();
private Supplier<SnippetBuilder> snippetBuilderFactory;
private static PrefixFinder PREFIX_FINDER = new PrefixFinder() {
@Override
protected boolean isPrefixChar(char c) {
return Character.isJavaIdentifierPart(c);
}
};
public JavaSnippetManager(Supplier<SnippetBuilder> snippetBuilderFactory) {
this.snippetBuilderFactory = snippetBuilderFactory;
}
public void add(JavaSnippet javaSnippet) {
snippets.add(javaSnippet);
}
public Collection<ICompletionProposal> getCompletions(IDocument doc, int offset, ASTNode node) {
Collection<ICompletionProposal> completions = new ArrayList<>();
String query = PREFIX_FINDER.getPrefix(doc, offset);
for (JavaSnippet javaSnippet : snippets) {
if (FuzzyMatcher.matchScore(query, javaSnippet.getName()) != 0) {
javaSnippet.generateCompletion(snippetBuilderFactory, doc, offset, node, query)
.ifPresent((completion) -> completions.add(completion));
}
}
return completions;
}
}