2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com
.intellij
.find
;
19 import com
.intellij
.codeInsight
.hint
.HintManager
;
20 import com
.intellij
.codeInsight
.hint
.HintManagerImpl
;
21 import com
.intellij
.codeInsight
.hint
.HintUtil
;
22 import com
.intellij
.find
.impl
.FindInProjectUtil
;
23 import com
.intellij
.find
.replaceInProject
.ReplaceInProjectManager
;
24 import com
.intellij
.openapi
.actionSystem
.ActionManager
;
25 import com
.intellij
.openapi
.actionSystem
.AnAction
;
26 import com
.intellij
.openapi
.actionSystem
.IdeActions
;
27 import com
.intellij
.openapi
.application
.ApplicationManager
;
28 import com
.intellij
.openapi
.command
.CommandProcessor
;
29 import com
.intellij
.openapi
.editor
.*;
30 import com
.intellij
.openapi
.editor
.actionSystem
.EditorActionManager
;
31 import com
.intellij
.openapi
.editor
.colors
.EditorColors
;
32 import com
.intellij
.openapi
.editor
.colors
.EditorColorsManager
;
33 import com
.intellij
.openapi
.editor
.event
.CaretEvent
;
34 import com
.intellij
.openapi
.editor
.event
.CaretListener
;
35 import com
.intellij
.openapi
.editor
.ex
.DocumentEx
;
36 import com
.intellij
.openapi
.editor
.ex
.RangeHighlighterEx
;
37 import com
.intellij
.openapi
.editor
.markup
.HighlighterLayer
;
38 import com
.intellij
.openapi
.editor
.markup
.HighlighterTargetArea
;
39 import com
.intellij
.openapi
.editor
.markup
.RangeHighlighter
;
40 import com
.intellij
.openapi
.editor
.markup
.TextAttributes
;
41 import com
.intellij
.openapi
.fileEditor
.FileDocumentManager
;
42 import com
.intellij
.openapi
.fileEditor
.FileEditor
;
43 import com
.intellij
.openapi
.fileEditor
.TextEditor
;
44 import com
.intellij
.openapi
.fileEditor
.ex
.IdeDocumentHistory
;
45 import com
.intellij
.openapi
.keymap
.KeymapUtil
;
46 import com
.intellij
.openapi
.project
.Project
;
47 import com
.intellij
.openapi
.util
.Key
;
48 import com
.intellij
.openapi
.util
.Pair
;
49 import com
.intellij
.openapi
.util
.TextRange
;
50 import com
.intellij
.openapi
.util
.text
.StringUtil
;
51 import com
.intellij
.openapi
.vfs
.VirtualFile
;
52 import com
.intellij
.psi
.PsiDocumentManager
;
53 import com
.intellij
.psi
.PsiFile
;
54 import com
.intellij
.ui
.LightweightHint
;
55 import com
.intellij
.usageView
.UsageInfo
;
56 import com
.intellij
.usages
.*;
57 import org
.jetbrains
.annotations
.NotNull
;
58 import org
.jetbrains
.annotations
.Nullable
;
61 import java
.awt
.event
.FocusAdapter
;
62 import java
.util
.ArrayList
;
63 import java
.util
.Collections
;
64 import java
.util
.Comparator
;
65 import java
.util
.List
;
70 public class FindUtil
{
71 private static final Key
<Direction
> KEY
= Key
.create("FindUtil.KEY");
75 @Nullable static VirtualFile
getVirtualFile(@NotNull Editor myEditor
) {
76 Project project
= myEditor
.getProject();
77 PsiFile file
= project
!= null ? PsiDocumentManager
.getInstance(project
).getPsiFile(myEditor
.getDocument()):null;
78 return file
!= null ? file
.getVirtualFile() : null;
81 private enum Direction
{
85 public static void findWordAtCaret(Project project
, Editor editor
) {
86 int caretOffset
= editor
.getCaretModel().getOffset();
87 Document document
= editor
.getDocument();
88 CharSequence text
= document
.getCharsSequence();
90 int end
= document
.getTextLength();
91 if (!editor
.getSelectionModel().hasSelection()) {
92 for (int i
= caretOffset
- 1; i
>= 0; i
--) {
93 char c
= text
.charAt(i
);
94 if (!Character
.isJavaIdentifierPart(c
)) {
99 for (int i
= caretOffset
; i
< document
.getTextLength(); i
++) {
100 char c
= text
.charAt(i
);
101 if (!Character
.isJavaIdentifierPart(c
)) {
108 start
= editor
.getSelectionModel().getSelectionStart();
109 end
= editor
.getSelectionModel().getSelectionEnd();
114 FindManager findManager
= FindManager
.getInstance(project
);
115 String s
= text
.subSequence(start
, end
).toString();
116 FindSettings
.getInstance().addStringToFind(s
);
117 findManager
.getFindInFileModel().setStringToFind(s
);
118 findManager
.setFindWasPerformed();
119 FindModel model
= new FindModel();
120 model
.setStringToFind(s
);
121 model
.setCaseSensitive(true);
122 model
.setWholeWordsOnly(!editor
.getSelectionModel().hasSelection());
124 final JComponent header
= editor
.getHeaderComponent();
125 if (header
instanceof EditorSearchComponent
) {
126 final EditorSearchComponent searchComponent
= (EditorSearchComponent
)header
;
127 searchComponent
.setTextInField(model
.getStringToFind());
130 findManager
.setFindNextModel(model
);
131 doSearch(project
, editor
, caretOffset
, true, model
, true);
134 public static void find(final Project project
, final Editor editor
) {
135 ApplicationManager
.getApplication().assertIsDispatchThread();
136 final FindManager findManager
= FindManager
.getInstance(project
);
137 String s
= editor
.getSelectionModel().getSelectedText();
139 final FindModel model
= (FindModel
)findManager
.getFindInFileModel().clone();
141 if (s
.indexOf('\n') >= 0) {
142 model
.setGlobal(false);
145 model
.setStringToFind(s
);
146 model
.setGlobal(true);
150 model
.setGlobal(true);
153 model
.setReplaceState(false);
154 model
.setFindAllEnabled(PsiDocumentManager
.getInstance(project
).getPsiFile(editor
.getDocument()) != null);
156 findManager
.showFindDialog(model
, new Runnable() {
158 if (model
.isFindAll()) {
159 findManager
.setFindNextModel(model
);
160 findAll(project
, editor
, model
);
164 if (!model
.isGlobal() && editor
.getSelectionModel().hasSelection()) {
165 int offset
= model
.isForward()
166 ? editor
.getSelectionModel().getSelectionStart()
167 : editor
.getSelectionModel().getSelectionEnd();
168 ScrollType scrollType
= model
.isForward() ? ScrollType
.CENTER_DOWN
: ScrollType
.CENTER_UP
;
169 moveCaretAndDontChangeSelection(editor
, offset
, scrollType
);
173 if (model
.isGlobal()) {
174 if (model
.isFromCursor()) {
175 offset
= editor
.getCaretModel().getOffset();
178 offset
= model
.isForward() ?
0 : editor
.getDocument().getTextLength();
184 if (!editor
.getSelectionModel().hasSelection()) {
185 // TODO[anton] actually, this should never happen - Find dialog should not allow such combination
186 findManager
.setFindNextModel(null);
190 offset
= model
.isForward() ? editor
.getSelectionModel().getSelectionStart() : editor
.getSelectionModel().getSelectionEnd();
193 findManager
.setFindNextModel(null);
194 findManager
.getFindInFileModel().copyFrom(model
);
195 doSearch(project
, editor
, offset
, true, model
, true);
200 public static void findAll(final Project project
, final Editor editor
, final FindModel findModel
) {
201 final Document document
= editor
.getDocument();
202 final PsiFile psiFile
= PsiDocumentManager
.getInstance(project
).getPsiFile(document
);
203 if (psiFile
== null) return;
205 CharSequence text
= document
.getCharsSequence();
206 int textLength
= document
.getTextLength();
207 final List
<Usage
> usages
= new ArrayList
<Usage
>();
208 FindManager findManager
= FindManager
.getInstance(project
);
209 findModel
.setForward(true); // when find all there is no diff in direction
212 VirtualFile virtualFile
= getVirtualFile(editor
);
214 while (offset
< textLength
) {
215 FindResult result
= findManager
.findString(text
, offset
, findModel
, virtualFile
);
216 if (!result
.isStringFound()) break;
218 usages
.add(new UsageInfo2UsageAdapter(new UsageInfo(psiFile
, result
.getStartOffset(), result
.getEndOffset())));
220 final int prevOffset
= offset
;
221 offset
= result
.getEndOffset();
223 if (prevOffset
== offset
) {
224 // for regular expr the size of the match could be zero -> could be infinite loop in finding usages!
228 final UsageTarget
[] usageTargets
= { new FindInProjectUtil
.StringUsageTarget(findModel
.getStringToFind()) };
229 final UsageViewPresentation usageViewPresentation
= FindInProjectUtil
.setupViewPresentation(false, findModel
);
230 UsageViewManager
.getInstance(project
).showUsages(usageTargets
, usages
.toArray(new Usage
[usages
.size()]), usageViewPresentation
);
233 public static void searchBack(Project project
, FileEditor fileEditor
) {
234 if (!(fileEditor
instanceof TextEditor
)) return;
235 TextEditor textEditor
= (TextEditor
)fileEditor
;
236 Editor editor
= textEditor
.getEditor();
238 searchBack(project
, editor
);
241 public static void searchBack(final Project project
, final Editor editor
) {
242 FindManager findManager
= FindManager
.getInstance(project
);
243 if (!findManager
.findWasPerformed()) {
244 find(project
, editor
);
248 FindModel model
= findManager
.getFindNextModel(editor
);
250 model
= findManager
.getFindInFileModel();
252 model
= (FindModel
)model
.clone();
253 model
.setForward(!model
.isForward());
254 if (!model
.isGlobal() && !editor
.getSelectionModel().hasSelection()) {
255 model
.setGlobal(true);
259 if (Direction
.UP
.equals(editor
.getUserData(KEY
)) && !model
.isForward()) {
260 offset
= editor
.getDocument().getTextLength();
262 else if (Direction
.DOWN
.equals(editor
.getUserData(KEY
)) && model
.isForward()) {
266 editor
.putUserData(KEY
, null);
267 offset
= editor
.getCaretModel().getOffset();
268 if (!model
.isForward() && offset
> 0) {
272 searchAgain(project
, editor
, offset
, model
);
275 public static boolean searchAgain(Project project
, FileEditor fileEditor
) {
276 if (!(fileEditor
instanceof TextEditor
)) return false;
277 TextEditor textEditor
= (TextEditor
)fileEditor
;
278 Editor editor
= textEditor
.getEditor();
280 return searchAgain(project
, editor
);
283 public static boolean searchAgain(final Project project
, final Editor editor
) {
284 FindManager findManager
= FindManager
.getInstance(project
);
285 if (!findManager
.findWasPerformed()) {
286 find(project
, editor
);
290 FindModel model
= findManager
.getFindNextModel(editor
);
292 model
= findManager
.getFindInFileModel();
294 model
= (FindModel
)model
.clone();
297 if (Direction
.DOWN
.equals(editor
.getUserData(KEY
)) && model
.isForward()) {
300 else if (Direction
.UP
.equals(editor
.getUserData(KEY
)) && !model
.isForward()) {
301 offset
= editor
.getDocument().getTextLength();
304 editor
.putUserData(KEY
, null);
305 offset
= editor
.getCaretModel().getOffset();
306 if (!model
.isForward() && offset
> 0 ) {
310 return searchAgain(project
, editor
, offset
, model
);
313 private static boolean searchAgain(Project project
, Editor editor
, int offset
, FindModel model
) {
314 if (!model
.isGlobal() && !editor
.getSelectionModel().hasSelection()) {
315 model
.setGlobal(true);
317 model
.setFromCursor(false);
318 if (model
.isReplaceState()) {
319 model
.setPromptOnReplace(true);
320 model
.setReplaceAll(false);
321 replace(project
, editor
, offset
, model
);
325 doSearch(project
, editor
, offset
, true, model
, true);
330 public static void replace(final Project project
, final Editor editor
) {
331 final FindManager findManager
= FindManager
.getInstance(project
);
332 final FindModel model
= (FindModel
)findManager
.getFindInFileModel().clone();
333 final String s
= editor
.getSelectionModel().getSelectedText();
335 if (s
.indexOf('\n') >= 0) {
336 model
.setGlobal(false);
339 model
.setStringToFind(s
);
340 model
.setGlobal(true);
344 model
.setGlobal(true);
346 model
.setReplaceState(true);
348 findManager
.showFindDialog(model
, new Runnable() {
350 if (!model
.isGlobal() && editor
.getSelectionModel().hasSelection()) {
351 int offset
= model
.isForward()
352 ? editor
.getSelectionModel().getSelectionStart()
353 : editor
.getSelectionModel().getSelectionEnd();
354 ScrollType scrollType
= model
.isForward() ? ScrollType
.CENTER_DOWN
: ScrollType
.CENTER_UP
;
355 moveCaretAndDontChangeSelection(editor
, offset
, scrollType
);
358 if (model
.isGlobal()) {
359 if (model
.isFromCursor()) {
360 offset
= editor
.getCaretModel().getOffset();
361 if (!model
.isForward()) {
366 offset
= model
.isForward() ?
0 : editor
.getDocument().getTextLength();
372 if (!editor
.getSelectionModel().hasSelection()) {
373 // TODO[anton] actually, this should never happen - Find dialog should not allow such combination
374 findManager
.setFindNextModel(null);
378 offset
= model
.isForward() ? editor
.getSelectionModel().getSelectionStart() : editor
.getSelectionModel().getSelectionEnd();
381 if (s
!= null && editor
.getSelectionModel().hasSelection() && s
.equals(model
.getStringToFind())) {
382 if (model
.isFromCursor() && model
.isForward()) {
383 offset
= Math
.min(editor
.getSelectionModel().getSelectionStart(), offset
);
385 else if (model
.isFromCursor() && !model
.isForward()) {
386 offset
= Math
.max(editor
.getSelectionModel().getSelectionEnd(), offset
);
389 findManager
.setFindNextModel(null);
390 findManager
.getFindInFileModel().copyFrom(model
);
391 replace(project
, editor
, offset
, model
);
396 public static boolean replace(Project project
, Editor editor
, int offset
, FindModel model
) {
397 Document document
= editor
.getDocument();
399 if (!FileDocumentManager
.getInstance().requestWriting(document
, project
)) {
403 document
.startGuardedBlockChecking();
404 boolean toPrompt
= model
.isPromptOnReplace();
407 ((DocumentEx
) document
).setInBulkUpdate(true);
410 toPrompt
= doReplace(project
, editor
, model
, document
, offset
, toPrompt
);
412 catch (ReadOnlyFragmentModificationException e
) {
413 EditorActionManager
.getInstance().getReadonlyFragmentModificationHandler(document
).handle(e
);
417 ((DocumentEx
) document
).setInBulkUpdate(false);
419 document
.stopGuardedBlockChecking();
425 private static boolean doReplace(Project project
, Editor editor
, FindModel model
, final Document document
, int caretOffset
, boolean toPrompt
) {
426 FindManager findManager
= FindManager
.getInstance(project
);
427 model
= (FindModel
)model
.clone();
430 List
<Pair
<TextRange
,String
>> rangesToChange
= new ArrayList
<Pair
<TextRange
, String
>>();
432 boolean replaced
= false;
433 int offset
= caretOffset
;
434 while (offset
>= 0 && offset
< editor
.getDocument().getTextLength()) {
435 caretOffset
= offset
;
436 FindResult result
= doSearch(project
, editor
, offset
, !replaced
, model
, toPrompt
);
437 if (result
== null) {
440 int startResultOffset
= result
.getStartOffset();
441 model
.setFromCursor(true);
443 int promptResult
= findManager
.showPromptDialog(model
, FindBundle
.message("find.replace.dialog.title"));
444 if (promptResult
== FindManager
.PromptResult
.SKIP
) {
445 offset
= model
.isForward() ? result
.getEndOffset() : startResultOffset
;
448 if (promptResult
== FindManager
.PromptResult
.CANCEL
) {
451 if (promptResult
== FindManager
.PromptResult
.ALL
) {
453 ((DocumentEx
) document
).setInBulkUpdate(true);
457 int startOffset
= result
.getStartOffset();
458 int endOffset
= result
.getEndOffset();
459 String foundString
= document
.getCharsSequence().subSequence(startOffset
, endOffset
).toString();
460 String toReplace
= findManager
.getStringToReplace(foundString
, model
, startOffset
, document
.getText());
461 if (toReplace
== null) break;
463 boolean reallyReplace
= toPrompt
;
464 TextRange textRange
= doReplace(project
, document
, model
, result
, toReplace
, reallyReplace
, rangesToChange
);
466 int newOffset
= model
.isForward() ? textRange
.getEndOffset() : textRange
.getStartOffset();
467 if (newOffset
== offset
) {
468 newOffset
+= model
.isForward() ?
1 : -1;
475 editor
.getCaretModel().moveToOffset(0);
483 CharSequence text
= document
.getCharsSequence();
484 final StringBuilder newText
= new StringBuilder(document
.getTextLength());
485 Collections
.sort(rangesToChange
, new Comparator
<Pair
<TextRange
, String
>>() {
486 public int compare(Pair
<TextRange
, String
> o1
, Pair
<TextRange
, String
> o2
) {
487 return o1
.getFirst().getStartOffset() - o2
.getFirst().getStartOffset();
490 int offsetBefore
= 0;
491 for (Pair
<TextRange
, String
> pair
: rangesToChange
) {
492 TextRange range
= pair
.getFirst();
493 String replace
= pair
.getSecond();
494 newText
.append(text
, offsetBefore
, range
.getStartOffset()); //before change
495 newText
.append(replace
);
496 offsetBefore
= range
.getEndOffset();
497 if (offsetBefore
< caretOffset
) {
498 caretOffset
+= replace
.length() - range
.getLength();
501 newText
.append(text
, offsetBefore
, text
.length()); //tail
502 CommandProcessor
.getInstance().executeCommand(project
, new Runnable() {
504 ApplicationManager
.getApplication().runWriteAction(new Runnable() {
506 document
.setText(newText
);
512 if (caretOffset
> document
.getTextLength()) caretOffset
= document
.getTextLength();
514 editor
.getCaretModel().moveToOffset(caretOffset
);
517 ReplaceInProjectManager
.reportNumberReplacedOccurences(project
, occurrences
);
522 private static FindResult
doSearch(Project project
,
526 FindModel model
, boolean adjustEditor
) {
527 FindManager findManager
= FindManager
.getInstance(project
);
528 Document document
= editor
.getDocument();
530 final FindResult result
= findManager
.findString(document
.getCharsSequence(), offset
, model
, getVirtualFile(editor
));
532 boolean isFound
= result
.isStringFound();
533 if (!model
.isGlobal()) {
534 if (result
.getEndOffset() > editor
.getSelectionModel().getSelectionEnd() ||
535 result
.getStartOffset() < editor
.getSelectionModel().getSelectionStart()) {
541 processNotFound(editor
, model
.getStringToFind(), model
, project
);
547 final CaretModel caretModel
= editor
.getCaretModel();
548 final ScrollingModel scrollingModel
= editor
.getScrollingModel();
549 int oldCaretOffset
= caretModel
.getOffset();
550 boolean forward
= oldCaretOffset
< result
.getStartOffset();
551 final ScrollType scrollType
= forward ? ScrollType
.CENTER_DOWN
: ScrollType
.CENTER_UP
;
553 if (model
.isGlobal()) {
554 caretModel
.moveToOffset(result
.getEndOffset());
555 editor
.getSelectionModel().removeSelection();
556 scrollingModel
.scrollToCaret(scrollType
);
557 scrollingModel
.runActionOnScrollingFinished(
560 scrollingModel
.scrollTo(editor
.offsetToLogicalPosition(result
.getStartOffset()), scrollType
);
561 scrollingModel
.scrollTo(editor
.offsetToLogicalPosition(result
.getEndOffset()), scrollType
);
567 moveCaretAndDontChangeSelection(editor
, result
.getStartOffset(), scrollType
);
568 moveCaretAndDontChangeSelection(editor
, result
.getEndOffset(), scrollType
);
570 IdeDocumentHistory
.getInstance(project
).includeCurrentCommandAsNavigation();
572 EditorColorsManager manager
= EditorColorsManager
.getInstance();
573 TextAttributes selectionAttributes
= manager
.getGlobalScheme().getAttributes(EditorColors
.SEARCH_RESULT_ATTRIBUTES
);
575 if (!model
.isGlobal()) {
576 final RangeHighlighterEx segmentHighlighter
= (RangeHighlighterEx
)editor
.getMarkupModel().addRangeHighlighter(
577 result
.getStartOffset(),
578 result
.getEndOffset(),
579 HighlighterLayer
.SELECTION
+ 1,
580 selectionAttributes
, HighlighterTargetArea
.EXACT_RANGE
);
581 MyListener listener
= new MyListener(editor
, segmentHighlighter
);
582 editor
.getContentComponent().addFocusListener(listener
);
583 caretModel
.addCaretListener(listener
);
586 editor
.getSelectionModel().setSelection(result
.getStartOffset(), result
.getEndOffset());
593 private static class MyListener
extends FocusAdapter
implements CaretListener
{
594 private final Editor myEditor
;
595 private final RangeHighlighter mySegmentHighlighter
;
597 private MyListener(Editor editor
, RangeHighlighter segmentHighlighter
) {
599 mySegmentHighlighter
= segmentHighlighter
;
602 public void caretPositionChanged(CaretEvent e
) {
606 private void removeAll() {
607 myEditor
.getMarkupModel().removeHighlighter(mySegmentHighlighter
);
608 myEditor
.getContentComponent().addFocusListener(this);
609 myEditor
.getCaretModel().removeCaretListener(this);
613 private static void processNotFound(final Editor editor
, String stringToFind
, FindModel model
, Project project
) {
615 String message
= FindBundle
.message("find.search.string.not.found.message", stringToFind
);
617 if (model
.isGlobal()) {
618 final FindModel newModel
= (FindModel
)model
.clone();
619 FindManager findManager
= FindManager
.getInstance(project
);
620 Document document
= editor
.getDocument();
622 if (newModel
.isForward()) {
623 result
= findManager
.findString(document
.getCharsSequence(), 0, model
, getVirtualFile(editor
));
626 result
= findManager
.findString(document
.getCharsSequence(), document
.getTextLength(), model
, getVirtualFile(editor
));
628 if (!result
.isStringFound()) {
632 FindModel modelForNextSearch
= findManager
.getFindNextModel(editor
);
633 if (modelForNextSearch
== null) {
634 modelForNextSearch
= findManager
.getFindInFileModel();
637 if (result
!= null) {
638 if (newModel
.isForward()) {
639 AnAction action
= ActionManager
.getInstance().getAction(
640 modelForNextSearch
.isForward() ? IdeActions
.ACTION_FIND_NEXT
: IdeActions
.ACTION_FIND_PREVIOUS
);
641 String shortcutsText
= KeymapUtil
.getFirstKeyboardShortcutText(action
);
642 if (shortcutsText
.length() > 0) {
643 message
= FindBundle
.message("find.search.again.from.top.hotkey.message", message
, shortcutsText
);
646 message
= FindBundle
.message("find.search.again.from.top.action.message", message
);
648 editor
.putUserData(KEY
, Direction
.DOWN
);
651 AnAction action
= ActionManager
.getInstance().getAction(
652 modelForNextSearch
.isForward() ? IdeActions
.ACTION_FIND_PREVIOUS
: IdeActions
.ACTION_FIND_NEXT
);
653 String shortcutsText
= KeymapUtil
.getFirstKeyboardShortcutText(action
);
654 if (shortcutsText
.length() > 0) {
655 message
= FindBundle
.message("find.search.again.from.bottom.hotkey.message", message
, shortcutsText
);
658 message
= FindBundle
.message("find.search.again.from.bottom.action.message", message
);
660 editor
.putUserData(KEY
, Direction
.UP
);
663 CaretListener listener
= new CaretListener() {
664 public void caretPositionChanged(CaretEvent e
) {
665 editor
.putUserData(KEY
, null);
666 editor
.getCaretModel().removeCaretListener(this);
669 editor
.getCaretModel().addCaretListener(listener
);
671 JComponent component
= HintUtil
.createInformationLabel(message
);
672 final LightweightHint hint
= new LightweightHint(component
);
673 HintManagerImpl
.getInstanceImpl().showEditorHint(hint
, editor
, HintManager
.UNDER
,
674 HintManager
.HIDE_BY_ANY_KEY
| HintManager
.HIDE_BY_TEXT_CHANGE
| HintManager
.HIDE_BY_SCROLLING
,
678 private static TextRange
doReplace(final Project project
, final Document document
, final FindModel model
, FindResult result
, @NotNull String stringToReplace
,
679 boolean reallyReplace
,
680 List
<Pair
<TextRange
, String
>> rangesToChange
) {
681 final int startOffset
= result
.getStartOffset();
682 final int endOffset
= result
.getEndOffset();
684 final String converted
= StringUtil
.convertLineSeparators(stringToReplace
);
687 CommandProcessor
.getInstance().executeCommand(project
, new Runnable() {
689 ApplicationManager
.getApplication().runWriteAction(new Runnable() {
691 //[ven] I doubt converting is a good solution to SCR 21224
692 document
.replaceString(startOffset
, endOffset
, converted
);
697 newOffset
= startOffset
+ converted
.length();
700 TextRange textRange
= new TextRange(startOffset
, endOffset
);
701 rangesToChange
.add(Pair
.create(textRange
,converted
));
703 newOffset
= endOffset
;
706 int start
= startOffset
;
708 if (model
.isRegularExpressions()) {
709 String toFind
= model
.getStringToFind();
710 if (model
.isForward()) {
711 if (StringUtil
.endsWithChar(toFind
, '$')) {
713 int length
= toFind
.length();
714 while (i
+ 2 <= length
&& toFind
.charAt(length
- i
- 2) == '\\') i
++;
715 if (i
% 2 == 0) end
++; //This $ is a special symbol in regexp syntax
717 else if (StringUtil
.startsWithChar(toFind
, '^')) {
718 while (end
< document
.getTextLength() && document
.getCharsSequence().charAt(end
) != '\n') end
++;
722 if (StringUtil
.startsWithChar(toFind
, '^')) {
725 else if (StringUtil
.endsWithChar(toFind
, '$')) {
726 while (start
>= 0 && document
.getCharsSequence().charAt(start
) != '\n') start
--;
730 return new TextRange(start
, end
);
733 private static void moveCaretAndDontChangeSelection(final Editor editor
, int offset
, ScrollType scrollType
) {
734 LogicalPosition pos
= editor
.offsetToLogicalPosition(offset
);
735 editor
.getCaretModel().moveToLogicalPosition(pos
);
736 editor
.getScrollingModel().scrollToCaret(scrollType
);