SSR: easier to use "contained with search template" constraints

This commit is contained in:
Bas Leijdekkers
2017-05-07 20:53:20 +02:00
parent edb817d1b4
commit 4212918a97
9 changed files with 99 additions and 52 deletions
@@ -353,7 +353,7 @@ public class MatcherImpl {
*/
protected List<MatchResult> 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);
@@ -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);
}
@@ -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<MatchResult> results = matcher.matchByDownUp(match, myMatchOptions);
public boolean match(PsiElement patternNode, PsiElement matchedNode, MatchContext context) {
final List<MatchResult> 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;
}
}
@@ -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<Element> {
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<Configuration> configurations, final String name) {
for(Configuration config:configurations) {
if (config.getName().equals(name)) return config;
@@ -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<EditorTextField> 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());
}
@@ -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<Configuration> historyModel;
private final JList historyList;
private final JList<Configuration> 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<Configuration> {
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 + ')',
@@ -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);
}
}
@@ -300,9 +300,9 @@
<clientProperties>
<BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithIndent"/>
</clientProperties>
<border type="none" title="Contained in constraints"/>
<border type="none" title-resource-bundle="messages/SSRBundle" title-key="var.constraints.within.pattern.border"/>
<children>
<component id="7003f" class="com.intellij.ui.ComboboxWithBrowseButton" binding="withinCombo">
<component id="ecda0" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="withinTextField">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
@@ -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