mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
SSR: fix replacing xml tag set as target (IDEA-187291)
This commit is contained in:
+3
-1
@@ -30,6 +30,7 @@ import com.intellij.structuralsearch.plugin.ui.SearchContext;
|
||||
import com.intellij.structuralsearch.plugin.ui.UIUtil;
|
||||
import com.intellij.util.LocalTimeCounter;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -259,6 +260,7 @@ public abstract class StructuralSearchProfile {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Contract("null -> false")
|
||||
public boolean isIdentifier(PsiElement element) {
|
||||
return false;
|
||||
}
|
||||
@@ -272,7 +274,7 @@ public abstract class StructuralSearchProfile {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Contract("!null -> !null")
|
||||
public PsiElement getPresentableElement(PsiElement element) {
|
||||
return isIdentifier(element) ? element.getParent() : element;
|
||||
}
|
||||
|
||||
+5
-7
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2017 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.
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.structuralsearch;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
@@ -46,13 +46,11 @@ public class StructuralSearchUtil {
|
||||
return !isIdentifier(element) ? element : element.getParent();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PsiElement getPresentableElement(@NotNull PsiElement element) {
|
||||
@Contract("!null -> !null")
|
||||
public static PsiElement getPresentableElement(PsiElement element) {
|
||||
if (element == null) return null;
|
||||
final StructuralSearchProfile profile = getProfileByPsiElement(element);
|
||||
if (profile == null) {
|
||||
return element;
|
||||
}
|
||||
return profile.getPresentableElement(element);
|
||||
return profile == null ? element : profile.getPresentableElement(element);
|
||||
}
|
||||
|
||||
private static StructuralSearchProfile[] getNewStyleProfiles() {
|
||||
|
||||
+51
-65
@@ -153,83 +153,69 @@ public class XmlStructuralSearchProfile extends StructuralSearchProfile {
|
||||
private static class MyReplaceHandler extends StructuralReplaceHandler {
|
||||
private final ReplacementContext myContext;
|
||||
|
||||
private MyReplaceHandler(ReplacementContext context) {
|
||||
MyReplaceHandler(ReplacementContext context) {
|
||||
myContext = context;
|
||||
}
|
||||
|
||||
public void replace(ReplacementInfo info, ReplaceOptions options) {
|
||||
PsiElement elementToReplace = info.getMatch(0);
|
||||
final PsiElement elementToReplace = StructuralSearchUtil.getPresentableElement(info.getMatch(0));
|
||||
assert elementToReplace != null;
|
||||
PsiElement elementParent = elementToReplace.getParent();
|
||||
String replacementToMake = info.getReplacement();
|
||||
boolean listContext = elementToReplace.getParent() instanceof XmlTag;
|
||||
final String replacementToMake = info.getReplacement();
|
||||
final PsiElement elementParent = elementToReplace.getParent();
|
||||
final boolean listContext = elementParent instanceof XmlTag;
|
||||
|
||||
if (listContext) {
|
||||
doReplaceInContext(info, elementToReplace, replacementToMake, elementParent, myContext);
|
||||
}
|
||||
|
||||
PsiElement[] statements = ReplacerUtil.createTreeForReplacement(replacementToMake, PatternTreeContext.Block, myContext);
|
||||
|
||||
if (statements.length > 0) {
|
||||
PsiElement replacement = ReplacerUtil.copySpacesAndCommentsBefore(elementToReplace, statements, replacementToMake, elementParent);
|
||||
|
||||
// preserve comments
|
||||
Replacer.handleComments(elementToReplace, replacement, info);
|
||||
elementToReplace.replace(replacement);
|
||||
}
|
||||
else {
|
||||
elementToReplace.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
final PsiElement[] statements = ReplacerUtil.createTreeForReplacement(replacementToMake, PatternTreeContext.Block, myContext);
|
||||
if (statements.length > 0) {
|
||||
PsiElement replacement = ReplacerUtil.copySpacesAndCommentsBefore(elementToReplace, statements, replacementToMake, elementParent);
|
||||
|
||||
private static void doReplaceInContext(ReplacementInfo info,
|
||||
PsiElement elementToReplace,
|
||||
String replacementToMake,
|
||||
PsiElement elementParent,
|
||||
ReplacementContext context) {
|
||||
PsiElement[] statements = ReplacerUtil.createTreeForReplacement(replacementToMake, PatternTreeContext.Block, context);
|
||||
|
||||
if (statements.length > 1) {
|
||||
elementParent.addRangeBefore(statements[0], statements[statements.length - 1], elementToReplace);
|
||||
}
|
||||
else if (statements.length == 1) {
|
||||
PsiElement replacement = statements[0];
|
||||
|
||||
Replacer.handleComments(elementToReplace, replacement, info);
|
||||
|
||||
try {
|
||||
elementParent.addBefore(replacement, elementToReplace);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
elementToReplace.replace(replacement);
|
||||
}
|
||||
}
|
||||
|
||||
final int matchSize = info.getMatchesCount();
|
||||
|
||||
for (int i = 0; i < matchSize; ++i) {
|
||||
PsiElement element = info.getMatch(i);
|
||||
|
||||
if (element == null) continue;
|
||||
PsiElement firstToDelete = element;
|
||||
PsiElement lastToDelete = element;
|
||||
PsiElement prevSibling = element.getPrevSibling();
|
||||
PsiElement nextSibling = element.getNextSibling();
|
||||
|
||||
if (prevSibling instanceof PsiWhiteSpace) {
|
||||
firstToDelete = prevSibling;
|
||||
}
|
||||
else if (prevSibling == null && nextSibling instanceof PsiWhiteSpace) {
|
||||
lastToDelete = nextSibling;
|
||||
}
|
||||
if (nextSibling instanceof XmlText && i + 1 < matchSize) {
|
||||
final PsiElement next = info.getMatch(i + 1);
|
||||
if (next != null && next == nextSibling.getNextSibling()) {
|
||||
lastToDelete = nextSibling;
|
||||
// preserve comments
|
||||
Replacer.handleComments(elementToReplace, replacement, info);
|
||||
elementToReplace.replace(replacement);
|
||||
}
|
||||
else {
|
||||
elementToReplace.delete();
|
||||
}
|
||||
}
|
||||
element.getParent().deleteChildRange(firstToDelete, lastToDelete);
|
||||
}
|
||||
|
||||
private static void doReplaceInContext(ReplacementInfo info,
|
||||
PsiElement elementToReplace,
|
||||
String replacementToMake,
|
||||
PsiElement elementParent,
|
||||
ReplacementContext context) {
|
||||
final PsiElement[] statements = ReplacerUtil.createTreeForReplacement(replacementToMake, PatternTreeContext.Block, context);
|
||||
|
||||
if (statements.length > 1) {
|
||||
elementParent.addRangeBefore(statements[0], statements[statements.length - 1], elementToReplace);
|
||||
}
|
||||
else if (statements.length == 1) {
|
||||
Replacer.handleComments(elementToReplace, statements[0], info);
|
||||
try {
|
||||
elementParent.addBefore(statements[0], elementToReplace);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
elementToReplace.replace(statements[0]);
|
||||
}
|
||||
}
|
||||
|
||||
final int matchSize = info.getMatchesCount();
|
||||
for (int i = 0; i < matchSize; ++i) {
|
||||
final PsiElement element = StructuralSearchUtil.getPresentableElement(info.getMatch(i));
|
||||
final PsiElement prevSibling = element.getPrevSibling();
|
||||
element.getParent().deleteChildRange(isWhitespace(prevSibling) ? prevSibling : element, element);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isWhitespace(PsiElement element) {
|
||||
if (element instanceof PsiWhiteSpace) return true;
|
||||
if (!(element instanceof XmlText)) return false;
|
||||
final PsiElement firstChild = element.getFirstChild();
|
||||
final PsiElement lastChild = element.getLastChild();
|
||||
return firstChild == lastChild && firstChild instanceof PsiWhiteSpace;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +227,7 @@ public class XmlStructuralSearchProfile extends StructuralSearchProfile {
|
||||
private static class XmlPredefinedConfigurations {
|
||||
private static final String HTML_XML = SSRBundle.message("xml_html.category");
|
||||
|
||||
private static Configuration[] createPredefinedTemplates() {
|
||||
static Configuration[] createPredefinedTemplates() {
|
||||
return new Configuration[]{
|
||||
createSearchTemplateInfo("xml tag", "<'a/>", HTML_XML, StdFileTypes.XML),
|
||||
createSearchTemplateInfo("xml attribute", "<'_tag 'attribute=\"'_value\"/>", HTML_XML, StdFileTypes.XML),
|
||||
|
||||
+32
@@ -94,6 +94,38 @@ public class XmlStructuralReplaceTest extends StructuralReplaceTestCase {
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
public void testRemoveAttribute() {
|
||||
String in = "<input class=\"other\" placeholder=\"Some placeholder\">";
|
||||
String what = "<input 'a:[regex( placeholder )]>";
|
||||
String by = "";
|
||||
String expected = "<input class=\"other\">";
|
||||
|
||||
assertEquals(expected, Replacer.testReplace(in, what, by, options, getProject()));
|
||||
}
|
||||
|
||||
public void testRemoveTag() {
|
||||
String in = "<a>\n" +
|
||||
" <b>liberation</b>\n" +
|
||||
" <c>remuneration</c>\n" +
|
||||
"</a>";
|
||||
String what = "<'tag:[regex( c )]>'_text</'tag>";
|
||||
String by = "";
|
||||
String expected = "<a>\n" +
|
||||
" <b>liberation</b>\n" +
|
||||
"</a>";
|
||||
|
||||
assertEquals(expected, Replacer.testReplace(in, what, by, options, getProject()));
|
||||
}
|
||||
|
||||
public void testReplaceAttributeValue() {
|
||||
String in = "<input id=\"one\" class=\"no\">";
|
||||
String what = "<'_tag '_attr:[regex( id )]=\\''value\\'>";
|
||||
String by = "\"two\"";
|
||||
String expected = "<input id=\"two\" class=\"no\">";
|
||||
|
||||
assertEquals(expected, Replacer.testReplace(in, what, by, options, getProject()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
|
||||
Reference in New Issue
Block a user