mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
SSR: simpler Replacer
This commit is contained in:
+2
-2
@@ -1,3 +1,4 @@
|
||||
// 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.refactoring.typeMigration;
|
||||
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
@@ -89,8 +90,7 @@ public class TypeConversionDescriptor extends TypeConversionDescriptorBase {
|
||||
final ReplaceOptions options = new ReplaceOptions();
|
||||
final MatchOptions matchOptions = options.getMatchOptions();
|
||||
matchOptions.setFileType(StdFileTypes.JAVA);
|
||||
final Replacer replacer = new Replacer(project, null);
|
||||
final String replacement = replacer.testReplace(expression.getText(), stringToReplace, replaceByString, options);
|
||||
final String replacement = Replacer.testReplace(expression.getText(), stringToReplace, replaceByString, options, project);
|
||||
return (PsiExpression)JavaCodeStyleManager.getInstance(project).shortenClassReferences(expression.replace(
|
||||
JavaPsiFacade.getInstance(project).getElementFactory().createExpressionFromText(replacement, expression)));
|
||||
}
|
||||
|
||||
+41
-82
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// 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.plugin.replace.impl;
|
||||
|
||||
import com.intellij.codeInsight.template.Template;
|
||||
@@ -47,59 +33,62 @@ import java.util.List;
|
||||
*/
|
||||
public class Replacer {
|
||||
private final Project project;
|
||||
private ReplacementBuilder replacementBuilder;
|
||||
private ReplaceOptions options;
|
||||
private ReplacementContext context;
|
||||
private StructuralReplaceHandler replaceHandler;
|
||||
private final ReplaceOptions options;
|
||||
private final StructuralReplaceHandler replaceHandler;
|
||||
private final ReplacementBuilder replacementBuilder;
|
||||
private PsiElement lastAffectedElement = null;
|
||||
|
||||
public Replacer(Project project, ReplaceOptions options) {
|
||||
this.project = project;
|
||||
this.options = options;
|
||||
final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(options.getMatchOptions().getFileType());
|
||||
assert profile != null;
|
||||
replaceHandler = profile.getReplaceHandler(new ReplacementContext(options, project));
|
||||
assert replaceHandler != null;
|
||||
replacementBuilder = new ReplacementBuilder(this.project, this.options);
|
||||
}
|
||||
|
||||
public static String stripTypedVariableDecoration(final String type) {
|
||||
return type.substring(1,type.length()-1);
|
||||
}
|
||||
return type.substring(1, type.length() - 1);
|
||||
}
|
||||
|
||||
public static int insertSubstitution(StringBuilder result, int offset, final ParameterInfo info, String image) {
|
||||
if (image.length() > 0) result.insert(offset+ info.getStartIndex(),image);
|
||||
offset += image.length();
|
||||
if (!image.isEmpty()) {
|
||||
result.insert(offset + info.getStartIndex(), image);
|
||||
offset += image.length();
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
public String testReplace(String in, String what, String by, ReplaceOptions options) throws IncorrectOperationException {
|
||||
return testReplace(in, what, by, options, false);
|
||||
public static String testReplace(String in, String what, String by, ReplaceOptions options, Project project) {
|
||||
return testReplace(in, what, by, options, project, false);
|
||||
}
|
||||
|
||||
public String testReplace(String in, String what, String by, ReplaceOptions options, boolean filePattern) {
|
||||
public static String testReplace(String in, String what, String by, ReplaceOptions options, Project project, boolean sourceIsFile) {
|
||||
FileType type = options.getMatchOptions().getFileType();
|
||||
return testReplace(in, what, by, options, filePattern, false, type, null);
|
||||
return testReplace(in, what, by, options, project, sourceIsFile, false, type, null);
|
||||
}
|
||||
|
||||
public String testReplace(String in, String what, String by, ReplaceOptions options, boolean filePattern, boolean createPhysicalFile,
|
||||
FileType sourceFileType, Language sourceDialect) {
|
||||
this.options = options;
|
||||
final MatchOptions matchOptions = this.options.getMatchOptions();
|
||||
this.options.setReplacement(by);
|
||||
replacementBuilder=null;
|
||||
context = null;
|
||||
replaceHandler = null;
|
||||
public static String testReplace(String in, String what, String by, ReplaceOptions replaceOptions, Project project, boolean sourceIsFile,
|
||||
boolean createPhysicalFile, FileType sourceFileType, Language sourceDialect) {
|
||||
replaceOptions.setReplacement(by);
|
||||
|
||||
final MatchOptions matchOptions = replaceOptions.getMatchOptions();
|
||||
matchOptions.clearVariableConstraints();
|
||||
matchOptions.fillSearchCriteria(what);
|
||||
|
||||
Matcher.validate(project, matchOptions);
|
||||
checkSupportedReplacementPattern(project, options);
|
||||
checkSupportedReplacementPattern(project, replaceOptions);
|
||||
|
||||
Matcher matcher = new Matcher(project);
|
||||
final Replacer replacer = new Replacer(project, replaceOptions);
|
||||
final Matcher matcher = new Matcher(project);
|
||||
try {
|
||||
PsiElement firstElement, lastElement, parent;
|
||||
final PsiElement firstElement, lastElement, parent;
|
||||
|
||||
if (options.getMatchOptions().getScope() == null) {
|
||||
PsiElement[] elements = MatcherImplUtil.createTreeFromText(
|
||||
if (replaceOptions.getMatchOptions().getScope() == null) {
|
||||
final PsiElement[] elements = MatcherImplUtil.createTreeFromText(
|
||||
in,
|
||||
filePattern ? PatternTreeContext.File : PatternTreeContext.Block,
|
||||
sourceIsFile ? PatternTreeContext.File : PatternTreeContext.Block,
|
||||
sourceFileType, sourceDialect, null,
|
||||
project,
|
||||
createPhysicalFile
|
||||
@@ -111,7 +100,7 @@ public class Replacer {
|
||||
|
||||
matchOptions.setScope(new LocalSearchScope(elements));
|
||||
} else {
|
||||
parent = ((LocalSearchScope)options.getMatchOptions().getScope()).getScope()[0];
|
||||
parent = ((LocalSearchScope)matchOptions.getScope()).getScope()[0];
|
||||
firstElement = parent.getFirstChild();
|
||||
lastElement = parent.getLastChild();
|
||||
}
|
||||
@@ -121,24 +110,24 @@ public class Replacer {
|
||||
|
||||
final List<ReplacementInfo> resultPtrList = new SmartList<>();
|
||||
for (final MatchResult result : sink.getMatches()) {
|
||||
resultPtrList.add(buildReplacement(result));
|
||||
resultPtrList.add(replacer.buildReplacement(result));
|
||||
}
|
||||
|
||||
int startOffset = firstElement.getTextRange().getStartOffset();
|
||||
int endOffset = filePattern ? 0 : parent.getTextLength() - lastElement.getTextRange().getEndOffset();
|
||||
int endOffset = sourceIsFile ? 0 : parent.getTextLength() - lastElement.getTextRange().getEndOffset();
|
||||
|
||||
// get nodes from text may contain
|
||||
PsiElement prevSibling = firstElement.getPrevSibling();
|
||||
final PsiElement prevSibling = firstElement.getPrevSibling();
|
||||
if (prevSibling instanceof PsiWhiteSpace) {
|
||||
startOffset -= prevSibling.getTextLength() - 1;
|
||||
}
|
||||
|
||||
PsiElement nextSibling = lastElement.getNextSibling();
|
||||
final PsiElement nextSibling = lastElement.getNextSibling();
|
||||
if (nextSibling instanceof PsiWhiteSpace) {
|
||||
endOffset -= nextSibling.getTextLength() - 1;
|
||||
}
|
||||
|
||||
replaceAll(resultPtrList);
|
||||
replacer.replaceAll(resultPtrList);
|
||||
|
||||
String result = parent.getText();
|
||||
result = result.substring(startOffset);
|
||||
@@ -150,17 +139,13 @@ public class Replacer {
|
||||
throw new IncorrectOperationException(e);
|
||||
}
|
||||
finally {
|
||||
options.getMatchOptions().setScope(null);
|
||||
matchOptions.setScope(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void replaceAll(final List<ReplacementInfo> infos) {
|
||||
for (ReplacementInfo info : infos) {
|
||||
PsiElement element = info.getMatch(0);
|
||||
initContextAndHandler(element);
|
||||
if (replaceHandler != null) {
|
||||
replaceHandler.prepare(info);
|
||||
}
|
||||
replaceHandler.prepare(info);
|
||||
}
|
||||
|
||||
((ApplicationImpl)ApplicationManager.getApplication()).runWriteActionWithCancellableProgressInDispatchThread(
|
||||
@@ -201,11 +186,7 @@ public class Replacer {
|
||||
}
|
||||
|
||||
public void replace(ReplacementInfo info) {
|
||||
initContextAndHandler(info.getMatch(0));
|
||||
|
||||
if (replaceHandler != null) {
|
||||
replaceHandler.prepare(info);
|
||||
}
|
||||
replaceHandler.prepare(info);
|
||||
reformatAndPostProcess(doReplace(info));
|
||||
}
|
||||
|
||||
@@ -218,11 +199,7 @@ public class Replacer {
|
||||
final PsiElement elementParent = StructuralSearchUtil.getPresentableElement(element).getParent();
|
||||
|
||||
CodeStyleManager.getInstance(project).performActionWithFormatterDisabled(
|
||||
(Runnable)() -> {
|
||||
if (replaceHandler != null) {
|
||||
replaceHandler.replace(info, options);
|
||||
}
|
||||
}
|
||||
(Runnable)() -> replaceHandler.replace(info, options)
|
||||
);
|
||||
|
||||
if (!elementParent.isValid() || !elementParent.isWritable()) {
|
||||
@@ -245,21 +222,7 @@ public class Replacer {
|
||||
final int parentOffset = elementParent.getTextRange().getStartOffset();
|
||||
CodeStyleManager.getInstance(project).reformatRange(containingFile, parentOffset, parentOffset + elementParent.getTextLength(), true);
|
||||
}
|
||||
if (replaceHandler != null) {
|
||||
replaceHandler.postProcess(elementParent, options);
|
||||
}
|
||||
}
|
||||
|
||||
private void initContextAndHandler(PsiElement psiContext) {
|
||||
if (context == null) {
|
||||
context = new ReplacementContext(options, project);
|
||||
}
|
||||
if (replaceHandler == null) {
|
||||
final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByPsiElement(psiContext);
|
||||
if (profile != null) {
|
||||
replaceHandler = profile.getReplaceHandler(context);
|
||||
}
|
||||
}
|
||||
replaceHandler.postProcess(elementParent, options);
|
||||
}
|
||||
|
||||
public static void handleComments(final PsiElement el, final PsiElement replacement, ReplacementInfo replacementInfo) {
|
||||
@@ -350,10 +313,6 @@ public class Replacer {
|
||||
|
||||
public ReplacementInfo buildReplacement(MatchResult result) {
|
||||
final ReplacementInfoImpl replacementInfo = new ReplacementInfoImpl(result, project);
|
||||
|
||||
if (replacementBuilder == null) {
|
||||
replacementBuilder = new ReplacementBuilder(project, options);
|
||||
}
|
||||
replacementInfo.setReplacement(replacementBuilder.process(result, replacementInfo, options.getMatchOptions().getFileType()));
|
||||
|
||||
return replacementInfo;
|
||||
|
||||
+151
-140
File diff suppressed because it is too large
Load Diff
+1
-4
@@ -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.codeInsight.daemon.quickFix.LightQuickFixTestCase;
|
||||
@@ -7,13 +7,11 @@ import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.structuralsearch.plugin.replace.ReplaceOptions;
|
||||
import com.intellij.structuralsearch.plugin.replace.impl.Replacer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
abstract class StructuralReplaceTestCase extends LightQuickFixTestCase {
|
||||
protected Replacer replacer;
|
||||
protected ReplaceOptions options;
|
||||
|
||||
@Override
|
||||
@@ -23,7 +21,6 @@ abstract class StructuralReplaceTestCase extends LightQuickFixTestCase {
|
||||
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_4);
|
||||
|
||||
options = new ReplaceOptions();
|
||||
replacer = new Replacer(getProject(), null);
|
||||
}
|
||||
|
||||
protected String loadFile(String fileName) throws IOException {
|
||||
|
||||
+10
-28
@@ -2,6 +2,7 @@
|
||||
package com.intellij.structuralsearch;
|
||||
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.structuralsearch.plugin.replace.impl.Replacer;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -13,22 +14,14 @@ public class XmlStructuralReplaceTest extends StructuralReplaceTestCase {
|
||||
super.setUp();
|
||||
options.getMatchOptions().setFileType(StdFileTypes.XML);
|
||||
}
|
||||
|
||||
|
||||
public void testReplaceXmlAndHtml() {
|
||||
|
||||
String s1 = "<a/>";
|
||||
String s2 = "<a/>";
|
||||
String s3 = "<a><b/></a>";
|
||||
|
||||
String expectedResult = "<a><b/></a>";
|
||||
String actualResult = replacer.testReplace(s1,s2,s3,options);
|
||||
|
||||
assertEquals(
|
||||
"First tag replacement",
|
||||
expectedResult,
|
||||
actualResult
|
||||
);
|
||||
|
||||
assertEquals("First tag replacement", expectedResult, Replacer.testReplace(s1, s2, s3, options, getProject()));
|
||||
|
||||
String s4 = "<group id=\"EditorTabPopupMenu\">\n" +
|
||||
" <reference id=\"Compile\"/>\n" +
|
||||
@@ -42,7 +35,6 @@ public class XmlStructuralReplaceTest extends StructuralReplaceTestCase {
|
||||
String s5 = "<reference id=\"'_Value\"/>";
|
||||
String s6 = "<reference ref=\"$Value$\"/>";
|
||||
|
||||
actualResult = replacer.testReplace(s4,s5,s6,options);
|
||||
expectedResult = "<group id=\"EditorTabPopupMenu\">\n" +
|
||||
" <reference ref=\"Compile\"/>\n" +
|
||||
" <reference ref=\"RunContextPopupGroup\"/>\n" +
|
||||
@@ -52,42 +44,32 @@ public class XmlStructuralReplaceTest extends StructuralReplaceTestCase {
|
||||
" <separator/>\n" +
|
||||
" <reference ref=\"ExternalToolsGroup\"/>\n" +
|
||||
"</group>";
|
||||
assertEquals(
|
||||
"Replace tag",
|
||||
expectedResult,
|
||||
actualResult
|
||||
);
|
||||
assertEquals("Replace tag", expectedResult, Replacer.testReplace(s4, s5, s6, options, getProject()));
|
||||
|
||||
String s7 = "<h4 class=\"a\">My title<aaa>ZZZZ</aaa> My title 3</h4>\n" +
|
||||
"<h4>My title 2</h4>";
|
||||
String s8 = "<h4 class=\"a\">'_Content*</h4>";
|
||||
String s9 = "<h5>$Content$</h5>";
|
||||
|
||||
actualResult = replacer.testReplace(s7,s8,s9,options);
|
||||
expectedResult = "<h5>My title <aaa>ZZZZ</aaa> My title 3</h5>\n" +
|
||||
"<h4>My title 2</h4>";
|
||||
|
||||
assertEquals(
|
||||
"Replace tag saving content",
|
||||
expectedResult,
|
||||
actualResult
|
||||
);
|
||||
assertEquals("Replace tag saving content", expectedResult, Replacer.testReplace(s7, s8, s9, options, getProject()));
|
||||
|
||||
expectedResult = "\n" +
|
||||
"<h4>My title 2</h4>";
|
||||
assertEquals("Delete tag", expectedResult, replacer.testReplace(s7, s8, "", options));
|
||||
assertEquals("Delete tag", expectedResult, Replacer.testReplace(s7, s8, "", options, getProject()));
|
||||
|
||||
String what = "<'_H:h4 class=\"a\">'_Content*</'_H>";
|
||||
String by = "<$H$>$Content$</$H$>";
|
||||
expectedResult = "<h4>My title <aaa>ZZZZ</aaa> My title 3</h4>\n" +
|
||||
"<h4>My title 2</h4>";
|
||||
assertEquals("Replace with variable", expectedResult, replacer.testReplace(s7, what, by, options));
|
||||
assertEquals("Replace with variable", expectedResult, Replacer.testReplace(s7, what, by, options, getProject()));
|
||||
|
||||
String in = "<b>Cry 'Havoc!', and <i>let slip the<br> dogs of war</i></b>";
|
||||
what = "<'_Tag:b >'_Content2*</'_Tag>";
|
||||
by = "<$Tag$ id=\"unique\">$Content2$</$Tag$>";
|
||||
expectedResult = "<b id=\"unique\">Cry 'Havoc!', and <i>let slip the<br> dogs of war</i></b>";
|
||||
assertEquals("Replace complex content with variable", expectedResult, replacer.testReplace(in, what, by, options));
|
||||
assertEquals("Replace complex content with variable", expectedResult, Replacer.testReplace(in, what, by, options, getProject()));
|
||||
}
|
||||
|
||||
public void testHtmlReplacement1() throws IOException {
|
||||
@@ -108,7 +90,7 @@ public class XmlStructuralReplaceTest extends StructuralReplaceTestCase {
|
||||
String by = "<input $a$ id=\"someId1\" />";
|
||||
String expected = "<input class=\"other\" type=\"text\" ng-model=\"someModel\" placeholder=\"Some placeholder\" id=\"someId1\" />";
|
||||
|
||||
String actual = replacer.testReplace(in, what, by, options);
|
||||
String actual = Replacer.testReplace(in, what, by, options, getProject());
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@@ -130,7 +112,7 @@ public class XmlStructuralReplaceTest extends StructuralReplaceTestCase {
|
||||
String replacement = loadFile(replacementFileName);
|
||||
String expectedResult = loadFile(outFileName);
|
||||
|
||||
assertEquals(message, expectedResult, replacer.testReplace(content,pattern,replacement,options,filepattern));
|
||||
assertEquals(message, expectedResult, Replacer.testReplace(content, pattern, replacement, options,getProject(), filepattern));
|
||||
|
||||
options.getMatchOptions().setFileType(StdFileTypes.XML);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user