diff options
Diffstat (limited to 'platform/lang-impl/src/com/intellij/find')
14 files changed, 501 insertions, 157 deletions
diff --git a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java index 8c5864c6569b..8a36638d993c 100644 --- a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java +++ b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -48,6 +48,7 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -68,11 +69,12 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data private final Project myProject; private ActionToolbar myActionsToolbar; - + @NotNull public Editor getEditor() { return myEditor; } + @NotNull private final Editor myEditor; public JTextComponent getSearchField() { @@ -173,7 +175,7 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data return findModel; } - public EditorSearchComponent(Editor editor, Project project) { + public EditorSearchComponent(@NotNull Editor editor, Project project) { this(editor, project, createDefaultFindModel(project, editor)); } @@ -225,7 +227,7 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data } @Override - public void cursorMoved(boolean toChangeSelection) { + public void cursorMoved() { updateExcludeStatus(); } @@ -233,10 +235,7 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data public void updateFinished() { } - @Override - public void editorChanged(SearchResults sr, Editor oldEditor) { } - - public EditorSearchComponent(final Editor editor, final Project project, FindModel findModel) { + public EditorSearchComponent(@NotNull final Editor editor, final Project project, FindModel findModel) { myFindModel = findModel; myProject = project; @@ -367,6 +366,9 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data actionGroup.add(new ShowHistoryAction(mySearchFieldGetter, this)); actionGroup.add(new PrevOccurrenceAction(this, mySearchFieldGetter)); actionGroup.add(new NextOccurrenceAction(this, mySearchFieldGetter)); + actionGroup.add(new AddOccurrenceAction(this)); + actionGroup.add(new RemoveOccurrenceAction(this)); + actionGroup.add(new SelectAllAction(this)); actionGroup.add(new FindAllAction(this)); actionGroup.add(new ToggleMultiline(this)); actionGroup.add(new ToggleMatchCase(this)); @@ -803,10 +805,6 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data } public void close() { - if (myEditor.getSelectionModel().hasSelection()) { - myEditor.getCaretModel().moveToOffset(myEditor.getSelectionModel().getSelectionStart()); - myEditor.getSelectionModel().removeSelection(); - } IdeFocusManager.getInstance(myProject).requestFocus(myEditor.getContentComponent(), false); myLivePreviewController.dispose(); @@ -937,6 +935,18 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data return insets; } + public void selectAllOccurrences() { + FindUtil.selectSearchResultsInEditor(myEditor, mySearchResults.getOccurrences().iterator(), -1); + } + + public void removeOccurrence() { + mySearchResults.prevOccurrence(true); + } + + public void addNextOccurrence() { + mySearchResults.nextOccurrence(true); + } + private static class MyUndoProvider extends TextComponentUndoProvider { private boolean myEnabled = true; public MyUndoProvider(JTextComponent textComponent) { diff --git a/platform/lang-impl/src/com/intellij/find/FindUtil.java b/platform/lang-impl/src/com/intellij/find/FindUtil.java index 0728ea07e2b3..edc906481398 100644 --- a/platform/lang-impl/src/com/intellij/find/FindUtil.java +++ b/platform/lang-impl/src/com/intellij/find/FindUtil.java @@ -31,6 +31,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.actionSystem.EditorActionManager; +import com.intellij.openapi.editor.actions.EditorActionUtil; import com.intellij.openapi.editor.actions.IncrementalFindAction; import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.colors.EditorColorsManager; @@ -70,10 +71,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; +import java.util.*; public class FindUtil { private static final Key<Direction> KEY = Key.create("FindUtil.KEY"); @@ -385,7 +383,7 @@ public class FindUtil { } else { editor.putUserData(KEY, null); - offset = editor.getCaretModel().getOffset(); + offset = model.isGlobal() && model.isForward() ? editor.getSelectionModel().getSelectionEnd() : editor.getCaretModel().getOffset(); if (!model.isForward() && offset > 0) { offset--; } @@ -714,7 +712,18 @@ public class FindUtil { final ScrollType scrollType = forward ? ScrollType.CENTER_DOWN : ScrollType.CENTER_UP; if (model.isGlobal()) { - caretModel.moveToOffset(result.getEndOffset()); + int targetCaretPosition = result.getEndOffset(); + if (selection.getSelectionEnd() - selection.getSelectionStart() == result.getLength()) { + // keeping caret's position relative to selection + // use case: FindNext is used after SelectNextOccurrence action + targetCaretPosition = caretModel.getOffset() - selection.getSelectionStart() + result.getStartOffset(); + } + if (caretModel.getCaretAt(editor.offsetToVisualPosition(targetCaretPosition)) != null) { + // if there's a different caret at target position, don't move current caret/selection + // use case: FindNext is used after SelectNextOccurrence action + return result; + } + caretModel.moveToOffset(targetCaretPosition); selection.removeSelection(); scrollingModel.scrollToCaret(scrollType); scrollingModel.runActionOnScrollingFinished( @@ -829,17 +838,12 @@ public class FindUtil { editor.getCaretModel().addCaretListener(listener); } JComponent component = HintUtil.createInformationLabel(JDOMUtil.escapeText(message, false, false)); - - if (ApplicationManager.getApplication().isUnitTestMode()) { - LivePreview.processNotFound(); - } else { - final LightweightHint hint = new LightweightHint(component); - HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, position, - HintManager.HIDE_BY_ANY_KEY | - HintManager.HIDE_BY_TEXT_CHANGE | - HintManager.HIDE_BY_SCROLLING, - 0, false); - } + final LightweightHint hint = new LightweightHint(component); + HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, position, + HintManager.HIDE_BY_ANY_KEY | + HintManager.HIDE_BY_TEXT_CHANGE | + HintManager.HIDE_BY_SCROLLING, + 0, false); } public static TextRange doReplace(final Project project, @@ -954,4 +958,68 @@ public class FindUtil { }); return view; } + + /** + * Creates a selection in editor per each search result. Existing carets and selections in editor are discarded. + * + * @param caretShiftFromSelectionStart if non-negative, defines caret position relative to selection start, for each created selection. + * if negative, carets will be positioned at selection ends + */ + public static void selectSearchResultsInEditor(@NotNull Editor editor, + @NotNull Iterator<FindResult> resultIterator, + int caretShiftFromSelectionStart) { + if (!editor.getCaretModel().supportsMultipleCarets()) { + return; + } + ArrayList<CaretState> caretStates = new ArrayList<CaretState>(); + while (resultIterator.hasNext()) { + FindResult findResult = resultIterator.next(); + int caretOffset = getCaretPosition(findResult, caretShiftFromSelectionStart); + int selectionStartOffset = findResult.getStartOffset(); + int selectionEndOffset = findResult.getEndOffset(); + EditorActionUtil.makePositionVisible(editor, caretOffset); + EditorActionUtil.makePositionVisible(editor, selectionStartOffset); + EditorActionUtil.makePositionVisible(editor, selectionEndOffset); + caretStates.add(new CaretState(editor.offsetToLogicalPosition(caretOffset), + editor.offsetToLogicalPosition(selectionStartOffset), + editor.offsetToLogicalPosition(selectionEndOffset))); + } + if (caretStates.isEmpty()) { + return; + } + editor.getCaretModel().setCaretsAndSelections(caretStates); + } + + /** + * Attempts to add a new caret to editor, with selection corresponding to given search result. + * + * @param caretShiftFromSelectionStart if non-negative, defines caret position relative to selection start, for each created selection. + * if negative, caret will be positioned at selection end + * @return <code>true</code> if caret was added successfully, <code>false</code> if it cannot be done, e.g. because a caret already + * exists at target position + */ + public static boolean selectSearchResultInEditor(@NotNull Editor editor, @NotNull FindResult result, int caretShiftFromSelectionStart) { + if (!editor.getCaretModel().supportsMultipleCarets()) { + return false; + } + int caretOffset = getCaretPosition(result, caretShiftFromSelectionStart); + EditorActionUtil.makePositionVisible(editor, caretOffset); + Caret newCaret = editor.getCaretModel().addCaret(editor.offsetToVisualPosition(caretOffset)); + if (newCaret == null) { + return false; + } + else { + int selectionStartOffset = result.getStartOffset(); + int selectionEndOffset = result.getEndOffset(); + EditorActionUtil.makePositionVisible(editor, selectionStartOffset); + EditorActionUtil.makePositionVisible(editor, selectionEndOffset); + newCaret.setSelection(selectionStartOffset, selectionEndOffset); + return true; + } + } + + private static int getCaretPosition(FindResult findResult, int caretShiftFromSelectionStart) { + return caretShiftFromSelectionStart < 0 + ? findResult.getEndOffset() : Math.min(findResult.getStartOffset() + caretShiftFromSelectionStart, findResult.getEndOffset()); + } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/AddOccurrenceAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/AddOccurrenceAction.java new file mode 100644 index 000000000000..9064113d9c9b --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/AddOccurrenceAction.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2014 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. + */ +package com.intellij.find.editorHeaderActions; + +import com.intellij.find.EditorSearchComponent; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.project.DumbAware; + +import java.util.Arrays; + +public class AddOccurrenceAction extends EditorHeaderAction implements DumbAware { + public AddOccurrenceAction(EditorSearchComponent editorSearchComponent) { + super(editorSearchComponent); + + copyFrom(ActionManager.getInstance().getAction(IdeActions.ACTION_SELECT_NEXT_OCCURENCE)); + getTemplatePresentation().setIcon(AllIcons.General.Add); + + registerShortcutsForComponent(Arrays.asList(getShortcutSet().getShortcuts()), editorSearchComponent.getSearchField()); + } + + @Override + public void actionPerformed(AnActionEvent e) { + getEditorSearchComponent().addNextOccurrence(); + } + + @Override + public void update(AnActionEvent e) { + boolean isFind = !getEditorSearchComponent().getFindModel().isReplaceState(); + boolean hasMatches = getEditorSearchComponent().hasMatches(); + e.getPresentation().setVisible(isFind); + e.getPresentation().setEnabled(isFind && hasMatches); + }} diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderAction.java index 6cdba4b1e6eb..15348730a41d 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderAction.java @@ -1,21 +1,34 @@ +/* + * Copyright 2000-2014 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. + */ package com.intellij.find.editorHeaderActions; import com.intellij.find.EditorSearchComponent; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.CustomShortcutSet; -import com.intellij.openapi.actionSystem.KeyboardShortcut; import com.intellij.openapi.actionSystem.Shortcut; import javax.swing.*; -import java.util.ArrayList; import java.util.List; public abstract class EditorHeaderAction extends AnAction { private final EditorSearchComponent myEditorSearchComponent; - protected static void registerShortcutsForComponent(List<Shortcut> shortcuts, JComponent component, AnAction a) { - a.registerCustomShortcutSet( + protected void registerShortcutsForComponent(List<Shortcut> shortcuts, JComponent component) { + registerCustomShortcutSet( new CustomShortcutSet(shortcuts.toArray(new Shortcut[shortcuts.size()])), component); } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/NextOccurrenceAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/NextOccurrenceAction.java index 1eb933cf2d03..0e6e67168521 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/NextOccurrenceAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/NextOccurrenceAction.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2014 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. + */ package com.intellij.find.editorHeaderActions; import com.intellij.find.EditorSearchComponent; @@ -35,7 +50,7 @@ public class NextOccurrenceAction extends EditorHeaderAction implements DumbAwar shortcuts.add(new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), null)); } - registerShortcutsForComponent(shortcuts, editorTextField.get(), this); + registerShortcutsForComponent(shortcuts, editorTextField.get()); } @Override diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevOccurrenceAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevOccurrenceAction.java index f5a2d3911b43..586f90a835d1 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevOccurrenceAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevOccurrenceAction.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2014 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. + */ package com.intellij.find.editorHeaderActions; import com.intellij.find.EditorSearchComponent; @@ -34,7 +49,7 @@ public class PrevOccurrenceAction extends EditorHeaderAction implements DumbAwar shortcuts.add(new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_DOWN_MASK), null)); } - registerShortcutsForComponent(shortcuts, editorTextField.get(), this); + registerShortcutsForComponent(shortcuts, editorTextField.get()); } @Override diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RemoveOccurrenceAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RemoveOccurrenceAction.java new file mode 100644 index 000000000000..b739f942991d --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RemoveOccurrenceAction.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2014 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. + */ +package com.intellij.find.editorHeaderActions; + +import com.intellij.find.EditorSearchComponent; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.project.DumbAware; + +import java.util.Arrays; + +public class RemoveOccurrenceAction extends EditorHeaderAction implements DumbAware { + public RemoveOccurrenceAction(EditorSearchComponent editorSearchComponent) { + super(editorSearchComponent); + + copyFrom(ActionManager.getInstance().getAction(IdeActions.ACTION_UNSELECT_PREVIOUS_OCCURENCE)); + getTemplatePresentation().setIcon(AllIcons.General.Remove); + + registerShortcutsForComponent(Arrays.asList(getShortcutSet().getShortcuts()), editorSearchComponent.getSearchField()); + } + + @Override + public void actionPerformed(AnActionEvent e) { + getEditorSearchComponent().removeOccurrence(); + } + + @Override + public void update(AnActionEvent e) { + boolean isFind = !getEditorSearchComponent().getFindModel().isReplaceState(); + boolean hasMatches = getEditorSearchComponent().hasMatches(); + e.getPresentation().setVisible(isFind); + e.getPresentation().setEnabled(isFind && hasMatches); + } +} diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RestorePreviousSettingsAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RestorePreviousSettingsAction.java index cad2be2ddc20..2607ebf0557b 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RestorePreviousSettingsAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RestorePreviousSettingsAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -39,8 +39,7 @@ public class RestorePreviousSettingsAction extends EditorHeaderAction implements public RestorePreviousSettingsAction(EditorSearchComponent editorSearchComponent, JTextComponent textField) { super(editorSearchComponent); myTextField = textField; - registerShortcutsForComponent(Collections.<Shortcut>singletonList(SHORTCUT), - textField, this); + registerShortcutsForComponent(Collections.<Shortcut>singletonList(SHORTCUT), textField); } @Override diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SelectAllAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SelectAllAction.java new file mode 100644 index 000000000000..0e52566f6fbc --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SelectAllAction.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2014 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. + */ +package com.intellij.find.editorHeaderActions; + +import com.intellij.find.EditorSearchComponent; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.project.DumbAware; +import com.intellij.util.containers.ContainerUtil; + +import java.util.ArrayList; +import java.util.List; + +public class SelectAllAction extends EditorHeaderAction implements DumbAware { + public SelectAllAction(EditorSearchComponent editorSearchComponent) { + super(editorSearchComponent); + + copyFrom(ActionManager.getInstance().getAction(IdeActions.ACTION_SELECT_ALL_OCCURRENCES)); + getTemplatePresentation().setIcon(AllIcons.Actions.Selectall); + + List<Shortcut> shortcuts = new ArrayList<Shortcut>(); + ContainerUtil.addAll(shortcuts, getShortcutSet().getShortcuts()); + ContainerUtil.addAll(shortcuts, CommonShortcuts.ALT_ENTER.getShortcuts()); + registerShortcutsForComponent(shortcuts, editorSearchComponent.getSearchField()); + } + + @Override + public void actionPerformed(AnActionEvent e) { + getEditorSearchComponent().selectAllOccurrences(); + getEditorSearchComponent().close(); + } + + @Override + public void update(AnActionEvent e) { + boolean isFind = !getEditorSearchComponent().getFindModel().isReplaceState(); + boolean hasMatches = getEditorSearchComponent().hasMatches(); + e.getPresentation().setVisible(isFind); + e.getPresentation().setEnabled(isFind && hasMatches); + } +} diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java index 23f14c5eb0b4..e4570b7379bf 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java @@ -47,6 +47,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.ex.VirtualFileManagerEx; import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.ui.content.Content; @@ -54,6 +55,7 @@ import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageViewManager; import com.intellij.usages.ConfigurableUsageTarget; import com.intellij.usages.FindUsagesProcessPresentation; +import com.intellij.usages.UsageView; import com.intellij.usages.UsageViewPresentation; import com.intellij.util.Function; import com.intellij.util.PatternUtil; @@ -324,7 +326,7 @@ public class FindInProjectUtil { return processPresentation; } - public static class StringUsageTarget implements ConfigurableUsageTarget, ItemPresentation { + public static class StringUsageTarget implements ConfigurableUsageTarget, ItemPresentation, TypeSafeDataProvider { @NotNull protected final Project myProject; @NotNull protected final FindModel myFindModel; @@ -423,5 +425,12 @@ public class FindInProjectUtil { public KeyboardShortcut getShortcut() { return ActionManager.getInstance().getKeyboardShortcut("FindInPath"); } + + @Override + public void calcData(DataKey key, DataSink sink) { + if (key == UsageView.USAGE_SCOPE) { + sink.put(UsageView.USAGE_SCOPE, GlobalSearchScope.allScope(myProject)); + } + } } } diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java index c20b5925721d..4ba97e0151e5 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -121,7 +121,7 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search } highlightUsages(); - updateCursorHighlighting(false); + updateCursorHighlighting(); if (myInSmartUpdate) { clearUnusedHightlighters(); myInSmartUpdate = false; @@ -218,9 +218,9 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search } @Override - public void cursorMoved(boolean toChangeSelection) { + public void cursorMoved() { updateInSelectionHighlighters(); - updateCursorHighlighting(toChangeSelection); + updateCursorHighlighting(); } @Override @@ -228,14 +228,7 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search dumpState(); } - @Override - public void editorChanged(SearchResults sr, Editor oldEditor) { - removeFromEditor(); - oldEditor.getDocument().removeDocumentListener(this); - mySearchResults.getEditor().getDocument().addDocumentListener(this); - } - - private void updateCursorHighlighting(boolean scroll) { + private void updateCursorHighlighting() { hideBalloon(); if (myCursorHighlighter != null) { @@ -245,7 +238,6 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search final FindResult cursor = mySearchResults.getCursor(); Editor editor = mySearchResults.getEditor(); - SelectionModel selection = editor.getSelectionModel(); if (cursor != null) { Set<RangeHighlighter> dummy = new HashSet<RangeHighlighter>(); highlightRange(cursor, new TextAttributes(null, null, Color.BLACK, EffectType.ROUNDED_BOX, 0), dummy); @@ -253,33 +245,6 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search myCursorHighlighter = dummy.iterator().next(); } - if (scroll) { - if (mySearchResults.getFindModel().isGlobal()) { - FoldingModel foldingModel = editor.getFoldingModel(); - final FoldRegion[] allRegions = editor.getFoldingModel().getAllFoldRegions(); - - foldingModel.runBatchFoldingOperation(new Runnable() { - @Override - public void run() { - for (FoldRegion region : allRegions) { - if (!region.isValid()) continue; - if (cursor.intersects(TextRange.create(region))) { - region.setExpanded(true); - } - } - } - }); - selection.setSelection(cursor.getStartOffset(), cursor.getEndOffset()); - - editor.getCaretModel().moveToOffset(cursor.getEndOffset()); - editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); - } else { - if (!SearchResults.insideVisibleArea(editor, cursor)) { - LogicalPosition pos = editor.offsetToLogicalPosition(cursor.getStartOffset()); - editor.getScrollingModel().scrollTo(pos, ScrollType.CENTER); - } - } - } editor.getScrollingModel().runActionOnScrollingFinished(new Runnable() { @Override public void run() { @@ -496,6 +461,8 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search new Processor<RangeHighlighterEx>() { @Override public boolean process(RangeHighlighterEx highlighter) { + if (!highlighter.getEditorFilter().avaliableIn(mySearchResults.getEditor())) return true; + TextAttributes textAttributes = highlighter.getTextAttributes(); if (highlighter.getUserData(SEARCH_MARKER) != null && diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java index 8368f1b2f2aa..94a6c3f9c1bc 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2014 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. + */ package com.intellij.find.impl.livePreview; import com.intellij.find.*; @@ -83,9 +98,9 @@ public class LivePreviewController implements LivePreview.Delegate, FindUtil.Rep public void moveCursor(SearchResults.Direction direction) { if (direction == SearchResults.Direction.UP) { - mySearchResults.prevOccurrence(); + mySearchResults.prevOccurrence(false); } else { - mySearchResults.nextOccurrence(); + mySearchResults.nextOccurrence(false); } } diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java index dff4989bb2f6..39b17dd2acc8 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java @@ -21,9 +21,7 @@ import com.intellij.find.FindModel; import com.intellij.find.FindResult; import com.intellij.find.FindUtil; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.RangeMarker; -import com.intellij.openapi.editor.SelectionModel; +import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.event.DocumentListener; import com.intellij.openapi.fileEditor.FileDocumentManager; @@ -38,6 +36,7 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import com.intellij.util.containers.Stack; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -70,6 +69,7 @@ public class SearchResults implements DocumentListener { private @Nullable FindResult myCursor; + @NotNull private List<FindResult> myOccurrences = new ArrayList<FindResult>(); private final Set<RangeMarker> myExcluded = new HashSet<RangeMarker>(); @@ -90,6 +90,8 @@ public class SearchResults implements DocumentListener { private final Stack<Pair<FindModel, FindResult>> myCursorPositions = new Stack<Pair<FindModel, FindResult>>(); + private final SelectionManager mySelectionManager = new SelectionManager(this); + public SearchResults(Editor editor, Project project) { myEditor = editor; myProject = project; @@ -127,9 +129,8 @@ public class SearchResults implements DocumentListener { public void exclude(FindResult occurrence) { boolean include = false; - final TextRange r = occurrence; for (RangeMarker rangeMarker : myExcluded) { - if (TextRange.areSegmentsEqual(rangeMarker, r)) { + if (TextRange.areSegmentsEqual(rangeMarker, occurrence)) { myExcluded.remove(rangeMarker); rangeMarker.dispose(); include = true; @@ -137,7 +138,7 @@ public class SearchResults implements DocumentListener { } } if (!include) { - myExcluded.add(myEditor.getDocument().createRangeMarker(r.getStartOffset(), r.getEndOffset(), true)); + myExcluded.add(myEditor.getDocument().createRangeMarker(occurrence.getStartOffset(), occurrence.getEndOffset(), true)); } notifyChanged(); } @@ -149,8 +150,7 @@ public class SearchResults implements DocumentListener { public interface SearchResultsListener { void searchResultsUpdated(SearchResults sr); - void editorChanged(SearchResults sr, Editor oldEditor); - void cursorMoved(boolean toChangeSelection); + void cursorMoved(); void updateFinished(); } @@ -175,6 +175,7 @@ public class SearchResults implements DocumentListener { return myCursor; } + @NotNull public List<FindResult> getOccurrences() { return myOccurrences; } @@ -184,19 +185,7 @@ public class SearchResults implements DocumentListener { return myProject; } - public synchronized void setEditor(Editor editor) { - Editor oldOne = myEditor; - myEditor = editor; - notifyEditorChanged(oldOne); - } - - private void notifyEditorChanged(Editor oldOne) { - for (SearchResultsListener listener : myListeners) { - listener.editorChanged(this, oldOne); - } - } - - public synchronized Editor getEditor() { + public Editor getEditor() { return myEditor; } @@ -334,7 +323,7 @@ public class SearchResults implements DocumentListener { myEditor.getDocument().removeDocumentListener(this); } - private void searchCompleted(List<FindResult> occurrences, Editor editor, @Nullable FindModel findModel, + private void searchCompleted(@NotNull List<FindResult> occurrences, Editor editor, @Nullable FindModel findModel, boolean toChangeSelection, @Nullable TextRange next, int stamp) { if (stamp < myLastUpdatedStamp){ return; @@ -344,7 +333,7 @@ public class SearchResults implements DocumentListener { return; } myOccurrences = occurrences; - final TextRange oldCursorRange = myCursor != null ? myCursor : null; + final TextRange oldCursorRange = myCursor; Collections.sort(myOccurrences, new Comparator<FindResult>() { @Override public int compare(FindResult findResult, FindResult findResult1) { @@ -357,7 +346,10 @@ public class SearchResults implements DocumentListener { updateExcluded(); notifyChanged(); if (oldCursorRange == null || myCursor == null || !myCursor.equals(oldCursorRange)) { - notifyCursorMoved(toChangeSelection); + if (toChangeSelection) { + mySelectionManager.updateSelection(true, true); + } + notifyCursorMoved(); } dumpIfNeeded(); } @@ -389,7 +381,7 @@ public class SearchResults implements DocumentListener { myCursor = firstOccurrenceAfterOffset(oldCursorRange.getEndOffset()); } else { if (justReplaced) { - nextOccurrence(false, next, false, justReplaced); + nextOccurrence(false, next, false, true, false); } else { FindResult afterCaret = oldCursorRange == null ? firstOccurrenceAtOrAfterCaret() : firstOccurrenceAfterCaret(); if (afterCaret != null) { @@ -405,7 +397,7 @@ public class SearchResults implements DocumentListener { } } if (!justReplaced && myCursor == null && hasMatches()) { - nextOccurrence(true, oldCursorRange, false, false); + nextOccurrence(true, oldCursorRange, false, false, false); } if (toPush && myCursor != null){ push(); @@ -445,6 +437,13 @@ public class SearchResults implements DocumentListener { return occurrence; } } + int selectionStartOffset = getEditor().getSelectionModel().getSelectionStart(); + int selectionEndOffset = getEditor().getSelectionModel().getSelectionEnd(); + for (FindResult occurrence : myOccurrences) { + if (selectionEndOffset >= occurrence.getEndOffset() && selectionStartOffset <= occurrence.getStartOffset()) { + return occurrence; + } + } return firstOccurrenceAfterCaret(); } @@ -462,25 +461,6 @@ public class SearchResults implements DocumentListener { } @Nullable - private FindResult firstVisibleOccurrence() { - int offset = Integer.MAX_VALUE; - FindResult firstOccurrence = null; - FindResult firstVisibleOccurrence = null; - for (FindResult o : getOccurrences()) { - if (insideVisibleArea(myEditor, o)) { - if (firstVisibleOccurrence == null || o.getStartOffset() < firstVisibleOccurrence.getStartOffset()) { - firstVisibleOccurrence = o; - } - } - if (o.getStartOffset() < offset) { - offset = o.getStartOffset(); - firstOccurrence = o; - } - } - return firstVisibleOccurrence != null ? firstVisibleOccurrence : firstOccurrence; - } - - @Nullable private FindResult firstOccurrenceBeforeCaret() { int offset = getEditor().getCaretModel().getOffset(); return firstOccurrenceBeforeOffset(offset); @@ -554,32 +534,45 @@ public class SearchResults implements DocumentListener { return null; } - public void prevOccurrence() { - FindResult next = null; - if (myFindModel == null) return; - boolean processFromTheBeginning = false; - if (myNotFoundState) { - myNotFoundState = false; - processFromTheBeginning = true; - } - if (!myFindModel.isGlobal()) { - if (myCursor != null) { - next = prevOccurrence(myCursor); + public void prevOccurrence(boolean findSelected) { + if (findSelected) { + if (mySelectionManager.removeCurrentSelection()) { + myCursor = firstOccurrenceAtOrAfterCaret(); } - } else { - next = firstOccurrenceBeforeCaret(); - } - if (next == null) { - if (processFromTheBeginning) { - if (hasMatches()) { - next = getOccurrences().get(getOccurrences().size()-1); + else { + myCursor = null; + } + notifyCursorMoved(); + } + else { + FindResult next = null; + if (myFindModel == null) return; + boolean processFromTheBeginning = false; + if (myNotFoundState) { + myNotFoundState = false; + processFromTheBeginning = true; + } + if (!myFindModel.isGlobal()) { + if (myCursor != null) { + next = prevOccurrence(myCursor); + } + } + else { + next = firstOccurrenceBeforeCaret(); + } + if (next == null) { + if (processFromTheBeginning) { + if (hasMatches()) { + next = getOccurrences().get(getOccurrences().size() - 1); + } + } + else { + setNotFoundState(false); } - } else { - setNotFoundState(false); } - } - moveCursorTo(next); + moveCursorTo(next, false); + } push(); } @@ -587,13 +580,13 @@ public class SearchResults implements DocumentListener { myCursorPositions.push(Pair.create(myFindModel, myCursor)); } - public void nextOccurrence() { + public void nextOccurrence(boolean retainOldSelection) { if (myFindModel == null) return; - nextOccurrence(false, myCursor != null ? myCursor : null, true, false); + nextOccurrence(false, myCursor, true, false, retainOldSelection); push(); } - private void nextOccurrence(boolean processFromTheBeginning, TextRange cursor, boolean toNotify, boolean justReplaced) { + private void nextOccurrence(boolean processFromTheBeginning, TextRange cursor, boolean toNotify, boolean justReplaced, boolean retainOldSelection) { FindResult next; if (myNotFoundState) { myNotFoundState = false; @@ -614,22 +607,24 @@ public class SearchResults implements DocumentListener { } } if (toNotify) { - moveCursorTo(next); + moveCursorTo(next, retainOldSelection); } else { myCursor = next; } } - public void moveCursorTo(FindResult next) { - if (next != null) { + public void moveCursorTo(FindResult next, boolean retainOldSelection) { + if (next != null && !mySelectionManager.isSelected(next)) { + retainOldSelection &= (myCursor != null && mySelectionManager.isSelected(myCursor)); myCursor = next; - notifyCursorMoved(true); + mySelectionManager.updateSelection(!retainOldSelection, false); + notifyCursorMoved(); } } - private void notifyCursorMoved(boolean toChangeSelection) { + private void notifyCursorMoved() { for (SearchResultsListener listener : myListeners) { - listener.cursorMoved(toChangeSelection); + listener.cursorMoved(); } } } diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SelectionManager.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SelectionManager.java new file mode 100644 index 000000000000..50f37927c506 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SelectionManager.java @@ -0,0 +1,90 @@ +/* + * Copyright 2000-2014 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. + */ +package com.intellij.find.impl.livePreview; + +import com.intellij.find.FindResult; +import com.intellij.find.FindUtil; +import com.intellij.openapi.editor.*; +import com.intellij.openapi.util.TextRange; +import org.jetbrains.annotations.NotNull; + +public class SelectionManager { + @NotNull private final SearchResults mySearchResults; + + public SelectionManager(@NotNull SearchResults results) { + mySearchResults = results; + } + + public void updateSelection(boolean removePreviousSelection, boolean removeAllPreviousSelections) { + Editor editor = mySearchResults.getEditor(); + if (removeAllPreviousSelections) { + editor.getCaretModel().removeSecondaryCarets(); + } + final FindResult cursor = mySearchResults.getCursor(); + if (cursor == null) { + return; + } + if (mySearchResults.getFindModel().isGlobal()) { + if (removePreviousSelection || removeAllPreviousSelections) { + FoldingModel foldingModel = editor.getFoldingModel(); + final FoldRegion[] allRegions = editor.getFoldingModel().getAllFoldRegions(); + + foldingModel.runBatchFoldingOperation(new Runnable() { + @Override + public void run() { + for (FoldRegion region : allRegions) { + if (!region.isValid()) continue; + if (cursor.intersects(TextRange.create(region))) { + region.setExpanded(true); + } + } + } + }); + editor.getSelectionModel().setSelection(cursor.getStartOffset(), cursor.getEndOffset()); + editor.getCaretModel().moveToOffset(cursor.getEndOffset()); + } + else { + FindUtil.selectSearchResultInEditor(editor, cursor, -1); + } + editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); + } else { + if (!SearchResults.insideVisibleArea(editor, cursor)) { + LogicalPosition pos = editor.offsetToLogicalPosition(cursor.getStartOffset()); + editor.getScrollingModel().scrollTo(pos, ScrollType.CENTER); + } + } + } + + public boolean removeCurrentSelection() { + Editor editor = mySearchResults.getEditor(); + CaretModel caretModel = editor.getCaretModel(); + Caret primaryCaret = caretModel.getPrimaryCaret(); + if (caretModel.getCaretCount() > 1) { + caretModel.removeCaret(primaryCaret); + return true; + } + else { + primaryCaret.moveToOffset(primaryCaret.getSelectionStart()); + primaryCaret.removeSelection(); + return false; + } + } + + public boolean isSelected(@NotNull FindResult result) { + Editor editor = mySearchResults.getEditor(); + return editor.getCaretModel().getCaretAt(editor.offsetToVisualPosition(result.getEndOffset())) != null; + } +} |