mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
LSP-561 [lsp] Support live templates completion in LSP
GitOrigin-RevId: cc42c46046fd8f24e16e11f3116a9e68d0c164ee
This commit is contained in:
committed by
intellij-monorepo-bot
parent
3eee71e033
commit
14f0aa7378
+20
-1
@@ -1022,6 +1022,25 @@ public class JavaLiveTemplateTest extends LiveTemplateTestCase {
|
||||
""");
|
||||
}
|
||||
|
||||
public void testModCommandSoutm() {
|
||||
TemplateImpl template = TemplateSettings.getInstance().getTemplate("soutm", "Java");
|
||||
configureByJavaText("Test.java", """
|
||||
class X {
|
||||
void test() {
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
""");
|
||||
runModCommand(template);
|
||||
myFixture.checkResult("""
|
||||
class X {
|
||||
void test() {
|
||||
System.out.println("X.test");<caret>
|
||||
}
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
public void testModCommandMain() {
|
||||
TemplateImpl template = TemplateSettings.getInstance().getTemplate("main", "Java");
|
||||
configureByJavaText("Test.java", """
|
||||
@@ -1052,7 +1071,7 @@ public class JavaLiveTemplateTest extends LiveTemplateTestCase {
|
||||
myFixture.checkResult("""
|
||||
class X {
|
||||
void test() {
|
||||
for (int <selection>i<caret></selection> = 0; i <; i++) {
|
||||
for (int <selection>i<caret></selection> = 0; i < ; i++) {
|
||||
\s
|
||||
}
|
||||
}
|
||||
|
||||
+79
-12
@@ -3,19 +3,26 @@
|
||||
package com.intellij.codeInsight.template.impl;
|
||||
|
||||
import com.intellij.codeInsight.template.Expression;
|
||||
import com.intellij.codeInsight.template.ExpressionContext;
|
||||
import com.intellij.codeInsight.template.Result;
|
||||
import com.intellij.codeInsight.template.Template;
|
||||
import com.intellij.codeInsight.template.TextResult;
|
||||
import com.intellij.modcommand.ModCommand;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.modcommand.ModTemplateBuilder;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.options.SchemeElement;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.NlsContexts;
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -435,28 +442,46 @@ public class TemplateImpl extends TemplateBase implements SchemeElement {
|
||||
Variable variable = variableMap.get(segment.name);
|
||||
if (variable != null) {
|
||||
manager.commitDocument(document);
|
||||
PsiElement element = updater.getPsiFile().findElementAt(start + segment.offset);
|
||||
PsiElement element = updater.getPsiFile().findElementAt(info.marker.getStartOffset());
|
||||
if (element != null) {
|
||||
if (builder == null) builder = updater.templateBuilder();
|
||||
builder.field(element, info.marker.getTextRange().shiftLeft(element.getTextRange().getStartOffset()), segment.name,
|
||||
variable.getExpression());
|
||||
if (!variable.isAlwaysStopAt()) {
|
||||
Result result = variable.getExpression().calculateResult(new DummyContext(info.marker.getTextRange(), element, updater.getPsiFile()));
|
||||
if (result != null) {
|
||||
document.replaceString(info.marker.getStartOffset(), info.marker.getEndOffset(), result.toString());
|
||||
}
|
||||
} else {
|
||||
if (builder == null) builder = updater.templateBuilder();
|
||||
builder.field(element, info.marker.getTextRange().shiftLeft(element.getTextRange().getStartOffset()), segment.name,
|
||||
variable.getExpression());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isToReformat()) {
|
||||
List<MarkerInfo> emptyValues = new ArrayList<>();
|
||||
for (MarkerInfo info : markers) {
|
||||
if (info.marker.getStartOffset() == info.marker.getEndOffset()) {
|
||||
document.insertString(info.marker.getStartOffset(), "a");
|
||||
emptyValues.add(info);
|
||||
}
|
||||
}
|
||||
manager.commitDocument(document);
|
||||
CodeStyleManager.getInstance(updater.getProject())
|
||||
.reformatText(updater.getPsiFile(), wholeTemplate.getStartOffset(), wholeTemplate.getEndOffset());
|
||||
}
|
||||
if (endMarker != null) {
|
||||
document.deleteString(endMarker.getStartOffset(), endMarker.getEndOffset());
|
||||
if (builder != null) {
|
||||
builder.finishAt(endMarker.getStartOffset());
|
||||
} else {
|
||||
updater.moveCaretTo(endMarker.getStartOffset());
|
||||
for (MarkerInfo value : emptyValues) {
|
||||
document.deleteString(value.marker.getStartOffset(), value.marker.getEndOffset());
|
||||
}
|
||||
endMarker.dispose();
|
||||
}
|
||||
if (endMarker == null) {
|
||||
endMarker = document.createRangeMarker(wholeTemplate.getEndOffset(), wholeTemplate.getEndOffset());
|
||||
}
|
||||
document.deleteString(endMarker.getStartOffset(), endMarker.getEndOffset());
|
||||
if (builder != null) {
|
||||
builder.finishAt(endMarker.getStartOffset());
|
||||
} else {
|
||||
updater.moveCaretTo(endMarker.getStartOffset());
|
||||
}
|
||||
endMarker.dispose();
|
||||
for (MarkerInfo info : markers) {
|
||||
info.marker.dispose();
|
||||
}
|
||||
@@ -467,4 +492,46 @@ public class TemplateImpl extends TemplateBase implements SchemeElement {
|
||||
public String toString() {
|
||||
return myGroupName +"/" + myKey;
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static class DummyContext implements ExpressionContext {
|
||||
private final @NotNull TextRange myRange;
|
||||
private final @NotNull PsiElement myElement;
|
||||
private final @NotNull PsiFile myFile;
|
||||
|
||||
public DummyContext(@NotNull TextRange range, @NotNull PsiElement element, @NotNull PsiFile file) {
|
||||
myRange = range;
|
||||
myElement = element;
|
||||
myFile = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Project getProject() { return myFile.getProject(); }
|
||||
|
||||
@Override
|
||||
public @Nullable PsiFile getPsiFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Editor getEditor() { return null; }
|
||||
|
||||
@Override
|
||||
public int getStartOffset() { return myRange.getStartOffset(); }
|
||||
|
||||
@Override
|
||||
public int getTemplateStartOffset() { return myRange.getStartOffset(); }
|
||||
|
||||
@Override
|
||||
public int getTemplateEndOffset() { return myRange.getEndOffset(); }
|
||||
|
||||
@Override
|
||||
public <T> T getProperty(Key<T> key) { return null; }
|
||||
|
||||
@Override
|
||||
public @Nullable PsiElement getPsiElementAtStartOffset() { return myElement.isValid() ? myElement : null; }
|
||||
|
||||
@Override
|
||||
public @Nullable TextResult getVariableValue(String variableName) { return null; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,8 @@ package com.intellij.lang.impl.modcommand;
|
||||
|
||||
import com.intellij.analysis.AnalysisBundle;
|
||||
import com.intellij.codeInsight.template.Expression;
|
||||
import com.intellij.codeInsight.template.ExpressionContext;
|
||||
import com.intellij.codeInsight.template.Result;
|
||||
import com.intellij.codeInsight.template.TextResult;
|
||||
import com.intellij.codeInsight.template.impl.TemplateImpl;
|
||||
import com.intellij.injected.editor.DocumentWindow;
|
||||
import com.intellij.injected.editor.InjectionEditService;
|
||||
import com.intellij.lang.Language;
|
||||
@@ -31,7 +30,6 @@ import com.intellij.modcommand.ModUpdateReferences;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.editor.colors.TextAttributesKey;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
@@ -298,6 +296,7 @@ final class PsiUpdateImpl {
|
||||
private final Consumer<@NotNull Document> myCopyCleaner;
|
||||
private final List<ModHighlight.HighlightInfo> myHighlightInfos = new ArrayList<>();
|
||||
private final List<ModStartTemplate.TemplateField> myTemplateFields = new ArrayList<>();
|
||||
private final Map<String, Result> myTemplateValues = new HashMap<>();
|
||||
private final List<ModLaunchEditorAction> myLaunchEditorActions = new ArrayList<>();
|
||||
private @NotNull Function<? super @NotNull PsiFile, ? extends @NotNull ModCommand> myTemplateFinishFunction = f -> nop();
|
||||
private @Nullable ModStartRename myRenameSymbol;
|
||||
@@ -521,7 +520,9 @@ final class PsiUpdateImpl {
|
||||
}
|
||||
TextRange rangeForTemplate = templateRange(elementRange, rangeInElement);
|
||||
TextRange range = mapRange(rangeForTemplate);
|
||||
Result result = expression.calculateResult(new DummyContext(range, element, getPsiFile()));
|
||||
TextRange rangeForContext = range;
|
||||
Result result = myTemplateValues.computeIfAbsent(varName, v -> expression.calculateResult(new TemplateImpl.DummyContext(
|
||||
rangeForContext, element, getPsiFile())));
|
||||
if (result != null) {
|
||||
FileTracker tracker = requireNonNull(myTracker); // guarded by getRange call
|
||||
String fieldValue = result.toString();
|
||||
@@ -825,46 +826,5 @@ final class PsiUpdateImpl {
|
||||
if (myTemplateFields.isEmpty()) return nop();
|
||||
return new ModStartTemplate(navigationFile(), myTemplateFields, myTemplateFinishFunction);
|
||||
}
|
||||
|
||||
private class DummyContext implements ExpressionContext {
|
||||
private final TextRange myRange;
|
||||
private final @NotNull PsiElement myElement;
|
||||
private final @NotNull PsiFile myFile;
|
||||
|
||||
private DummyContext(TextRange range, @NotNull PsiElement element, @NotNull PsiFile file) {
|
||||
myRange = range;
|
||||
myElement = element;
|
||||
myFile = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Project getProject() { return myActionContext.project(); }
|
||||
|
||||
@Override
|
||||
public @Nullable PsiFile getPsiFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Editor getEditor() { return null; }
|
||||
|
||||
@Override
|
||||
public int getStartOffset() { return myRange.getStartOffset(); }
|
||||
|
||||
@Override
|
||||
public int getTemplateStartOffset() { return myRange.getStartOffset(); }
|
||||
|
||||
@Override
|
||||
public int getTemplateEndOffset() { return myRange.getEndOffset(); }
|
||||
|
||||
@Override
|
||||
public <T> T getProperty(Key<T> key) { return null; }
|
||||
|
||||
@Override
|
||||
public @Nullable PsiElement getPsiElementAtStartOffset() { return myElement.isValid() ? myElement : null; }
|
||||
|
||||
@Override
|
||||
public @Nullable TextResult getVariableValue(String variableName) { return null; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ final class LiveTemplateModCompletionItemProvider implements ModCompletionItemPr
|
||||
PsiFile file = context.getPosition().getContainingFile();
|
||||
int offset = context.offset();
|
||||
List<TemplateImpl> availableTemplates = TemplateManagerImpl.listApplicableTemplates(
|
||||
TemplateActionContext.expanding(file, offset));
|
||||
TemplateActionContext.expanding(file, offset - context.prefix().length()));
|
||||
Map<TemplateImpl, String> templates =
|
||||
ListTemplatesHandler.filterTemplatesByPrefix(availableTemplates, file.getFileDocument(), offset, false, false);
|
||||
for (Map.Entry<TemplateImpl, String> entry : templates.entrySet()) {
|
||||
|
||||
Reference in New Issue
Block a user