Add support to include imports through additional edits
This commit is contained in:
@@ -15,11 +15,9 @@ 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.DocumentRegion;
|
||||
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;
|
||||
|
||||
@@ -46,15 +44,14 @@ public class JavaSnippet {
|
||||
}
|
||||
|
||||
public Optional<ICompletionProposal> generateCompletion(Supplier<SnippetBuilder> snippetBuilderFactory,
|
||||
IDocument doc, int offset, ASTNode node, String query) {
|
||||
DocumentRegion query, ASTNode node) {
|
||||
|
||||
if (context.appliesTo(node)) {
|
||||
return Optional.of(
|
||||
SimpleCompletionFactory.simpleProposal(doc,
|
||||
offset,
|
||||
new JavaSnippetCompletion(snippetBuilderFactory,
|
||||
query,
|
||||
kind, template, "Snippet", Renderables.NO_DESCRIPTION
|
||||
).setLabel(name)
|
||||
this
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -65,4 +62,16 @@ public class JavaSnippet {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getTemplate() {
|
||||
return this.template;
|
||||
}
|
||||
|
||||
public List<String> getImports() {
|
||||
return this.imports;
|
||||
}
|
||||
|
||||
public CompletionItemKind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*******************************************************************************
|
||||
* 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 org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SnippetBuilder;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
public class JavaSnippetBuilder{
|
||||
|
||||
private Supplier<SnippetBuilder> snippetBuilderFactory;
|
||||
|
||||
public JavaSnippetBuilder(Supplier<SnippetBuilder> snippetBuilderFactory) {
|
||||
this.snippetBuilderFactory = snippetBuilderFactory;
|
||||
}
|
||||
|
||||
public DocumentEdits createEdit(DocumentRegion query, String template) {
|
||||
DocumentEdits edit = new DocumentEdits(query.getDocument());
|
||||
|
||||
edit.replace(query.getStart(), query.getEnd(), template);
|
||||
return edit;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*******************************************************************************
|
||||
* 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.Optional;
|
||||
|
||||
import org.eclipse.lsp4j.CompletionItemKind;
|
||||
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.util.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SnippetBuilder;
|
||||
import org.springframework.ide.vscode.commons.util.Renderable;
|
||||
import org.springframework.ide.vscode.commons.util.Renderables;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
public class JavaSnippetCompletion implements ICompletionProposal{
|
||||
|
||||
private DocumentRegion query;
|
||||
private JavaSnippet javaSnippet;
|
||||
private Supplier<SnippetBuilder> snippetBuilderFactory;
|
||||
|
||||
public JavaSnippetCompletion(Supplier<SnippetBuilder> snippetBuilderFactory, DocumentRegion query, JavaSnippet javaSnippet) {
|
||||
this.snippetBuilderFactory = snippetBuilderFactory;
|
||||
this.query = query;
|
||||
this.javaSnippet = javaSnippet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return javaSnippet.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionItemKind getKind() {
|
||||
return javaSnippet.getKind();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocumentEdits getTextEdit() {
|
||||
return new JavaSnippetBuilder(snippetBuilderFactory).createEdit(query, javaSnippet.getTemplate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDetail() {
|
||||
return "Snippet";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Renderable getDocumentation() {
|
||||
return Renderables.NO_DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DocumentEdits> getAdditionalEdit() {
|
||||
DocumentEdits edit = new DocumentEdits(query.getDocument());
|
||||
edit.insert(0, "import my.stuff;\n");
|
||||
return Optional.of(edit );
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ 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.DocumentRegion;
|
||||
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;
|
||||
@@ -48,11 +49,11 @@ public class JavaSnippetManager {
|
||||
public Collection<ICompletionProposal> getCompletions(IDocument doc, int offset, ASTNode node) {
|
||||
Collection<ICompletionProposal> completions = new ArrayList<>();
|
||||
|
||||
String query = PREFIX_FINDER.getPrefix(doc, offset);
|
||||
DocumentRegion query = PREFIX_FINDER.getPrefixRegion(doc, offset);
|
||||
|
||||
for (JavaSnippet javaSnippet : snippets) {
|
||||
if (FuzzyMatcher.matchScore(query, javaSnippet.getName()) != 0) {
|
||||
javaSnippet.generateCompletion(snippetBuilderFactory, doc, offset, node, query)
|
||||
if (FuzzyMatcher.matchScore(query.toString(), javaSnippet.getName()) != 0) {
|
||||
javaSnippet.generateCompletion(snippetBuilderFactory, query, node)
|
||||
.ifPresent((completion) -> completions.add(completion));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
package org.springframework.ide.vscode.commons.languageserver.completion;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.lsp4j.CompletionItemKind;
|
||||
import org.springframework.ide.vscode.commons.util.Renderable;
|
||||
|
||||
@@ -23,6 +25,7 @@ public interface ICompletionProposal {
|
||||
String getLabel();
|
||||
CompletionItemKind getKind();
|
||||
DocumentEdits getTextEdit();
|
||||
default Optional<DocumentEdits> getAdditionalEdit() { return Optional.empty(); }
|
||||
|
||||
String getDetail();
|
||||
Renderable getDocumentation();
|
||||
|
||||
@@ -15,6 +15,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -35,6 +36,8 @@ import org.springframework.ide.vscode.commons.util.Renderable;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
@@ -174,7 +177,19 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
|
||||
|
||||
private static void resolveItem(TextDocument doc, ICompletionProposal completion, CompletionItem item) throws Exception {
|
||||
item.setDocumentation(toMarkdown(completion.getDocumentation()));
|
||||
adaptEdits(item, doc, completion.getTextEdit());
|
||||
Optional<TextEdit> mainEdit = adaptEdits(doc, completion.getTextEdit());
|
||||
if (mainEdit.isPresent()) {
|
||||
item.setTextEdit(mainEdit.get());
|
||||
item.setInsertTextFormat(InsertTextFormat.Snippet);
|
||||
} else {
|
||||
item.setInsertText("");
|
||||
}
|
||||
|
||||
completion.getAdditionalEdit().ifPresent(edit -> {
|
||||
adaptEdits(doc, edit).ifPresent(extraEdit -> {
|
||||
item.setAdditionalTextEdits(ImmutableList.of(extraEdit));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static String toMarkdown(Renderable r) {
|
||||
@@ -184,24 +199,28 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void adaptEdits(CompletionItem item, TextDocument doc, DocumentEdits edits) throws Exception {
|
||||
TextReplace replaceEdit = edits.asReplacement(doc);
|
||||
if (replaceEdit==null) {
|
||||
//The original edit does nothing.
|
||||
item.setInsertText("");
|
||||
} else {
|
||||
TextDocument newDoc = doc.copy();
|
||||
edits.apply(newDoc);
|
||||
TextEdit vscodeEdit = new TextEdit();
|
||||
vscodeEdit.setRange(doc.toRange(replaceEdit.start, replaceEdit.end-replaceEdit.start));
|
||||
if (Boolean.getBoolean("lsp.completions.indentation.enable")) {
|
||||
vscodeEdit.setNewText(replaceEdit.newText);
|
||||
private static Optional<TextEdit> adaptEdits(TextDocument doc, DocumentEdits edits) {
|
||||
try {
|
||||
TextReplace replaceEdit = edits.asReplacement(doc);
|
||||
if (replaceEdit==null) {
|
||||
//The original edit does nothing.
|
||||
return Optional.empty();
|
||||
} else {
|
||||
vscodeEdit.setNewText(vscodeIndentFix(doc, vscodeEdit.getRange().getStart(), replaceEdit.newText));
|
||||
TextDocument newDoc = doc.copy();
|
||||
edits.apply(newDoc);
|
||||
TextEdit vscodeEdit = new TextEdit();
|
||||
vscodeEdit.setRange(doc.toRange(replaceEdit.start, replaceEdit.end-replaceEdit.start));
|
||||
if (Boolean.getBoolean("lsp.completions.indentation.enable")) {
|
||||
vscodeEdit.setNewText(replaceEdit.newText);
|
||||
} else {
|
||||
vscodeEdit.setNewText(vscodeIndentFix(doc, vscodeEdit.getRange().getStart(), replaceEdit.newText));
|
||||
}
|
||||
//TODO: cursor offset within newText? for now we assume its always at the end.
|
||||
return Optional.of(vscodeEdit);
|
||||
}
|
||||
//TODO: cursor offset within newText? for now we assume its always at the end.
|
||||
item.setTextEdit(vscodeEdit);
|
||||
item.setInsertTextFormat(InsertTextFormat.Snippet);
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 Pivotal, Inc.
|
||||
* Copyright (c) 2015, 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
|
||||
@@ -32,4 +32,9 @@ public abstract class PrefixFinder {
|
||||
return getPrefix(doc, offset, 0);
|
||||
}
|
||||
protected abstract boolean isPrefixChar(char c);
|
||||
|
||||
public DocumentRegion getPrefixRegion(IDocument doc, int offset) {
|
||||
String prefix = getPrefix(doc, offset);
|
||||
return prefix != null ? new DocumentRegion(doc, offset - prefix.length(), offset) : null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user