From 4212918a971d1760d9834119b2b79926fa4656d5 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Sun, 7 May 2017 18:33:08 +0200 Subject: [PATCH] SSR: easier to use "contained with search template" constraints --- .../impl/matcher/MatcherImpl.java | 4 +- .../matcher/compiler/PatternCompiler.java | 3 +- .../matcher/predicates/WithinPredicate.java | 42 +++++++++++-------- .../plugin/ui/ConfigurationManager.java | 11 ++++- .../plugin/ui/EditVarConstraintsDialog.java | 22 +++++----- .../plugin/ui/ExistingTemplatesComponent.java | 36 +++++++++++----- .../plugin/ui/SelectTemplateDialog.java | 28 +++++++++---- .../plugin/ui/VarConstraints.form | 4 +- .../source/messages/SSRBundle.properties | 1 + 9 files changed, 99 insertions(+), 52 deletions(-) diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatcherImpl.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatcherImpl.java index 9f4a7aef4451..812bb33b1dd6 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatcherImpl.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatcherImpl.java @@ -353,7 +353,7 @@ public class MatcherImpl { */ protected List testFindMatches(String source, MatchOptions options, - boolean filePattern, + boolean fileContext, FileType sourceFileType, String sourceExtension, boolean physicalSourceFile) @@ -363,7 +363,7 @@ public class MatcherImpl { try { PsiElement[] elements = MatcherImplUtil.createSourceTreeFromText(source, - filePattern ? PatternTreeContext.File : PatternTreeContext.Block, + fileContext ? PatternTreeContext.File : PatternTreeContext.Block, sourceFileType, sourceExtension, project, physicalSourceFile); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java index ba0a1c7c25f0..abc2e9000886 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java @@ -459,8 +459,7 @@ public class PatternCompiler { ); if (!StringUtil.isEmptyOrSpaces(constraint.getWithinConstraint())) { - MatchPredicate predicate = - new WithinPredicate(Configuration.CONTEXT_VAR_NAME, constraint.getWithinConstraint(), options.getFileType(), project); + MatchPredicate predicate = new WithinPredicate(constraint.getWithinConstraint(), options.getFileType(), project); if (constraint.isInvertWithinConstraint()) { predicate = new NotPredicate(predicate); } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/WithinPredicate.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/WithinPredicate.java index 128fabfa3f2c..7cf265abde05 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/WithinPredicate.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/WithinPredicate.java @@ -20,40 +20,48 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.structuralsearch.MalformedPatternException; import com.intellij.structuralsearch.MatchOptions; import com.intellij.structuralsearch.MatchResult; import com.intellij.structuralsearch.Matcher; import com.intellij.structuralsearch.impl.matcher.MatchContext; +import com.intellij.structuralsearch.impl.matcher.handlers.MatchPredicate; +import com.intellij.structuralsearch.plugin.ui.Configuration; +import com.intellij.structuralsearch.plugin.ui.ConfigurationManager; import java.util.List; /** * @author Maxim.Mossienko */ -public class WithinPredicate extends AbstractStringBasedPredicate { +public class WithinPredicate extends MatchPredicate { private final MatchOptions myMatchOptions; - private Matcher matcher; + private final Matcher matcher; - public WithinPredicate(String name, String within, FileType fileType, Project project) { - super(name, within); - myMatchOptions = new MatchOptions(); - - myMatchOptions.setLooseMatching(true); - myMatchOptions.setFileType(fileType); - final String unquoted = StringUtil.unquoteString(within); - if (!unquoted.equals(within)) { - myMatchOptions.fillSearchCriteria(unquoted); - matcher = new Matcher(project, myMatchOptions); - } else { - assert false; + public WithinPredicate(String within, FileType fileType, Project project) { + if (StringUtil.isQuotedString(within)) { + // keep old configurations working + myMatchOptions = new MatchOptions(); + myMatchOptions.setLooseMatching(true); + myMatchOptions.setFileType(fileType); + myMatchOptions.fillSearchCriteria(StringUtil.unquoteString(within)); } + else { + final Configuration configuration = ConfigurationManager.getInstance(project).findConfigurationByName(within); + if (configuration == null) { + throw new MalformedPatternException(); + } + myMatchOptions = configuration.getMatchOptions(); + } + + matcher = new Matcher(project, myMatchOptions); } @Override - public boolean match(PsiElement node, PsiElement match, int start, int end, MatchContext context) { - final List results = matcher.matchByDownUp(match, myMatchOptions); + public boolean match(PsiElement patternNode, PsiElement matchedNode, MatchContext context) { + final List results = matcher.matchByDownUp(matchedNode, myMatchOptions); for (MatchResult result : results) { - if (PsiTreeUtil.isAncestor(result.getMatch(), match, false)) { + if (PsiTreeUtil.isAncestor(result.getMatch(), matchedNode, false)) { return true; } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ConfigurationManager.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ConfigurationManager.java index a691109012b7..19e39e8ade6a 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ConfigurationManager.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ConfigurationManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.NonEmptyInputValidator; import com.intellij.structuralsearch.SSRBundle; +import com.intellij.structuralsearch.StructuralSearchUtil; import com.intellij.structuralsearch.plugin.replace.ui.ReplaceConfiguration; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -154,6 +155,14 @@ public class ConfigurationManager implements PersistentStateComponent { return configurations; } + public Configuration findConfigurationByName(String name) { + final Configuration configuration = findConfigurationByName(configurations, name); + if (configuration != null) { + return configuration; + } + return findConfigurationByName(StructuralSearchUtil.getPredefinedTemplates(), name); + } + public static Configuration findConfigurationByName(final Collection configurations, final String name) { for(Configuration config:configurations) { if (config.getName().equals(name)) return config; diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java index 09172ae5cf2c..3a3748b70a3f 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java @@ -37,6 +37,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComponentWithBrowseButton; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.psi.PsiDocumentManager; @@ -47,7 +48,6 @@ import com.intellij.structuralsearch.impl.matcher.predicates.ScriptLog; import com.intellij.structuralsearch.impl.matcher.predicates.ScriptSupport; import com.intellij.structuralsearch.plugin.replace.ReplaceOptions; import com.intellij.structuralsearch.plugin.replace.ui.ReplaceConfiguration; -import com.intellij.ui.ComboboxWithBrowseButton; import com.intellij.ui.EditorTextField; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; @@ -96,7 +96,7 @@ class EditVarConstraintsDialog extends DialogWrapper { ComponentWithBrowseButton customScriptCode; JCheckBox maxoccursUnlimited; - ComboboxWithBrowseButton withinCombo; + TextFieldWithBrowseButton withinTextField; private JPanel containedInConstraints; private JCheckBox invertWithinIn; private JPanel expressionConstraints; @@ -168,24 +168,25 @@ class EditVarConstraintsDialog extends DialogWrapper { formalArgType.getDocument().addDocumentListener(new MyDocumentListener(formalArgTypeWithinHierarchy, invertFormalArgType)); containedInConstraints.setVisible(false); - withinCombo.getComboBox().setEditable(true); - withinCombo.getButton().addActionListener(new ActionListener() { + withinTextField.setEditable(false); + withinTextField.getButton().addActionListener(new ActionListener() { @Override public void actionPerformed(@NotNull final ActionEvent e) { final SelectTemplateDialog dialog = new SelectTemplateDialog(project, false, false); + dialog.selectConfiguration(withinTextField.getText().trim()); dialog.show(); if (dialog.getExitCode() == OK_EXIT_CODE) { final Configuration[] selectedConfigurations = dialog.getSelectedConfigurations(); if (selectedConfigurations.length == 1) { - withinCombo.getComboBox().getEditor().setItem(selectedConfigurations[0].getMatchOptions().getSearchPattern()); // TODO: + withinTextField.setText(selectedConfigurations[0].getName()); } } } }); boolean hasContextVar = false; - for(Variable var:variables) { + for (Variable var : variables) { if (Configuration.CONTEXT_VAR_NAME.equals(var.getName())) { hasContextVar = true; break; } @@ -361,8 +362,9 @@ class EditVarConstraintsDialog extends DialogWrapper { varInfo.setNameOfFormalArgType(formalArgType.getDocument().getText()); saveScriptInfo(varInfo); - final String withinConstraint = (String)withinCombo.getComboBox().getEditor().getItem(); - varInfo.setWithinConstraint(withinConstraint.length() > 0 ? "\"" + withinConstraint +"\"":""); + final String withinConstraint = withinTextField.getText().trim(); + final Configuration configuration = ConfigurationManager.getInstance(myProject).findConfigurationByName(withinConstraint); + varInfo.setWithinConstraint(configuration == null && withinConstraint.length() > 0 ? '"' + withinConstraint + '"' : withinConstraint); varInfo.setInvertWithinConstraint(invertWithinIn.isSelected()); } @@ -420,7 +422,7 @@ class EditVarConstraintsDialog extends DialogWrapper { formalArgType.getDocument().setText(""); customScriptCode.getChildComponent().setText(""); - withinCombo.getComboBox().getEditor().setItem(""); + withinTextField.setText(""); invertWithinIn.setSelected(false); } else { applyWithinTypeHierarchy.setSelected(varInfo.isWithinHierarchy()); @@ -450,7 +452,7 @@ class EditVarConstraintsDialog extends DialogWrapper { formalArgType.getDocument().setText(varInfo.getNameOfFormalArgType()); restoreScriptCode(varInfo); - withinCombo.getComboBox().getEditor().setItem(StringUtil.unquoteString(varInfo.getWithinConstraint())); + withinTextField.setText(StringUtil.unquoteString(varInfo.getWithinConstraint())); invertWithinIn.setSelected(varInfo.isInvertWithinConstraint()); } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ExistingTemplatesComponent.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ExistingTemplatesComponent.java index dfbdb8b54ff8..977eed14c5b8 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ExistingTemplatesComponent.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/ExistingTemplatesComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ import com.intellij.ui.treeStructure.Tree; import com.intellij.util.containers.Convertor; import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.UIUtil; +import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -55,7 +56,7 @@ public class ExistingTemplatesComponent { private final DefaultMutableTreeNode userTemplatesNode; private final JComponent panel; private final CollectionListModel historyModel; - private final JList historyList; + private final JList historyList; private final JComponent historyPanel; private DialogWrapper owner; private final Project project; @@ -150,7 +151,7 @@ public class ExistingTemplatesComponent { historyPanel = new JPanel(new BorderLayout()); historyPanel.add(BorderLayout.NORTH, new JLabel(SSRBundle.message("used.templates"))); - historyList = new JBList(historyModel); + historyList = new JBList<>(historyModel); historyPanel.add(BorderLayout.CENTER, ScrollPaneFactory.createScrollPane(historyList)); historyList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); historyList.setSelectedIndex(0); @@ -160,6 +161,23 @@ public class ExistingTemplatesComponent { configureSelectTemplateAction(historyList); } + public void selectConfiguration(String name) { + final DefaultMutableTreeNode root = (DefaultMutableTreeNode)patternTreeModel.getRoot(); + final int count = root.getChildCount(); + for (int i = 0; i < count; i++) { + final DefaultMutableTreeNode category = (DefaultMutableTreeNode)root.getChildAt(i); + final int count1 = category.getChildCount(); + for (int j = 0; j < count1; j++ ) { + final DefaultMutableTreeNode leaf = (DefaultMutableTreeNode)category.getChildAt(j); + final Configuration configuration = (Configuration)leaf.getUserObject(); + if (name.equals(configuration.getName())) { + TreeUtil.selectInTree(leaf, false, patternTree, false); + return; + } + } + } + } + public void setUserTemplates(ConfigurationManager configurationManager) { userTemplatesNode.removeAllChildren(); if (configurationManager.getConfigurations() != null) { @@ -226,7 +244,7 @@ public class ExistingTemplatesComponent { return ServiceManager.getService(project, ExistingTemplatesComponent.class); } - private static class ExistingTemplatesListCellRenderer extends ColoredListCellRenderer { + private static class ExistingTemplatesListCellRenderer extends ColoredListCellRenderer { private final ListSpeedSearch mySpeedSearch; @@ -235,18 +253,14 @@ public class ExistingTemplatesComponent { } @Override - protected void customizeCellRenderer(@NotNull JList list, Object value, int index, boolean selected, boolean focus) { - if (!(value instanceof Configuration)) { - return; - } - final Configuration configuration = (Configuration)value; + protected void customizeCellRenderer(@NotNull JList list, Configuration value, int index, boolean selected, boolean focus) { final Color background = (selected && !focus) ? UIUtil.getListUnfocusedSelectionBackground() : UIUtil.getListBackground(selected); final Color foreground = UIUtil.getListForeground(selected); setPaintFocusBorder(false); - SearchUtil.appendFragments(mySpeedSearch.getEnteredPrefix(), configuration.getName(), SimpleTextAttributes.STYLE_PLAIN, + SearchUtil.appendFragments(mySpeedSearch.getEnteredPrefix(), value.getName(), SimpleTextAttributes.STYLE_PLAIN, foreground, background, this); - final long created = configuration.getCreated(); + final long created = value.getCreated(); if (created > 0) { final String createdString = DateFormatUtil.formatPrettyDateTime(created); append(" (" + createdString + ')', diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SelectTemplateDialog.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SelectTemplateDialog.java index f7a1227e0834..8abd7cd698f7 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SelectTemplateDialog.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SelectTemplateDialog.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.structuralsearch.plugin.ui; import com.intellij.codeInsight.template.TemplateContextType; @@ -9,7 +24,6 @@ import com.intellij.openapi.ui.Splitter; import com.intellij.structuralsearch.MatchOptions; import com.intellij.structuralsearch.SSRBundle; import com.intellij.structuralsearch.plugin.replace.ui.ReplaceConfiguration; -import com.intellij.util.Producer; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -27,11 +41,9 @@ import java.util.ArrayList; import java.util.Collection; /** - * Created by IntelliJ IDEA. - * User: Maxim.Mossienko + * @author Maxim.Mossienko * Date: Apr 23, 2004 * Time: 5:03:52 PM - * To change this template use File | Settings | File Templates. */ public class SelectTemplateDialog extends DialogWrapper { private final boolean showHistory; @@ -80,9 +92,7 @@ public class SelectTemplateDialog extends DialogWrapper { class MySelectionListener implements TreeSelectionListener, ListSelectionListener { public void valueChanged(TreeSelectionEvent e) { if (e.getNewLeadSelectionPath() != null) { - setPatternFromNode( - (DefaultMutableTreeNode)e.getNewLeadSelectionPath().getLastPathComponent() - ); + setPatternFromNode((DefaultMutableTreeNode)e.getNewLeadSelectionPath().getLastPathComponent()); } } @@ -298,4 +308,8 @@ public class SelectTemplateDialog extends DialogWrapper { return configurations.toArray(new Configuration[configurations.size()]); } } + + public void selectConfiguration(String name) { + existingTemplatesComponent.selectConfiguration(name); + } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/VarConstraints.form b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/VarConstraints.form index 175305424788..5006ae64963f 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/VarConstraints.form +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/VarConstraints.form @@ -300,9 +300,9 @@ - + - + diff --git a/platform/structuralsearch/source/messages/SSRBundle.properties b/platform/structuralsearch/source/messages/SSRBundle.properties index 4e562c4fa397..c8d9fd8a070a 100644 --- a/platform/structuralsearch/source/messages/SSRBundle.properties +++ b/platform/structuralsearch/source/messages/SSRBundle.properties @@ -192,6 +192,7 @@ remove.template.action.name=Remove Template modify.editor.content.command.name=modify editor content var.constraints.variables.border=Variables var.constraints.occurrences.count.border=Occurrences count +var.constraints.within.pattern.border=Contained in search template var.constraints.script.constraints.border=Script constraints var.constraints.expression.constraints.border=Expression constraints var.constraints.text.constraints.border=Text constraints