run live template to adjust template from selection

This commit is contained in:
Dmitry Avdeev
2018-11-20 17:51:57 +03:00
parent 10a0435891
commit bf501b550a
3 changed files with 173 additions and 0 deletions
@@ -0,0 +1,127 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.structuralsearch;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.codeInsight.template.*;
import com.intellij.psi.*;
import com.intellij.structuralsearch.impl.matcher.CompiledPattern;
import com.intellij.structuralsearch.impl.matcher.compiler.PatternCompiler;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class StructuralSearchTemplateBuilder {
private final TemplateBuilder myBuilder;
private final PsiFile myPsiFile;
private final PlaceholderCount myClassCount = new PlaceholderCount("Class");
private final PlaceholderCount myVarCount = new PlaceholderCount("Var");
private final PlaceholderCount myFunCount = new PlaceholderCount("Fun");
private int myShift;
public StructuralSearchTemplateBuilder(@NotNull PsiFile psiFile) {
myBuilder = TemplateBuilderFactory.getInstance().createTemplateBuilder(psiFile);
myPsiFile = psiFile;
}
public TemplateBuilder buildTemplate() {
JavaRecursiveElementVisitor visitor = new JavaRecursiveElementVisitor() {
@Override
public void visitIdentifier(PsiIdentifier identifier) {
PsiElement parent = identifier.getParent();
if (parent instanceof PsiClass) {
replaceElement(identifier, myClassCount, true);
}
else if (parent instanceof PsiReferenceExpression) {
if (parent.getParent() instanceof PsiMethodCallExpression)
replaceElement(identifier, myFunCount, true);
else
replaceElement(identifier, myVarCount, false);
}
else if (parent instanceof PsiJavaCodeReferenceElement) {
replaceElement(identifier, myClassCount, false);
}
}
@Override
public void visitReferenceList(PsiReferenceList list) {
PsiJavaCodeReferenceElement[] elements = list.getReferenceElements();
for (PsiJavaCodeReferenceElement element : elements) {
replaceElement(element.getReferenceNameElement(), myClassCount, false);
}
}
};
MatchOptions matchOptions = new MatchOptions();
String text = myPsiFile.getText();
matchOptions.setSearchPattern(text);
CompiledPattern pattern = PatternCompiler.compilePattern(myPsiFile.getProject(), matchOptions, false);
if (pattern == null)
return myBuilder;
PsiElement current = pattern.getNodes().current();
if (current != null) {
myShift = current.getTextRange().getStartOffset();
current.accept(visitor);
}
return myBuilder;
}
private void replaceElement(@Nullable PsiElement element, PlaceholderCount count, boolean preferOriginal) {
if (element == null) {
return;
}
myBuilder.replaceRange(element.getTextRange().shiftLeft(myShift), new MyExpression(count.getPlaceholder(), element, preferOriginal));
}
private static class MyExpression extends Expression {
private final String myPlaceholder;
private final String myOriginalText;
private final boolean myPreferOriginal;
private MyExpression(String placeholder, PsiElement original, boolean preferOriginal) {
myPlaceholder = placeholder;
myOriginalText = original.getText();
myPreferOriginal = preferOriginal;
}
@Nullable
@Override
public Result calculateResult(ExpressionContext context) {
return new TextResult(myPreferOriginal ? myOriginalText : myPlaceholder);
}
@Nullable
@Override
public Result calculateQuickResult(ExpressionContext context) {
return calculateResult(context);
}
@Nullable
@Override
public LookupElement[] calculateLookupItems(ExpressionContext context) {
LookupElement[] elements = {LookupElementBuilder.create(myPlaceholder), LookupElementBuilder.create(myOriginalText)};
return myPreferOriginal ? ArrayUtil.reverseArray(elements) : elements;
}
}
private static class PlaceholderCount {
private final String myName;
private int myCount;
private PlaceholderCount(String name) {
myName = name;
}
public String getPlaceholder() {
return "$" + myName + ++myCount + "$";
}
}
}
@@ -2,6 +2,7 @@
package com.intellij.structuralsearch.plugin.ui;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.template.TemplateBuilder;
import com.intellij.codeInsight.template.impl.TemplateEditorUtil;
import com.intellij.codeInsight.template.impl.TemplateImplUtil;
import com.intellij.find.FindBundle;
@@ -74,6 +75,7 @@ import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
* @author Bas Leijdekkers
@@ -644,6 +646,12 @@ public class StructuralSearchDialog extends DialogWrapper {
setSize(otherSize.width, getSize().height);
}
}
Document document = mySearchCriteriaEdit.getDocument();
PsiFile psiFile = PsiDocumentManager.getInstance(getProject()).getPsiFile(document);
assert psiFile != null;
TemplateBuilder builder = new StructuralSearchTemplateBuilder(psiFile).buildTemplate();
WriteCommandAction.runWriteCommandAction(getProject(), () -> builder.run(Objects.requireNonNull(mySearchCriteriaEdit.getEditor()), true));
}
@Override
@@ -0,0 +1,38 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.structuralsearch;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateBuilderImpl;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.psi.PsiFile;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
public class SSTemplateBuilderTest extends LightCodeInsightFixtureTestCase {
public void testClassTemplate() {
doTest("class foo extends bar, next implements xxx", "class foo extends $Class2$, $Class3$ implements $Class4$");
}
public void testStatement() {
doTest("i=1", "$Var1$=1");
}
public void testMethodCall() {
Template template = doTest("foo()", "foo()");
assertEquals(1, template.getSegmentsCount());
}
private Template doTest(String text, String expected) {
PsiFile psiFile = myFixture.configureByText(JavaFileType.INSTANCE, text);
TemplateBuilderImpl builder = (TemplateBuilderImpl)new StructuralSearchTemplateBuilder(getFile()).buildTemplate();
Template template = WriteCommandAction.writeCommandAction(getProject()).compute(() -> {
Template inlineTemplate = builder.buildInlineTemplate();
TemplateManager.getInstance(getProject()).startTemplate(getEditor(), inlineTemplate);
return inlineTemplate;
});
assertEquals(expected, psiFile.getText());
return template;
}
}