mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
regex: new Check Regexp UI phase 1 (IDEA-242695)
GitOrigin-RevId: f3b8200dfb921f267199f25da284c3e3715a6b45
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9861e249f2
commit
8409c605ff
@@ -91,13 +91,10 @@ inspection.warning.potential.exponential.backtracking=Potential exponential back
|
||||
inspection.warning.redundant.character.escape.0.in.regexp=Redundant character escape <code>{0}</code> in RegExp
|
||||
inspection.warning.redundant.nested.character.class=Redundant nested character class
|
||||
inspection.warning.single.character.alternation.in.regexp=Single character alternation in RegExp
|
||||
intention.balloon.bad.pattern=Bad pattern
|
||||
intention.balloon.matches=Matches!
|
||||
intention.balloon.more.input.expected=More input expected
|
||||
intention.balloon.no.match=No match
|
||||
intention.balloon.pattern.is.too.complex=Pattern is too complex
|
||||
intention.name.check.regexp=Check RegExp
|
||||
intention.name.simplify.quantifier=Simplify quantifier
|
||||
label.regexp=&RegExp:
|
||||
label.sample=&Sample:
|
||||
parse.error.category.shorthand.not.allowed.in.this.regular.expression.dialect=Category shorthand not allowed in this regular expression dialect
|
||||
parse.error.character.class.expected=Character class expected
|
||||
parse.error.character.expected=Character expected
|
||||
@@ -137,6 +134,11 @@ surrounder.negative.lookbehind.pattern=Negative Lookbehind (?<!pattern)
|
||||
surrounder.non.capturing.group.pattern=Non-Capturing Group (?:pattern)
|
||||
surrounder.positive.lookahead.pattern=Positive Lookahead (?=pattern)
|
||||
surrounder.positive.lookbehind.pattern=Positive Lookbehind (?<=pattern)
|
||||
tooltip.bad.pattern=Bad regular expression pattern
|
||||
tooltip.matches=Expression.and example match!
|
||||
tooltip.more.input.expected=More example input expected
|
||||
tooltip.no.match=Expression and example do not match
|
||||
tooltip.pattern.is.too.complex=Regular expression pattern is too complex
|
||||
warning.duplicate.character.0.inside.character.class=Duplicate character ''{0}'' inside character class
|
||||
warning.duplicate.predefined.character.class.0.inside.character.class=Duplicate predefined character class ''{0}'' inside character class
|
||||
weak.warning.fixed.repetition.range=Fixed repetition range
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.intellij.lang.regexp.intention.CheckRegExpForm">
|
||||
<grid id="38faf" binding="myRootPanel" custom-create="true" layout-manager="GridLayoutManager" row-count="4" 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="376" height="163"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="5de69" class="com.intellij.ui.components.JBLabel" binding="myMessage">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="4" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<componentStyle value="SMALL"/>
|
||||
<text value="Red means I can't hear you!"/>
|
||||
</properties>
|
||||
</component>
|
||||
<vspacer id="dd293">
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="2" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
<component id="b01c9" 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>
|
||||
<preferredSize width="55" height="16"/>
|
||||
<text value="RegExp:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="ec7ec" 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>
|
||||
<preferredSize width="55" height="16"/>
|
||||
<text value="Sample:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="d8697" class="com.intellij.ui.EditorTextField" binding="myRegExp" custom-create="true">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="47807" class="com.intellij.ui.EditorTextField" binding="mySampleText" custom-create="true">
|
||||
<constraints>
|
||||
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
@@ -1,13 +1,16 @@
|
||||
// Copyright 2000-2020 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 org.intellij.lang.regexp.intention;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CustomShortcutSet;
|
||||
import com.intellij.openapi.application.*;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.actions.IncrementalFindAction;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
@@ -17,10 +20,9 @@ import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.fileTypes.PlainTextFileType;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.Balloon;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.NlsContexts;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
@@ -28,8 +30,8 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiLanguageInjectionHost;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
import com.intellij.ui.EditorTextField;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.ui.components.JBScrollBar;
|
||||
import com.intellij.ui.scale.JBUIScale;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
@@ -51,27 +53,17 @@ public class CheckRegExpForm {
|
||||
|
||||
private static final String LAST_EDITED_REGEXP = "last.edited.regexp";
|
||||
|
||||
private static final JBColor BACKGROUND_COLOR_MATCH = new JBColor(0xe7fadb, 0x445542);
|
||||
private static final JBColor BACKGROUND_COLOR_NOMATCH = new JBColor(0xffb1a0, 0x6e2b28);
|
||||
private final EditorTextField mySampleText;
|
||||
|
||||
private final PsiFile myRegexpFile;
|
||||
|
||||
private EditorTextField mySampleText;
|
||||
|
||||
private EditorTextField myRegExp;
|
||||
private JPanel myRootPanel;
|
||||
private JBLabel myMessage;
|
||||
private Project myProject;
|
||||
private final JPanel myRootPanel;
|
||||
private final JBLabel myRegExpIcon = new JBLabel();
|
||||
private final JBLabel mySampleIcon = new JBLabel();
|
||||
|
||||
public CheckRegExpForm(@NotNull PsiFile regexpFile) {
|
||||
myRegexpFile = regexpFile;
|
||||
}
|
||||
final Project project = regexpFile.getProject();
|
||||
final Document document = PsiDocumentManager.getInstance(project).getDocument(regexpFile);
|
||||
|
||||
private void createUIComponents() {
|
||||
myProject = myRegexpFile.getProject();
|
||||
Document document = PsiDocumentManager.getInstance(myProject).getDocument(myRegexpFile);
|
||||
|
||||
final Language language = myRegexpFile.getLanguage();
|
||||
final Language language = regexpFile.getLanguage();
|
||||
final LanguageFileType fileType;
|
||||
if (language instanceof RegExpLanguage) {
|
||||
fileType = RegExpLanguage.INSTANCE.getAssociatedFileType();
|
||||
@@ -80,7 +72,7 @@ public class CheckRegExpForm {
|
||||
// for correct syntax highlighting
|
||||
fileType = new RegExpFileType(language);
|
||||
}
|
||||
myRegExp = new EditorTextField(document, myProject, fileType, false, false) {
|
||||
final EditorTextField myRegExp = new EditorTextField(document, project, fileType, false, false) {
|
||||
@Override
|
||||
protected EditorEx createEditor() {
|
||||
final EditorEx editor = super.createEditor();
|
||||
@@ -95,8 +87,10 @@ public class CheckRegExpForm {
|
||||
setupBorder(editor);
|
||||
}
|
||||
};
|
||||
final String sampleText = PropertiesComponent.getInstance(myProject).getValue(LAST_EDITED_REGEXP, "Sample Text");
|
||||
mySampleText = new EditorTextField(sampleText, myProject, PlainTextFileType.INSTANCE) {
|
||||
setupIcon(myRegExp, myRegExpIcon);
|
||||
|
||||
final String sampleText = PropertiesComponent.getInstance(project).getValue(LAST_EDITED_REGEXP, "Sample Text");
|
||||
mySampleText = new EditorTextField(sampleText, project, PlainTextFileType.INSTANCE) {
|
||||
@Override
|
||||
protected EditorEx createEditor() {
|
||||
final EditorEx editor = super.createEditor();
|
||||
@@ -110,12 +104,14 @@ public class CheckRegExpForm {
|
||||
setupBorder(editor);
|
||||
}
|
||||
};
|
||||
|
||||
setupIcon(mySampleText, mySampleIcon);
|
||||
mySampleText.setOneLineMode(false);
|
||||
int preferredWidth = Math.max(JBUIScale.scale(250), myRegExp.getPreferredSize().width);
|
||||
final int preferredWidth = Math.max(JBUIScale.scale(250), myRegExp.getPreferredSize().width);
|
||||
myRegExp.setPreferredWidth(preferredWidth);
|
||||
mySampleText.setPreferredWidth(preferredWidth);
|
||||
|
||||
myRootPanel = new JPanel(new BorderLayout()) {
|
||||
myRootPanel = new JPanel(new GridBagLayout()) {
|
||||
Disposable disposable;
|
||||
Alarm updater;
|
||||
|
||||
@@ -132,7 +128,7 @@ public class CheckRegExpForm {
|
||||
registerFocusShortcut(mySampleText, "TAB", myRegExp);
|
||||
|
||||
updater = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, disposable);
|
||||
DocumentListener documentListener = new DocumentListener() {
|
||||
final DocumentListener documentListener = new DocumentListener() {
|
||||
@Override
|
||||
public void documentChanged(@NotNull DocumentEvent e) {
|
||||
update();
|
||||
@@ -146,7 +142,7 @@ public class CheckRegExpForm {
|
||||
}
|
||||
|
||||
private void registerFocusShortcut(JComponent source, String shortcut, EditorTextField target) {
|
||||
AnAction action = new AnAction() {
|
||||
final AnAction action = new AnAction() {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
IdeFocusManager.findInstance().requestFocus(target.getFocusTarget(), true);
|
||||
@@ -159,8 +155,8 @@ public class CheckRegExpForm {
|
||||
updater.cancelAllRequests();
|
||||
if (!updater.isDisposed()) {
|
||||
updater.addRequest(() -> {
|
||||
final RegExpMatchResult result = isMatchingText(myRegexpFile, myRegExp.getText(), mySampleText.getText());
|
||||
ApplicationManager.getApplication().invokeLater(() -> setBalloonState(result), ModalityState.any(), __ -> updater.isDisposed());
|
||||
final RegExpMatchResult result = isMatchingText(regexpFile, myRegExp.getText(), mySampleText.getText());
|
||||
ApplicationManager.getApplication().invokeLater(() -> reportResult(result), ModalityState.any(), __ -> updater.isDisposed());
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
@@ -169,36 +165,77 @@ public class CheckRegExpForm {
|
||||
public void removeNotify() {
|
||||
super.removeNotify();
|
||||
Disposer.dispose(disposable);
|
||||
PropertiesComponent.getInstance(myProject).setValue(LAST_EDITED_REGEXP, mySampleText.getText());
|
||||
PropertiesComponent.getInstance(project).setValue(LAST_EDITED_REGEXP, mySampleText.getText());
|
||||
}
|
||||
};
|
||||
myRootPanel.setBorder(JBUI.Borders.empty(UIUtil.DEFAULT_VGAP, UIUtil.DEFAULT_HGAP));
|
||||
|
||||
final GridBagConstraints c = new GridBagConstraints();
|
||||
c.insets = JBUI.insets(UIUtil.DEFAULT_VGAP / 2, UIUtil.DEFAULT_HGAP / 2);
|
||||
c.gridx = 0;
|
||||
c.gridy = 0;
|
||||
myRootPanel.add(createLabel(RegExpBundle.message("label.regexp"), myRegExp), c);
|
||||
c.gridx = 1;
|
||||
myRootPanel.add(myRegExp, c);
|
||||
c.gridx = 0;
|
||||
c.gridy++;
|
||||
myRootPanel.add(createLabel(RegExpBundle.message("label.sample"), mySampleText), c);
|
||||
c.gridx = 1;
|
||||
myRootPanel.add(mySampleText, c);
|
||||
}
|
||||
|
||||
void setBalloonState(RegExpMatchResult result) {
|
||||
mySampleText.setBackground(result == RegExpMatchResult.MATCHES ? BACKGROUND_COLOR_MATCH : BACKGROUND_COLOR_NOMATCH);
|
||||
private static JLabel createLabel(@NotNull @NlsContexts.Label String labelText, @NotNull JComponent component) {
|
||||
final JLabel label = new JLabel(UIUtil.removeMnemonic(labelText));
|
||||
final int index = UIUtil.getDisplayMnemonicIndex(labelText);
|
||||
if (index != -1) {
|
||||
label.setDisplayedMnemonic(labelText.charAt(index + 1));
|
||||
label.setDisplayedMnemonicIndex(index);
|
||||
}
|
||||
label.setLabelFor(component);
|
||||
return label;
|
||||
}
|
||||
|
||||
private static void setupIcon(@NotNull EditorTextField field, @NotNull JComponent icon) {
|
||||
field.addSettingsProvider(editor -> {
|
||||
icon.setBorder(JBUI.Borders.emptyLeft(2));
|
||||
final JScrollPane scrollPane = editor.getScrollPane();
|
||||
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
|
||||
final JScrollBar verticalScrollBar = scrollPane.getVerticalScrollBar();
|
||||
verticalScrollBar.setBackground(editor.getBackgroundColor());
|
||||
verticalScrollBar.add(JBScrollBar.LEADING, icon);
|
||||
verticalScrollBar.setOpaque(true);
|
||||
});
|
||||
}
|
||||
|
||||
void reportResult(RegExpMatchResult result) {
|
||||
switch (result) {
|
||||
case MATCHES:
|
||||
myMessage.setText(RegExpBundle.message("intention.balloon.matches"));
|
||||
break;
|
||||
case NO_MATCH:
|
||||
myMessage.setText(RegExpBundle.message("intention.balloon.no.match"));
|
||||
setIconAndTooltip(mySampleIcon, AllIcons.General.BalloonError, RegExpBundle.message("tooltip.no.match"));
|
||||
setIconAndTooltip(myRegExpIcon, null, null);
|
||||
break;
|
||||
case TIMEOUT:
|
||||
myMessage.setText(RegExpBundle.message("intention.balloon.pattern.is.too.complex"));
|
||||
break;
|
||||
case BAD_REGEXP:
|
||||
myMessage.setText(RegExpBundle.message("intention.balloon.bad.pattern"));
|
||||
case MATCHES:
|
||||
setIconAndTooltip(mySampleIcon, AllIcons.General.InspectionsOK, RegExpBundle.message("tooltip.matches"));
|
||||
setIconAndTooltip(myRegExpIcon, null, null);
|
||||
break;
|
||||
case INCOMPLETE:
|
||||
myMessage.setText(RegExpBundle.message("intention.balloon.more.input.expected"));
|
||||
setIconAndTooltip(mySampleIcon, AllIcons.General.BalloonWarning, RegExpBundle.message("tooltip.more.input.expected"));
|
||||
setIconAndTooltip(myRegExpIcon, null, null);
|
||||
break;
|
||||
case BAD_REGEXP:
|
||||
setIconAndTooltip(mySampleIcon, null, null);
|
||||
setIconAndTooltip(myRegExpIcon, AllIcons.General.BalloonError, RegExpBundle.message("tooltip.bad.pattern"));
|
||||
break;
|
||||
case TIMEOUT:
|
||||
setIconAndTooltip(mySampleIcon, null, null);
|
||||
setIconAndTooltip(myRegExpIcon, AllIcons.General.BalloonWarning, RegExpBundle.message("tooltip.pattern.is.too.complex"));
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
myRootPanel.revalidate();
|
||||
Balloon balloon = JBPopupFactory.getInstance().getParentBalloonFor(myRootPanel);
|
||||
if (balloon != null && !balloon.isDisposed()) balloon.revalidate();
|
||||
}
|
||||
|
||||
private static void setIconAndTooltip(JBLabel label, Icon icon, @NlsContexts.Tooltip String tooltip) {
|
||||
label.setIcon(icon);
|
||||
label.setToolTipText(tooltip);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -264,4 +301,4 @@ public class CheckRegExpForm {
|
||||
|
||||
return RegExpMatchResult.BAD_REGEXP;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user