postfix templates: extract common classes for js

This commit is contained in:
anstarovoyt
2018-04-17 18:24:35 +05:00
parent 306aab48bb
commit 9462c82d23
10 changed files with 441 additions and 272 deletions
@@ -4,8 +4,8 @@ package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.completion.CompletionInitializationContext;
import com.intellij.codeInsight.completion.JavaCompletionContributor;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.codeInsight.template.impl.TemplateSettings;
import com.intellij.codeInsight.template.postfix.templates.editable.*;
import com.intellij.codeInsight.template.postfix.templates.editable.JavaPostfixTemplateExpressionCondition.JavaPostfixTemplateExpressionFqnCondition;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Document;
@@ -17,25 +17,18 @@ import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import kotlin.LazyKt;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.java.JpsJavaSdkType;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import static com.intellij.codeInsight.template.postfix.templates.PostfixTemplatesUtils.*;
public class JavaPostfixTemplateProvider implements PostfixTemplateProvider {
private static final String LANGUAGE_LEVEL_ATTR = "language-level";
private static final String CONDITIONS_TAG = "conditions";
private static final String TEMPLATE_TAG = "template";
private static final String CONDITION_TAG = "condition";
private static final String ID_ATTR = "id";
private static final String FQN_ATTR = "fqn";
private static final String TOPMOST_ATTR = "topmost";
private final Set<PostfixTemplate> myBuiltinTemplates = ContainerUtil.newHashSet(
new AssertStatementPostfixTemplate(this),
@@ -140,7 +133,10 @@ public class JavaPostfixTemplateProvider implements PostfixTemplateProvider {
!(templateToEdit instanceof ForIndexedPostfixTemplate) &&
!(templateToEdit instanceof ArgumentPostfixTemplate) &&
!(templateToEdit instanceof OptionalPostfixTemplate)) {
return new JavaPostfixTemplateEditor(this, templateToEdit);
JavaPostfixTemplateEditor editor = new JavaPostfixTemplateEditor(this);
editor.setTemplate(templateToEdit);
return editor;
}
return null;
}
@@ -148,46 +144,30 @@ public class JavaPostfixTemplateProvider implements PostfixTemplateProvider {
@Nullable
@Override
public JavaEditablePostfixTemplate readExternalTemplate(@NotNull String id, @NotNull String name, @NotNull Element template) {
boolean useTopmostExpression = Boolean.parseBoolean(template.getAttributeValue(TOPMOST_ATTR));
TemplateImpl liveTemplate = readExternalLiveTemplate(template, this);
if (liveTemplate == null) return null;
Set<JavaPostfixTemplateExpressionCondition> conditions = readExternalConditions(template, JavaPostfixTemplateProvider::readExternal);
boolean useTopmostExpression = readExternalTopmostAttribute(template);
String languageLevelAttributeValue = template.getAttributeValue(LANGUAGE_LEVEL_ATTR);
LanguageLevel languageLevel = ObjectUtils.notNull(LanguageLevel.parse(languageLevelAttributeValue), LanguageLevel.JDK_1_6);
Set<JavaPostfixTemplateExpressionCondition> conditions = new LinkedHashSet<>();
Element conditionsElement = template.getChild(CONDITIONS_TAG);
if (conditionsElement != null) {
for (Element conditionElement : conditionsElement.getChildren(CONDITION_TAG)) {
ContainerUtil.addIfNotNull(conditions, readExternal(conditionElement));
}
}
Element templateChild = template.getChild(TemplateSettings.TEMPLATE);
if (templateChild == null) {
return null;
}
TemplateImpl liveTemplate = TemplateSettings.readTemplateFromElement("", templateChild, getClass().getClassLoader());
return new JavaEditablePostfixTemplate(id, name, liveTemplate, "", conditions, languageLevel, useTopmostExpression, this);
}
@Override
public void writeExternalTemplate(@NotNull PostfixTemplate template, @NotNull Element parentElement) {
if (template instanceof JavaEditablePostfixTemplate) {
parentElement.setAttribute(TOPMOST_ATTR, String.valueOf(((JavaEditablePostfixTemplate)template).isUseTopmostExpression()));
LanguageLevel languageLevel = ((JavaEditablePostfixTemplate)template).getMinimumLanguageLevel();
parentElement.setAttribute(LANGUAGE_LEVEL_ATTR, JpsJavaSdkType.complianceOption(languageLevel.toJavaVersion()));
Element conditionsTag = new Element(CONDITIONS_TAG);
for (JavaPostfixTemplateExpressionCondition condition : ((JavaEditablePostfixTemplate)template).getExpressionConditions()) {
writeExternal(condition, conditionsTag);
}
Element templateTag = TemplateSettings.serializeTemplate(((EditablePostfixTemplate)template).getLiveTemplate(), null,
LazyKt.lazyOf(Collections.emptyMap()));
parentElement.addContent(conditionsTag).addContent(templateTag);
PostfixTemplatesUtils.writeExternalTemplate(template, parentElement);
}
}
@Nullable
private static JavaPostfixTemplateExpressionCondition readExternal(@NotNull Element condition) {
String id = condition.getAttributeValue(ID_ATTR);
String id = condition.getAttributeValue(PostfixTemplateExpressionCondition.ID_ATTR);
if (JavaPostfixTemplateExpressionCondition.JavaPostfixTemplateArrayExpressionCondition.ID.equals(id)) {
return new JavaPostfixTemplateExpressionCondition.JavaPostfixTemplateArrayExpressionCondition();
}
@@ -206,22 +186,12 @@ public class JavaPostfixTemplateProvider implements PostfixTemplateProvider {
if (JavaPostfixTemplateExpressionCondition.JavaPostfixTemplateNotPrimitiveTypeExpressionCondition.ID.equals(id)) {
return new JavaPostfixTemplateExpressionCondition.JavaPostfixTemplateNotPrimitiveTypeExpressionCondition();
}
if (JavaPostfixTemplateExpressionCondition.JavaPostfixTemplateExpressionFqnCondition.ID.equals(id)) {
String fqn = condition.getAttributeValue(FQN_ATTR);
if (JavaPostfixTemplateExpressionFqnCondition.ID.equals(id)) {
String fqn = condition.getAttributeValue(JavaPostfixTemplateExpressionFqnCondition.FQN_ATTR);
if (StringUtil.isNotEmpty(fqn)) {
return new JavaPostfixTemplateExpressionCondition.JavaPostfixTemplateExpressionFqnCondition(fqn);
return new JavaPostfixTemplateExpressionFqnCondition(fqn);
}
}
return null;
}
private static void writeExternal(@NotNull JavaPostfixTemplateExpressionCondition condition, @NotNull Element parentElement) {
Element element = new Element(CONDITION_TAG);
element.setAttribute(ID_ATTR, condition.getId());
if (condition instanceof JavaPostfixTemplateExpressionCondition.JavaPostfixTemplateExpressionFqnCondition) {
String fqn = ((JavaPostfixTemplateExpressionCondition.JavaPostfixTemplateExpressionFqnCondition)condition).getFqn();
element.setAttribute(FQN_ATTR, fqn);
}
parentElement.addContent(element);
}
}
@@ -7,6 +7,7 @@ import com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Conditions;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
@@ -24,12 +25,11 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
public class JavaEditablePostfixTemplate extends EditablePostfixTemplate {
public class JavaEditablePostfixTemplate
extends EditablePostfixTemplateWithConditions<PsiExpression, JavaPostfixTemplateExpressionCondition> {
private static final Condition<PsiElement> PSI_ERROR_FILTER = element -> !PsiTreeUtil.hasErrorElements(element);
@NotNull private final Set<JavaPostfixTemplateExpressionCondition> myExpressionConditions;
@NotNull private final LanguageLevel myMinimumLanguageLevel;
private final boolean myUseTopmostExpression;
public JavaEditablePostfixTemplate(@NotNull String templateName,
@NotNull String templateText,
@@ -38,7 +38,8 @@ public class JavaEditablePostfixTemplate extends EditablePostfixTemplate {
@NotNull LanguageLevel minimumLanguageLevel,
boolean useTopmostExpression,
@NotNull PostfixTemplateProvider provider) {
this(templateName, templateName, createTemplate(templateText), example, expressionConditions, minimumLanguageLevel, useTopmostExpression, provider);
this(templateName, templateName, createTemplate(templateText), example, expressionConditions, minimumLanguageLevel,
useTopmostExpression, provider);
}
public JavaEditablePostfixTemplate(@NotNull String templateId,
@@ -49,18 +50,8 @@ public class JavaEditablePostfixTemplate extends EditablePostfixTemplate {
@NotNull LanguageLevel minimumLanguageLevel,
boolean useTopmostExpression,
@NotNull PostfixTemplateProvider provider) {
super(templateId, templateName, createTemplate(templateText), example, provider);
myExpressionConditions = expressionConditions;
super(templateId, templateName, createTemplate(templateText), example, expressionConditions, useTopmostExpression, provider);
myMinimumLanguageLevel = minimumLanguageLevel;
myUseTopmostExpression = useTopmostExpression;
}
@NotNull
private static TemplateImpl createTemplate(@NotNull String templateText) {
TemplateImpl template = new TemplateImpl("fakeKey", templateText, "");
template.setToReformat(true);
template.parseSegments();
return template;
}
public JavaEditablePostfixTemplate(@NotNull String templateId,
@@ -71,42 +62,16 @@ public class JavaEditablePostfixTemplate extends EditablePostfixTemplate {
@NotNull LanguageLevel minimumLanguageLevel,
boolean useTopmostExpression,
@NotNull PostfixTemplateProvider provider) {
super(templateId, templateName, liveTemplate, example, provider);
myExpressionConditions = expressionConditions;
super(templateId, templateName, liveTemplate, example, expressionConditions, useTopmostExpression, provider);
myMinimumLanguageLevel = minimumLanguageLevel;
myUseTopmostExpression = useTopmostExpression;
}
@NotNull
public Set<JavaPostfixTemplateExpressionCondition> getExpressionConditions() {
return myExpressionConditions;
}
@NotNull
public LanguageLevel getMinimumLanguageLevel() {
return myMinimumLanguageLevel;
}
public boolean isUseTopmostExpression() {
return myUseTopmostExpression;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof JavaEditablePostfixTemplate)) return false;
if (!super.equals(o)) return false;
JavaEditablePostfixTemplate template = (JavaEditablePostfixTemplate)o;
return myUseTopmostExpression == template.myUseTopmostExpression &&
Objects.equals(myExpressionConditions, template.myExpressionConditions) &&
myMinimumLanguageLevel == template.myMinimumLanguageLevel;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), myExpressionConditions, myMinimumLanguageLevel);
}
@Override
protected List<PsiElement> getExpressions(@NotNull PsiElement context, @NotNull Document document, int offset) {
if (DumbService.getInstance(context.getProject()).isDumb()) return Collections.emptyList();
@@ -122,28 +87,23 @@ public class JavaEditablePostfixTemplate extends EditablePostfixTemplate {
expressions = ContainerUtil.newArrayList(IntroduceVariableBase.collectExpressions(file, document, Math.max(offset - 1, 0), false));
}
return ContainerUtil.filter(expressions, e -> {
return ContainerUtil.filter(expressions, Conditions.and(e -> {
if (!PSI_ERROR_FILTER.value(e) || !(e instanceof PsiExpression) || e.getTextRange().getEndOffset() != offset) {
return false;
}
for (JavaPostfixTemplateExpressionCondition condition : myExpressionConditions) {
if (condition.value((PsiExpression)e)) {
return true;
}
}
return myExpressionConditions.isEmpty();
});
return true;
}, getExpressionCompositeCondition()));
}
@NotNull
@Override
protected PsiElement getElementToRemove(@NotNull PsiElement element) {
if (myUseTopmostExpression) {
PsiElement parent = element.getParent();
if (parent instanceof PsiExpressionStatement) {
return parent;
}
protected PsiElement getTopmostExpression(@NotNull PsiElement element) {
PsiElement parent = element.getParent();
if (parent instanceof PsiExpressionStatement) {
return parent;
}
return element;
}
@@ -157,4 +117,20 @@ public class JavaEditablePostfixTemplate extends EditablePostfixTemplate {
public boolean isBuiltin() {
return false;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
JavaEditablePostfixTemplate template = (JavaEditablePostfixTemplate)o;
return myMinimumLanguageLevel == template.myMinimumLanguageLevel;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), myMinimumLanguageLevel);
}
}
@@ -1,74 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.codeInsight.template.postfix.templates.editable.JavaPostfixTemplateEditor">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="7" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="1120" height="989"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<vspacer id="61107">
<constraints>
<grid row="6" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<component id="7f6a3" class="com.intellij.ui.components.JBCheckBox" binding="myApplyToTheTopmostJBCheckBox" default-binding="true">
<constraints>
<grid row="3" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Apply to the &amp;topmost expression"/>
</properties>
</component>
<component id="2a5e0" class="javax.swing.JLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Minimum language level:"/>
</properties>
</component>
<component id="b5263" class="com.intellij.ui.components.JBLabel" binding="myExpressionVariableHint">
<constraints>
<grid row="5" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Use $EXPR$ variable to refer target expression"/>
</properties>
</component>
<component id="8f839" class="com.intellij.openapi.ui.ComboBox" binding="myLanguageLevelCombo" custom-create="true">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
<grid id="c3cd5" binding="myExpressionTypesPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="2" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children/>
</grid>
<component id="3e6c3" class="javax.swing.JLabel">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Applicable expression types:"/>
</properties>
</component>
<grid id="d812" binding="myTemplateEditorPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="4" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children/>
</grid>
</children>
</grid>
</form>
@@ -2,16 +2,13 @@
package com.intellij.codeInsight.template.postfix.templates.editable;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.template.impl.TemplateEditorUtil;
import com.intellij.codeInsight.template.postfix.settings.PostfixTemplateEditorBase;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplateProvider;
import com.intellij.ide.DataManager;
import com.intellij.ide.util.TreeClassChooser;
import com.intellij.ide.util.TreeClassChooserFactory;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
@@ -20,75 +17,25 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.ui.AnActionButton;
import com.intellij.ui.ColoredListCellRenderer;
import com.intellij.ui.ListUtil;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBList;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.FormBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.Set;
public class JavaPostfixTemplateEditor implements PostfixTemplateEditor {
@NotNull private final PostfixTemplateProvider myProvider;
@NotNull private final Editor myTemplateEditor;
@NotNull private final JBList<JavaPostfixTemplateExpressionCondition> myExpressionTypesList;
@NotNull private final DefaultListModel<JavaPostfixTemplateExpressionCondition> myExpressionTypesListModel;
public class JavaPostfixTemplateEditor extends PostfixTemplateEditorBase<PsiExpression, JavaPostfixTemplateExpressionCondition> {
private JPanel myPanel;
private JBCheckBox myApplyToTheTopmostJBCheckBox;
private ComboBox<LanguageLevel> myLanguageLevelCombo;
private JBLabel myExpressionVariableHint;
private JPanel myExpressionTypesPanel;
private JPanel myTemplateEditorPanel;
@NotNull private final JPanel myPanel;
@NotNull private final ComboBox<LanguageLevel> myLanguageLevelCombo;
public JavaPostfixTemplateEditor(@NotNull PostfixTemplateProvider provider, @Nullable PostfixTemplate template) {
myProvider = provider;
Project defaultProject = ProjectManager.getInstance().getDefaultProject();
myTemplateEditor = TemplateEditorUtil.createEditor(false, createDocument(defaultProject), defaultProject);
myExpressionTypesListModel = JBList.createDefaultListModel();
myExpressionTypesList = new JBList<>(myExpressionTypesListModel);
myExpressionTypesList.setCellRenderer(new ColoredListCellRenderer<JavaPostfixTemplateExpressionCondition>() {
@Override
protected void customizeCellRenderer(@NotNull JList<? extends JavaPostfixTemplateExpressionCondition> list,
JavaPostfixTemplateExpressionCondition value,
int index,
boolean selected,
boolean hasFocus) {
append(value.getPresentableName());
}
});
myExpressionTypesPanel.setLayout(new BorderLayout());
myExpressionTypesPanel.add(ToolbarDecorator.createDecorator(myExpressionTypesList)
.setAddAction(button -> addExpressionType(button))
.setRemoveAction(button -> ListUtil.removeSelectedItems(myExpressionTypesList))
.disableUpDownActions()
.createPanel());
myExpressionTypesPanel.setMinimumSize(new Dimension(-1, 100));
myTemplateEditorPanel.setLayout(new BorderLayout());
myTemplateEditorPanel.add(myTemplateEditor.getComponent());
UIUtil.applyStyle(UIUtil.ComponentStyle.SMALL, myExpressionVariableHint);
myExpressionVariableHint.setFontColor(UIUtil.FontColor.BRIGHTER);
if (template instanceof JavaEditablePostfixTemplate) {
setTemplate((JavaEditablePostfixTemplate)template);
}
}
private void createUIComponents() {
public JavaPostfixTemplateEditor(@NotNull PostfixTemplateProvider provider) {
super(provider, createEditor());
myLanguageLevelCombo = new ComboBox<>(LanguageLevel.values());
myLanguageLevelCombo.setRenderer(new ColoredListCellRenderer<LanguageLevel>() {
@Override
@@ -96,11 +43,17 @@ public class JavaPostfixTemplateEditor implements PostfixTemplateEditor {
append(value.getPresentableText());
}
});
myPanel = FormBuilder.createFormBuilder()
.addLabeledComponent("Minimum language level:", myLanguageLevelCombo)
.addComponent(myEditTemplateAndConditionsPanel)
.getPanel();
}
@Override
public void dispose() {
TemplateEditorUtil.disposeTemplateEditor(myTemplateEditor);
@NotNull
private static Editor createEditor() {
Project defaultProject = ProjectManager.getInstance().getDefaultProject();
return createEditor(defaultProject, createDocument(defaultProject));
}
@NotNull
@@ -116,28 +69,12 @@ public class JavaPostfixTemplateEditor implements PostfixTemplateEditor {
myProvider);
}
private void setTemplate(@NotNull JavaEditablePostfixTemplate template) {
myExpressionTypesListModel.clear();
for (JavaPostfixTemplateExpressionCondition condition : template.getExpressionConditions()) {
myExpressionTypesListModel.addElement(condition);
}
myLanguageLevelCombo.setSelectedItem(template.getMinimumLanguageLevel());
myApplyToTheTopmostJBCheckBox.setSelected(template.isUseTopmostExpression());
ApplicationManager.getApplication()
.runWriteAction(() -> myTemplateEditor.getDocument().setText(template.getLiveTemplate().getString()));
}
@NotNull
@Override
public JComponent getComponent() {
return myPanel;
}
@Override
public String getHelpId() {
return "reference.custom.postfix.templates";
}
private static Document createDocument(@Nullable Project project) {
if (project == null) {
return EditorFactory.getInstance().createDocument("");
@@ -149,8 +86,8 @@ public class JavaPostfixTemplateEditor implements PostfixTemplateEditor {
return PsiDocumentManager.getInstance(project).getDocument(fragment);
}
private void addExpressionType(@NotNull AnActionButton button) {
DefaultActionGroup group = new DefaultActionGroup();
@Override
protected void fillConditions(@NotNull DefaultActionGroup group) {
group.add(new AddConditionAction(new JavaPostfixTemplateExpressionCondition.JavaPostfixTemplateVoidExpressionCondition()));
group.add(new AddConditionAction(new JavaPostfixTemplateExpressionCondition.JavaPostfixTemplateNonVoidExpressionCondition()));
group.add(new AddConditionAction(new JavaPostfixTemplateExpressionCondition.JavaPostfixTemplateBooleanExpressionCondition()));
@@ -162,10 +99,14 @@ public class JavaPostfixTemplateEditor implements PostfixTemplateEditor {
group.add(new ChooseClassAction(project));
}
group.add(new ChooseClassAction(null));
DataContext context = DataManager.getInstance().getDataContext(button.getContextComponent());
ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup(null, group, context,
JBPopupFactory.ActionSelectionAid.ALPHA_NUMBERING, true, null);
popup.show(ObjectUtils.assertNotNull(button.getPreferredPopupPoint()));
}
@Override
public void setTemplate(@Nullable PostfixTemplate template) {
super.setTemplate(template);
if (template instanceof JavaEditablePostfixTemplate) {
myLanguageLevelCombo.setSelectedItem(((JavaEditablePostfixTemplate)template).getMinimumLanguageLevel());
}
}
private class AddConditionAction extends DumbAwareAction {
@@ -2,25 +2,19 @@
package com.intellij.codeInsight.template.postfix.templates.editable;
import com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiType;
import com.intellij.psi.util.InheritanceUtil;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public interface JavaPostfixTemplateExpressionCondition extends Condition<PsiExpression> {
String getId();
String getPresentableName();
boolean equals(Object o);
int hashCode();
public interface JavaPostfixTemplateExpressionCondition extends PostfixTemplateExpressionCondition<PsiExpression> {
class JavaPostfixTemplateExpressionFqnCondition implements JavaPostfixTemplateExpressionCondition {
public static final String ID = "fqn";
public static final String FQN_ATTR = "fqn";
private final String myFqn;
@@ -38,11 +32,13 @@ public interface JavaPostfixTemplateExpressionCondition extends Condition<PsiExp
return type != null && InheritanceUtil.isInheritor(type, myFqn);
}
@NotNull
@Override
public String getId() {
return ID;
}
@NotNull
@Override
public String getPresentableName() {
return myFqn;
@@ -60,6 +56,12 @@ public interface JavaPostfixTemplateExpressionCondition extends Condition<PsiExp
public int hashCode() {
return Objects.hash(myFqn);
}
@Override
public void serializeTo(@NotNull Element element) {
JavaPostfixTemplateExpressionCondition.super.serializeTo(element);
element.setAttribute(FQN_ATTR, getFqn());
}
}
class JavaPostfixTemplateVoidExpressionCondition implements JavaPostfixTemplateExpressionCondition {
@@ -71,11 +73,13 @@ public interface JavaPostfixTemplateExpressionCondition extends Condition<PsiExp
return type != null && PsiType.VOID.equals(type);
}
@NotNull
@Override
public String getId() {
return ID;
}
@NotNull
@Override
public String getPresentableName() {
return "void";
@@ -102,11 +106,13 @@ public interface JavaPostfixTemplateExpressionCondition extends Condition<PsiExp
return JavaPostfixTemplatesUtils.isNonVoid(element.getType());
}
@NotNull
@Override
public String getId() {
return ID;
}
@NotNull
@Override
public String getPresentableName() {
return "non void";
@@ -132,11 +138,13 @@ public interface JavaPostfixTemplateExpressionCondition extends Condition<PsiExp
return JavaPostfixTemplatesUtils.isBoolean(element.getType());
}
@NotNull
@Override
public String getId() {
return ID;
}
@NotNull
@Override
public String getPresentableName() {
return "boolean";
@@ -162,11 +170,13 @@ public interface JavaPostfixTemplateExpressionCondition extends Condition<PsiExp
return JavaPostfixTemplatesUtils.isNumber(element.getType());
}
@NotNull
@Override
public String getId() {
return ID;
}
@NotNull
@Override
public String getPresentableName() {
return "number";
@@ -192,11 +202,13 @@ public interface JavaPostfixTemplateExpressionCondition extends Condition<PsiExp
return JavaPostfixTemplatesUtils.isNotPrimitiveTypeExpression(element);
}
@NotNull
@Override
public String getId() {
return ID;
}
@NotNull
@Override
public String getPresentableName() {
return "not primitive type";
@@ -222,11 +234,13 @@ public interface JavaPostfixTemplateExpressionCondition extends Condition<PsiExp
return JavaPostfixTemplatesUtils.isArray(element.getType());
}
@NotNull
@Override
public String getId() {
return ID;
}
@NotNull
@Override
public String getPresentableName() {
return "array";
@@ -86,7 +86,8 @@ public abstract class JavaPostfixTemplatesUtils {
};
}
public static PostfixTemplateExpressionSelector selectorAllExpressionsWithCurrentOffset(final Condition<PsiElement> additionalFilter) {
@NotNull
public static PostfixTemplateExpressionSelector selectorAllExpressionsWithCurrentOffset(@Nullable Condition<PsiElement> additionalFilter) {
return new PostfixTemplateExpressionSelectorBase(additionalFilter) {
@Override
protected List<PsiElement> getNonFilteredExpressions(@NotNull PsiElement context, @NotNull Document document, int offset) {
@@ -98,7 +99,7 @@ public abstract class JavaPostfixTemplatesUtils {
@Override
public List<PsiElement> getExpressions(@NotNull PsiElement context, @NotNull Document document, int offset) {
if (DumbService.getInstance(context.getProject()).isDumb()) return Collections.emptyList();
List<PsiElement> expressions = super.getExpressions(context, document, offset);
if (!expressions.isEmpty()) return expressions;
@@ -0,0 +1,149 @@
// 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.codeInsight.template.postfix.settings;
import com.intellij.codeInsight.template.impl.TemplateEditorUtil;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplateProvider;
import com.intellij.codeInsight.template.postfix.templates.editable.EditablePostfixTemplateWithConditions;
import com.intellij.codeInsight.template.postfix.templates.editable.PostfixTemplateEditor;
import com.intellij.codeInsight.template.postfix.templates.editable.PostfixTemplateExpressionCondition;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.psi.PsiElement;
import com.intellij.ui.AnActionButton;
import com.intellij.ui.ColoredListCellRenderer;
import com.intellij.ui.ListUtil;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBList;
import com.intellij.util.ObjectUtils;
import com.intellij.util.ui.DialogUtil;
import com.intellij.util.ui.FormBuilder;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
public abstract class PostfixTemplateEditorBase<ExpressionType extends PsiElement,
Condition extends PostfixTemplateExpressionCondition<ExpressionType>> implements PostfixTemplateEditor {
@NotNull protected final PostfixTemplateProvider myProvider;
@NotNull protected final Editor myTemplateEditor;
@NotNull protected final JBList<Condition> myExpressionTypesList;
@NotNull protected final DefaultListModel<Condition> myExpressionTypesListModel;
@NotNull protected final JPanel myTemplateEditorPanel;
@NotNull protected final JPanel myExpressionTypesPanel;
@NotNull protected final JBCheckBox myApplyToTheTopmostJBCheckBox;
@NotNull protected final JPanel myEditTemplateAndConditionsPanel;
@NotNull protected final JBLabel myExpressionVariableHint;
public PostfixTemplateEditorBase(@NotNull PostfixTemplateProvider provider) {
this(provider, createSimpleEditor());
}
public PostfixTemplateEditorBase(@NotNull PostfixTemplateProvider provider,
@NotNull Editor templateEditor) {
myProvider = provider;
myTemplateEditor = templateEditor;
myApplyToTheTopmostJBCheckBox = new JBCheckBox("Apply to the &topmost expression");
DialogUtil.registerMnemonic(myApplyToTheTopmostJBCheckBox, '&');
myTemplateEditorPanel = new JPanel(new BorderLayout());
myTemplateEditorPanel.add(myTemplateEditor.getComponent());
myExpressionVariableHint = new JBLabel("Use $EXPR$ variable to refer target expression");
UIUtil.applyStyle(UIUtil.ComponentStyle.SMALL, myExpressionVariableHint);
myExpressionVariableHint.setFontColor(UIUtil.FontColor.BRIGHTER);
myExpressionTypesListModel = JBList.createDefaultListModel();
myExpressionTypesList = new JBList<>(myExpressionTypesListModel);
myExpressionTypesList.setCellRenderer(new ColoredListCellRenderer<PostfixTemplateExpressionCondition<?>>() {
@Override
protected void customizeCellRenderer(@NotNull JList<? extends PostfixTemplateExpressionCondition<?>> list,
PostfixTemplateExpressionCondition<?> value,
int index,
boolean selected,
boolean hasFocus) {
append(value.getPresentableName());
}
});
myExpressionTypesPanel = new JPanel(new BorderLayout());
myExpressionTypesPanel.add(ToolbarDecorator.createDecorator(myExpressionTypesList)
.setAddAction(button -> showAddExpressionTypePopup(button))
.setRemoveAction(button -> ListUtil.removeSelectedItems(myExpressionTypesList))
.disableUpDownActions()
.createPanel());
myExpressionTypesPanel.setMinimumSize(new Dimension(-1, 100));
FormBuilder builder = FormBuilder.createFormBuilder();
builder.addLabeledComponent("Applicable expression types:", myExpressionTypesPanel, true);
builder.addComponent(myApplyToTheTopmostJBCheckBox);
builder.addComponent(myTemplateEditorPanel);
builder.addComponent(myExpressionVariableHint);
myEditTemplateAndConditionsPanel = builder.getPanel();
}
@NotNull
protected static Editor createEditor(@NotNull Project project, @NotNull Document document) {
return TemplateEditorUtil.createEditor(false, document, project);
}
@NotNull
private static Editor createSimpleEditor() {
Project defaultProject = ProjectManager.getInstance().getDefaultProject();
return createEditor(defaultProject, EditorFactory.getInstance().createDocument(""));
}
protected final void showAddExpressionTypePopup(@NotNull AnActionButton button) {
DefaultActionGroup group = new DefaultActionGroup();
fillConditions(group);
DataContext context = DataManager.getInstance().getDataContext(button.getContextComponent());
ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup(null, group, context,
JBPopupFactory.ActionSelectionAid.ALPHA_NUMBERING, true, null);
popup.show(ObjectUtils.assertNotNull(button.getPreferredPopupPoint()));
}
protected abstract void fillConditions(@NotNull DefaultActionGroup group);
public void setTemplate(@Nullable PostfixTemplate rawTemplate) {
if (!(rawTemplate instanceof EditablePostfixTemplateWithConditions)) return;
//noinspection unchecked
EditablePostfixTemplateWithConditions<ExpressionType, Condition> template = (EditablePostfixTemplateWithConditions)rawTemplate;
myExpressionTypesListModel.clear();
for (Condition condition : template.getExpressionConditions()) {
myExpressionTypesListModel.addElement(condition);
}
myApplyToTheTopmostJBCheckBox.setSelected(template.isUseTopmostExpression());
ApplicationManager.getApplication()
.runWriteAction(() -> myTemplateEditor.getDocument().setText(template.getLiveTemplate().getString()));
}
@Override
public String getHelpId() {
return "reference.custom.postfix.templates";
}
@Override
public void dispose() {
TemplateEditorUtil.disposeTemplateEditor(myTemplateEditor);
}
}
@@ -1,23 +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.codeInsight.template.postfix.templates;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.codeInsight.template.impl.TemplateSettings;
import com.intellij.codeInsight.template.postfix.settings.PostfixTemplateStorage;
import com.intellij.codeInsight.template.postfix.templates.editable.EditablePostfixTemplate;
import com.intellij.codeInsight.template.postfix.templates.editable.EditablePostfixTemplateWithConditions;
import com.intellij.codeInsight.template.postfix.templates.editable.PostfixChangedBuiltinTemplate;
import com.intellij.codeInsight.template.postfix.templates.editable.PostfixTemplateExpressionCondition;
import com.intellij.lang.surroundWith.Surrounder;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.UniqueNameGenerator;
import kotlin.LazyKt;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
public abstract class PostfixTemplatesUtils {
public static final String CONDITION_TAG = "condition";
public static final String CONDITIONS_TAG = "conditions";
public static final String TOPMOST_ATTR = "topmost";
private PostfixTemplatesUtils() {
}
@@ -66,4 +81,58 @@ public abstract class PostfixTemplatesUtils {
}
return UniqueNameGenerator.generateUniqueName(templateKey + "@userDefined", usedIds);
}
public static void writeExternalTemplate(@NotNull PostfixTemplate template, @NotNull Element parentElement) {
if (template instanceof EditablePostfixTemplateWithConditions) {
parentElement.setAttribute(TOPMOST_ATTR, String.valueOf(((EditablePostfixTemplateWithConditions)template).isUseTopmostExpression()));
Element conditionsTag = new Element(CONDITIONS_TAG);
//noinspection unchecked
Set<? extends PostfixTemplateExpressionCondition<? extends PsiElement>> conditions =
(Set<? extends PostfixTemplateExpressionCondition<? extends PsiElement>>)((EditablePostfixTemplateWithConditions)template)
.getExpressionConditions();
for (PostfixTemplateExpressionCondition<? extends PsiElement> condition : conditions) {
Element element = new Element(CONDITION_TAG);
condition.serializeTo(element);
conditionsTag.addContent(element);
}
parentElement.addContent(conditionsTag);
}
Element templateTag = TemplateSettings.serializeTemplate(((EditablePostfixTemplate)template).getLiveTemplate(), null,
LazyKt.lazyOf(Collections.emptyMap()));
parentElement.addContent(templateTag);
}
@NotNull
public static <T extends PostfixTemplateExpressionCondition> Set<T> readExternalConditions(@NotNull Element template,
@NotNull Function<Element, T> conditionFactory) {
Element conditionsElement = template.getChild(CONDITIONS_TAG);
if (conditionsElement != null) {
Set<T> conditions = new LinkedHashSet<>();
for (Element conditionElement : conditionsElement.getChildren(CONDITION_TAG)) {
T fun = conditionFactory.fun(conditionElement);
if (fun != null) {
ContainerUtil.addIfNotNull(conditions, fun);
}
}
return conditions;
}
return Collections.emptySet();
}
@Nullable
public static TemplateImpl readExternalLiveTemplate(@NotNull Element template, @NotNull PostfixTemplateProvider provider) {
Element templateChild = template.getChild(TemplateSettings.TEMPLATE);
if (templateChild == null) return null;
return TemplateSettings.readTemplateFromElement("", templateChild, provider.getClass().getClassLoader());
}
public static boolean readExternalTopmostAttribute(@NotNull Element template) {
return Boolean.parseBoolean(template.getAttributeValue(TOPMOST_ATTR));
}
}
@@ -0,0 +1,90 @@
// 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.codeInsight.template.postfix.templates.editable;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplateProvider;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.Set;
public abstract class EditablePostfixTemplateWithConditions<ExpressionType extends PsiElement,
ConditionType extends PostfixTemplateExpressionCondition<ExpressionType>>
extends EditablePostfixTemplate {
@NotNull protected final Set<ConditionType> myExpressionConditions;
protected final boolean myUseTopmostExpression;
protected EditablePostfixTemplateWithConditions(@NotNull String templateId,
@NotNull String templateName,
@NotNull TemplateImpl liveTemplate,
@NotNull String example,
@NotNull Set<ConditionType> expressionConditions,
boolean useTopmostExpression,
@NotNull PostfixTemplateProvider provider) {
super(templateId, templateName, liveTemplate, example, provider);
myExpressionConditions = expressionConditions;
myUseTopmostExpression = useTopmostExpression;
}
@NotNull
protected static TemplateImpl createTemplate(@NotNull String templateText) {
TemplateImpl template = new TemplateImpl("fakeKey", templateText, "");
template.setToReformat(true);
template.parseSegments();
return template;
}
@NotNull
@Override
protected PsiElement getElementToRemove(@NotNull PsiElement element) {
if (myUseTopmostExpression) {
return getTopmostExpression(element);
}
return element;
}
@NotNull
protected abstract PsiElement getTopmostExpression(@NotNull PsiElement element);
@NotNull
public Set<ConditionType> getExpressionConditions() {
return myExpressionConditions;
}
public boolean isUseTopmostExpression() {
return myUseTopmostExpression;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
EditablePostfixTemplateWithConditions<?, ?> that = (EditablePostfixTemplateWithConditions<?, ?>)o;
return myUseTopmostExpression == that.myUseTopmostExpression &&
Objects.equals(myExpressionConditions, that.myExpressionConditions);
}
@NotNull
protected Condition<PsiElement> getExpressionCompositeCondition() {
return e -> {
for (ConditionType condition : myExpressionConditions) {
//noinspection unchecked
if (condition.value((ExpressionType)e)) {
return true;
}
}
return myExpressionConditions.isEmpty();
};
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), myExpressionConditions, myUseTopmostExpression);
}
}
@@ -0,0 +1,33 @@
// 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.codeInsight.template.postfix.templates.editable;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.PsiElement;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
public interface PostfixTemplateExpressionCondition<T extends PsiElement> extends Condition<T> {
String ID_ATTR = "id";
/**
*
* @return
*/
@NotNull
String getPresentableName();
/**
* @return id for serialization
*/
@NotNull
String getId();
boolean equals(Object o);
int hashCode();
default void serializeTo(@NotNull Element element) {
element.setAttribute(ID_ATTR, getId());
}
}