diff --git a/java/testFramework/src/com/intellij/testFramework/PsiTestCase.java b/java/testFramework/src/com/intellij/testFramework/PsiTestCase.java index 13d60382643e..dd799580d467 100644 --- a/java/testFramework/src/com/intellij/testFramework/PsiTestCase.java +++ b/java/testFramework/src/com/intellij/testFramework/PsiTestCase.java @@ -29,8 +29,8 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; -import com.intellij.psi.impl.PsiManagerImpl; import com.intellij.psi.impl.JavaPsiFacadeImpl; +import com.intellij.psi.impl.PsiManagerImpl; import com.intellij.util.IncorrectOperationException; import org.jdom.Document; import org.jdom.Element; diff --git a/platform/lang-api/src/com/intellij/find/FindManager.java b/platform/lang-api/src/com/intellij/find/FindManager.java index 511b3a37fce0..f4e85c0496a6 100644 --- a/platform/lang-api/src/com/intellij/find/FindManager.java +++ b/platform/lang-api/src/com/intellij/find/FindManager.java @@ -116,7 +116,8 @@ public abstract class FindManager { * @param model the search and replace settings, including the replace string. * @return the string to replace the specified found string. */ - public abstract String getStringToReplace(@NotNull String foundString, FindModel model); + public abstract String getStringToReplace(@NotNull String foundString, @NotNull FindModel model); + public abstract String getStringToReplace(@NotNull String foundString, @NotNull FindModel model, int startOffset, @NotNull String documentText); /** * Gets the flag indicating whether the "Find Next" and "Find Previous" actions are diff --git a/platform/lang-impl/src/com/intellij/find/FindUtil.java b/platform/lang-impl/src/com/intellij/find/FindUtil.java index 32c6dab8fe20..528993a0f4a2 100644 --- a/platform/lang-impl/src/com/intellij/find/FindUtil.java +++ b/platform/lang-impl/src/com/intellij/find/FindUtil.java @@ -58,8 +58,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; +import java.awt.event.FocusAdapter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -206,26 +205,24 @@ public class FindUtil { CharSequence text = document.getCharsSequence(); int textLength = document.getTextLength(); final List usages = new ArrayList(); - if (text != null) { - FindManager findManager = FindManager.getInstance(project); - findModel.setForward(true); // when find all there is no diff in direction + FindManager findManager = FindManager.getInstance(project); + findModel.setForward(true); // when find all there is no diff in direction - int offset = 0; - VirtualFile virtualFile = getVirtualFile(editor); + int offset = 0; + VirtualFile virtualFile = getVirtualFile(editor); - while (offset < textLength) { - FindResult result = findManager.findString(text, offset, findModel, virtualFile); - if (!result.isStringFound()) break; + while (offset < textLength) { + FindResult result = findManager.findString(text, offset, findModel, virtualFile); + if (!result.isStringFound()) break; - usages.add(new UsageInfo2UsageAdapter(new UsageInfo(psiFile, result.getStartOffset(), result.getEndOffset()))); + usages.add(new UsageInfo2UsageAdapter(new UsageInfo(psiFile, result.getStartOffset(), result.getEndOffset()))); - final int prevOffset = offset; - offset = result.getEndOffset(); + final int prevOffset = offset; + offset = result.getEndOffset(); - if (prevOffset == offset) { - // for regular expr the size of the match could be zero -> could be infinite loop in finding usages! - ++offset; - } + if (prevOffset == offset) { + // for regular expr the size of the match could be zero -> could be infinite loop in finding usages! + ++offset; } } final UsageTarget[] usageTargets = { new FindInProjectUtil.StringUsageTarget(findModel.getStringToFind()) }; @@ -396,7 +393,7 @@ public class FindUtil { }); } - private static boolean replace(Project project, Editor editor, int offset, FindModel model) { + public static boolean replace(Project project, Editor editor, int offset, FindModel model) { Document document = editor.getDocument(); if (!FileDocumentManager.getInstance().requestWriting(document, project)) { @@ -422,7 +419,7 @@ public class FindUtil { document.stopGuardedBlockChecking(); } - return false; + return true; } private static boolean doReplace(Project project, Editor editor, FindModel model, final Document document, int caretOffset, boolean toPrompt) { @@ -460,7 +457,7 @@ public class FindUtil { int startOffset = result.getStartOffset(); int endOffset = result.getEndOffset(); String foundString = document.getCharsSequence().subSequence(startOffset, endOffset).toString(); - String toReplace = findManager.getStringToReplace(foundString, model); + String toReplace = findManager.getStringToReplace(foundString, model, startOffset, document.getText()); if (toReplace == null) break; boolean reallyReplace = toPrompt; @@ -531,10 +528,6 @@ public class FindUtil { Document document = editor.getDocument(); final FindResult result = findManager.findString(document.getCharsSequence(), offset, model, getVirtualFile(editor)); - String stringToFind = model.getStringToFind(); - if (stringToFind == null) { - return null; - } boolean isFound = result.isStringFound(); if (!model.isGlobal()) { @@ -597,7 +590,7 @@ public class FindUtil { return result; } - private static class MyListener implements FocusListener, CaretListener { + private static class MyListener extends FocusAdapter implements CaretListener { private final Editor myEditor; private final RangeHighlighter mySegmentHighlighter; @@ -606,13 +599,6 @@ public class FindUtil { mySegmentHighlighter = segmentHighlighter; } - public void focusGained(FocusEvent e) { -// removeAll(); - } - - public void focusLost(FocusEvent e) { - } - public void caretPositionChanged(CaretEvent e) { removeAll(); } @@ -689,14 +675,14 @@ public class FindUtil { 0, false); } - private static TextRange doReplace(final Project project, final Document document, final FindModel model, FindResult result, @NotNull final String stringToReplace, + private static TextRange doReplace(final Project project, final Document document, final FindModel model, FindResult result, @NotNull String stringToReplace, boolean reallyReplace, List> rangesToChange) { final int startOffset = result.getStartOffset(); final int endOffset = result.getEndOffset(); - int newOffset; final String converted = StringUtil.convertLineSeparators(stringToReplace); + int newOffset; if (reallyReplace) { CommandProcessor.getInstance().executeCommand(project, new Runnable() { public void run() { diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java index 1bd29f18ad22..9bbbfbbb20e6 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java @@ -488,7 +488,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo } return NOT_FOUND_RESULT; } - else{ + else { int start = -1; int end = -1; while(matcher.find() && matcher.end() < startOffset){ @@ -517,20 +517,69 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo return pattern.matcher(text); } - public String getStringToReplace(@NotNull String foundString, FindModel model) { - if (model == null) { + public String getStringToReplace(@NotNull String foundString, @NotNull FindModel model) { + String toReplace = model.getStringToReplace(); + if (model.isRegularExpressions()) { + return getStringToReplaceByRegexp0(foundString, model); + } + if (model.isPreserveCase()) { + return replaceWithCaseRespect (toReplace, foundString); + } + return toReplace; + } + + @Override + public String getStringToReplace(@NotNull String foundString, @NotNull FindModel model, int startOffset, @NotNull String documentText) { + String toReplace = model.getStringToReplace(); + if (model.isRegularExpressions()) { + return getStringToReplaceByRegexp(foundString, model, documentText, startOffset); + } + if (model.isPreserveCase()) { + return replaceWithCaseRespect (toReplace, foundString); + } + return toReplace; + } + + private String getStringToReplaceByRegexp(@NotNull String foundString, @NotNull final FindModel model, @NotNull String text, int startOffset) { + Matcher matcher = compileRegExp(model, text); + + if (model.isForward()){ + if (!matcher.find(startOffset)) { + return null; + } + if (matcher.end() > text.length()) { + return null; + } + } + else { + int start = -1; + while(matcher.find() && matcher.end() < startOffset){ + start = matcher.start(); + } + if (start < 0){ + return null; + } + } + try { + StringBuffer replaced = new StringBuffer(); + matcher.appendReplacement(replaced, model.getStringToReplace()); + + return replaced.substring(matcher.start()); + } + catch (Exception e) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + Messages.showErrorDialog(myProject, FindBundle.message("find.replace.invalid.replacement.string", model.getStringToReplace()), + FindBundle.message("find.replace.invalid.replacement.string.title")); + } + }); return null; } - String toReplace = model.getStringToReplace(); - if (!model.isRegularExpressions()) { - if (model.isPreserveCase()) { - return replaceWithCaseRespect (toReplace, foundString); - } - return toReplace; - } + } + private String getStringToReplaceByRegexp0(String foundString, final FindModel model) { String toFind = model.getStringToFind(); - + String toReplace = model.getStringToReplace(); Pattern pattern; try{ int flags = Pattern.MULTILINE; @@ -550,14 +599,15 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo } catch (Exception e) { ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - Messages.showErrorDialog(myProject, FindBundle.message("find.replace.invalid.replacement.string"), - FindBundle.message("find.replace.invalid.replacement.string.title")); - } - }); + public void run() { + Messages.showErrorDialog(myProject, FindBundle.message("find.replace.invalid.replacement.string", model.getStringToReplace()), + FindBundle.message("find.replace.invalid.replacement.string.title")); + } + }); return null; } - } else { + } + else { // There are valid situations (for example, IDEADEV-2543 or positive lookbehind assertions) // where an expression which matches a string in context will not match the same string // separately). diff --git a/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java b/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java index c967562b6c93..0a78f773a884 100644 --- a/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java +++ b/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java @@ -352,7 +352,7 @@ public class ReplaceInProjectManager { if (!findResult.isStringFound()){ return; } - String stringToReplace = findManager.getStringToReplace(foundString.toString(), replaceContext.getFindModel()); + String stringToReplace = findManager.getStringToReplace(foundString.toString(), replaceContext.getFindModel(), textOffset, document.getText()); if (stringToReplace != null) { document.replaceString(textOffset, textEndOffset, stringToReplace); } diff --git a/platform/platform-resources-en/src/messages/FindBundle.properties b/platform/platform-resources-en/src/messages/FindBundle.properties index 46b1c33caac1..2d3666179c5c 100644 --- a/platform/platform-resources-en/src/messages/FindBundle.properties +++ b/platform/platform-resources-en/src/messages/FindBundle.properties @@ -105,7 +105,7 @@ find.scope.module.title=Module {0} find.scope.directory.title=Directory {0} find.scope.files.with.mask={0} Files with Mask {1} find.usage.target.string.text=String ''{0}'' -find.replace.invalid.replacement.string=You have entered malformed replacement string +find.replace.invalid.replacement.string=You have entered malformed replacement string: ''{0}'' find.replace.invalid.replacement.string.title=Replace Error find.highlight.no.more.highlights.found=No more highlights found find.scope.all.project.classes=All Project Classes