mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-122076, IDEA-122172 Multicaret actions in quick find mode
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.intellij.find.editorHeaderActions.*;
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.openapi.util.Getter;
|
||||
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
|
||||
|
||||
import javax.swing.text.JTextComponent;
|
||||
import java.io.IOException;
|
||||
|
||||
public class FindInEditorMultiCaretTest extends LightPlatformCodeInsightFixtureTestCase {
|
||||
public void testBasic() throws IOException {
|
||||
init("abc\n" +
|
||||
"abc\n" +
|
||||
"abc");
|
||||
initFind();
|
||||
setTextToFind("b");
|
||||
checkResultByText("a<selection>b<caret></selection>c\n" +
|
||||
"abc\n" +
|
||||
"abc");
|
||||
addOccurrence();
|
||||
checkResultByText("a<selection>b<caret></selection>c\n" +
|
||||
"a<selection>b<caret></selection>c\n" +
|
||||
"abc");
|
||||
nextOccurrence();
|
||||
checkResultByText("a<selection>b<caret></selection>c\n" +
|
||||
"abc\n" +
|
||||
"a<selection>b<caret></selection>c");
|
||||
prevOccurrence();
|
||||
checkResultByText("a<selection>b<caret></selection>c\n" +
|
||||
"a<selection>b<caret></selection>c\n" +
|
||||
"abc");
|
||||
removeOccurrence();
|
||||
checkResultByText("a<selection>b<caret></selection>c\n" +
|
||||
"abc\n" +
|
||||
"abc");
|
||||
allOccurrences();
|
||||
checkResultByText("a<selection>b<caret></selection>c\n" +
|
||||
"a<selection>b<caret></selection>c\n" +
|
||||
"a<selection>b<caret></selection>c");
|
||||
assertNull(getEditorSearchComponent());
|
||||
}
|
||||
|
||||
public void testActionsWorkFromEditor() throws IOException {
|
||||
init("abc\n" +
|
||||
"abc\n" +
|
||||
"abc");
|
||||
initFind();
|
||||
setTextToFind("b");
|
||||
checkResultByText("a<selection>b<caret></selection>c\n" +
|
||||
"abc\n" +
|
||||
"abc");
|
||||
addOccurrenceFromEditor();
|
||||
checkResultByText("a<selection>b<caret></selection>c\n" +
|
||||
"a<selection>b<caret></selection>c\n" +
|
||||
"abc");
|
||||
nextOccurrenceFromEditor();
|
||||
checkResultByText("a<selection>b<caret></selection>c\n" +
|
||||
"abc\n" +
|
||||
"a<selection>b<caret></selection>c");
|
||||
prevOccurrenceFromEditor();
|
||||
checkResultByText("a<selection>b<caret></selection>c\n" +
|
||||
"a<selection>b<caret></selection>c\n" +
|
||||
"abc");
|
||||
removeOccurrenceFromEditor();
|
||||
checkResultByText("a<selection>b<caret></selection>c\n" +
|
||||
"abc\n" +
|
||||
"abc");
|
||||
allOccurrencesFromEditor();
|
||||
checkResultByText("a<selection>b<caret></selection>c\n" +
|
||||
"a<selection>b<caret></selection>c\n" +
|
||||
"a<selection>b<caret></selection>c");
|
||||
assertNull(getEditorSearchComponent());
|
||||
}
|
||||
|
||||
public void testCloseRetainsMulticaretSelection() throws IOException {
|
||||
init("abc\n" +
|
||||
"abc\n" +
|
||||
"abc");
|
||||
initFind();
|
||||
setTextToFind("b");
|
||||
addOccurrence();
|
||||
closeFind();
|
||||
checkResultByText("a<selection>b<caret></selection>c\n" +
|
||||
"a<selection>b<caret></selection>c\n" +
|
||||
"abc");
|
||||
}
|
||||
|
||||
public void testTextModificationRemovesOldSelections() throws IOException {
|
||||
init("abc\n" +
|
||||
"abc\n" +
|
||||
"abc");
|
||||
initFind();
|
||||
setTextToFind("b");
|
||||
addOccurrence();
|
||||
setTextToFind("bc");
|
||||
|
||||
assertEquals(1, myFixture.getEditor().getCaretModel().getCaretCount());
|
||||
assertEquals("bc", myFixture.getEditor().getSelectionModel().getSelectedText());
|
||||
}
|
||||
|
||||
public void testSecondFindNavigatesToTheSameOccurrence() throws IOException {
|
||||
init("ab<caret>c\n" +
|
||||
"abc\n" +
|
||||
"abc");
|
||||
initFind();
|
||||
setTextToFind("abc");
|
||||
checkResultByText("abc\n" +
|
||||
"<selection>abc<caret></selection>\n" +
|
||||
"abc");
|
||||
closeFind();
|
||||
initFind();
|
||||
setTextToFind("abc");
|
||||
checkResultByText("abc\n" +
|
||||
"<selection>abc<caret></selection>\n" +
|
||||
"abc");
|
||||
}
|
||||
|
||||
private void setTextToFind(String text) {
|
||||
EditorSearchComponent editorSearchComponent = getEditorSearchComponent();
|
||||
assertNotNull(editorSearchComponent);
|
||||
JTextComponent searchField = editorSearchComponent.getSearchField();
|
||||
assertNotNull(searchField);
|
||||
for (int i = 0; i <= text.length(); i++) {
|
||||
searchField.setText(text.substring(0, i)); // emulate typing chars one by one
|
||||
}
|
||||
}
|
||||
|
||||
private void nextOccurrence() {
|
||||
final EditorSearchComponent editorSearchComponent = getEditorSearchComponent();
|
||||
executeAction(new NextOccurrenceAction(editorSearchComponent, new Getter<JTextComponent>() {
|
||||
@Override
|
||||
public JTextComponent get() {
|
||||
return editorSearchComponent.getSearchField();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void prevOccurrence() {
|
||||
final EditorSearchComponent editorSearchComponent = getEditorSearchComponent();
|
||||
executeAction(new PrevOccurrenceAction(editorSearchComponent, new Getter<JTextComponent>() {
|
||||
@Override
|
||||
public JTextComponent get() {
|
||||
return editorSearchComponent.getSearchField();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void addOccurrence() {
|
||||
executeAction(new AddOccurrenceAction(getEditorSearchComponent()));
|
||||
}
|
||||
|
||||
private void removeOccurrence() {
|
||||
executeAction(new RemoveOccurrenceAction(getEditorSearchComponent()));
|
||||
}
|
||||
|
||||
private void allOccurrences() {
|
||||
executeAction(new SelectAllAction(getEditorSearchComponent()));
|
||||
}
|
||||
|
||||
private void nextOccurrenceFromEditor() {
|
||||
myFixture.performEditorAction(IdeActions.ACTION_FIND_NEXT);
|
||||
}
|
||||
|
||||
private void prevOccurrenceFromEditor() {
|
||||
myFixture.performEditorAction(IdeActions.ACTION_FIND_PREVIOUS);
|
||||
}
|
||||
|
||||
private void addOccurrenceFromEditor() {
|
||||
myFixture.performEditorAction(IdeActions.ACTION_SELECT_NEXT_OCCURENCE);
|
||||
}
|
||||
|
||||
private void removeOccurrenceFromEditor() {
|
||||
myFixture.performEditorAction(IdeActions.ACTION_UNSELECT_PREVIOUS_OCCURENCE);
|
||||
}
|
||||
|
||||
private void allOccurrencesFromEditor() {
|
||||
myFixture.performEditorAction(IdeActions.ACTION_SELECT_ALL_OCCURRENCES);
|
||||
}
|
||||
|
||||
private void closeFind() {
|
||||
EditorSearchComponent editorSearchComponent = getEditorSearchComponent();
|
||||
executeAction(new CloseOnESCAction(editorSearchComponent, editorSearchComponent.getSearchField()));
|
||||
}
|
||||
|
||||
private static void executeAction(EditorHeaderAction action) {
|
||||
action.actionPerformed(AnActionEvent.createFromInputEvent(action, null, ActionPlaces.EDITOR_TOOLBAR));
|
||||
}
|
||||
|
||||
private void initFind() {
|
||||
myFixture.performEditorAction("Find");
|
||||
}
|
||||
|
||||
private EditorSearchComponent getEditorSearchComponent() {
|
||||
return (EditorSearchComponent)myFixture.getEditor().getHeaderComponent();
|
||||
}
|
||||
|
||||
private void init(String text) {
|
||||
myFixture.configureByText(getTestName(false) + ".txt", text);
|
||||
}
|
||||
|
||||
private void checkResultByText(String text) {
|
||||
myFixture.checkResult(text);
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
@@ -960,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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}}
|
||||
+17
-4
@@ -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);
|
||||
}
|
||||
|
||||
+16
-1
@@ -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
|
||||
|
||||
+16
-1
@@ -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
|
||||
|
||||
+49
@@ -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);
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
+17
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -461,25 +460,6 @@ public class SearchResults implements DocumentListener {
|
||||
return visibleArea.contains(point);
|
||||
}
|
||||
|
||||
@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();
|
||||
@@ -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();
|
||||
else {
|
||||
myCursor = null;
|
||||
}
|
||||
notifyCursorMoved();
|
||||
}
|
||||
if (next == null) {
|
||||
if (processFromTheBeginning) {
|
||||
if (hasMatches()) {
|
||||
next = getOccurrences().get(getOccurrences().size()-1);
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
+34
-19
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
package com.intellij.openapi.editor.actions;
|
||||
|
||||
import com.intellij.find.FindManager;
|
||||
import com.intellij.find.FindModel;
|
||||
import com.intellij.find.FindResult;
|
||||
import com.intellij.find.*;
|
||||
import com.intellij.find.editorHeaderActions.EditorHeaderAction;
|
||||
import com.intellij.find.editorHeaderActions.SelectAllAction;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Caret;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
@@ -27,6 +27,8 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public class SelectAllOccurrencesAction extends EditorAction {
|
||||
protected SelectAllOccurrencesAction() {
|
||||
super(new Handler());
|
||||
@@ -39,7 +41,9 @@ public class SelectAllOccurrencesAction extends EditorAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doExecute(Editor editor, @Nullable Caret c, DataContext dataContext) {
|
||||
public void doExecute(final Editor editor, @Nullable Caret c, DataContext dataContext) {
|
||||
if (executeEquivalentFindPanelAction(editor, dataContext)) return;
|
||||
|
||||
Caret caret = c == null ? editor.getCaretModel().getPrimaryCaret() : c;
|
||||
|
||||
boolean wholeWordsSearch = false;
|
||||
@@ -58,25 +62,36 @@ public class SelectAllOccurrencesAction extends EditorAction {
|
||||
}
|
||||
|
||||
int caretShiftFromSelectionStart = caret.getOffset() - caret.getSelectionStart();
|
||||
FindManager findManager = FindManager.getInstance(project);
|
||||
final FindManager findManager = FindManager.getInstance(project);
|
||||
|
||||
FindModel model = new FindModel();
|
||||
model.setStringToFind(selectedText);
|
||||
model.setCaseSensitive(true);
|
||||
model.setWholeWordsOnly(wholeWordsSearch);
|
||||
final FindModel model = getFindModel(selectedText, wholeWordsSearch);
|
||||
|
||||
int searchStartOffset = 0;
|
||||
FindResult findResult = findManager.findString(editor.getDocument().getCharsSequence(), searchStartOffset, model);
|
||||
while (findResult.isStringFound()) {
|
||||
int newCaretOffset = caretShiftFromSelectionStart + findResult.getStartOffset();
|
||||
EditorActionUtil.makePositionVisible(editor, newCaretOffset);
|
||||
Caret newCaret = editor.getCaretModel().addCaret(editor.offsetToVisualPosition(newCaretOffset));
|
||||
if (newCaret != null) {
|
||||
setSelection(editor, newCaret, findResult);
|
||||
FindUtil.selectSearchResultsInEditor(editor, new Iterator<FindResult>() {
|
||||
FindResult findResult = findManager.findString(editor.getDocument().getCharsSequence(), 0, model);
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return findResult.isStringFound();
|
||||
}
|
||||
findResult = findManager.findString(editor.getDocument().getCharsSequence(), findResult.getEndOffset(), model);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FindResult next() {
|
||||
FindResult result = findResult;
|
||||
findResult = findManager.findString(editor.getDocument().getCharsSequence(), findResult.getEndOffset(), model);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}, caretShiftFromSelectionStart);
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EditorHeaderAction getEquivalentFindPanelAction(EditorSearchComponent searchComponent) {
|
||||
return new SelectAllAction(searchComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-14
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
package com.intellij.openapi.editor.actions;
|
||||
|
||||
import com.intellij.find.FindManager;
|
||||
import com.intellij.find.FindModel;
|
||||
import com.intellij.find.FindResult;
|
||||
import com.intellij.find.*;
|
||||
import com.intellij.find.editorHeaderActions.AddOccurrenceAction;
|
||||
import com.intellij.find.editorHeaderActions.EditorHeaderAction;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Caret;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
@@ -40,6 +40,8 @@ public class SelectNextOccurrenceAction extends EditorAction {
|
||||
|
||||
@Override
|
||||
public void doExecute(Editor editor, @Nullable Caret c, DataContext dataContext) {
|
||||
if (executeEquivalentFindPanelAction(editor, dataContext)) return;
|
||||
|
||||
Caret caret = c == null ? editor.getCaretModel().getPrimaryCaret() : c;
|
||||
TextRange wordSelectionRange = getSelectionRange(editor, caret);
|
||||
boolean notFoundPreviously = getAndResetNotFoundStatus(editor);
|
||||
@@ -52,10 +54,7 @@ public class SelectNextOccurrenceAction extends EditorAction {
|
||||
}
|
||||
FindManager findManager = FindManager.getInstance(project);
|
||||
|
||||
FindModel model = new FindModel();
|
||||
model.setStringToFind(selectedText);
|
||||
model.setCaseSensitive(true);
|
||||
model.setWholeWordsOnly(wholeWordSearch);
|
||||
FindModel model = getFindModel(selectedText, wholeWordSearch);
|
||||
|
||||
findManager.setFindWasPerformed();
|
||||
findManager.setFindNextModel(model);
|
||||
@@ -63,18 +62,13 @@ public class SelectNextOccurrenceAction extends EditorAction {
|
||||
int searchStartOffset = notFoundPreviously ? 0 : caret.getSelectionEnd();
|
||||
FindResult findResult = findManager.findString(editor.getDocument().getCharsSequence(), searchStartOffset, model);
|
||||
if (findResult.isStringFound()) {
|
||||
int newCaretOffset = caret.getOffset() - caret.getSelectionStart() + findResult.getStartOffset();
|
||||
EditorActionUtil.makePositionVisible(editor, newCaretOffset);
|
||||
Caret newCaret = editor.getCaretModel().addCaret(editor.offsetToVisualPosition(newCaretOffset));
|
||||
if (newCaret == null) {
|
||||
boolean caretAdded = FindUtil.selectSearchResultInEditor(editor, findResult, caret.getOffset() - caret.getSelectionStart());
|
||||
if (!caretAdded) {
|
||||
// this means that the found occurence is already selected
|
||||
if (notFoundPreviously) {
|
||||
setNotFoundStatus(editor); // to make sure we won't show hint anymore if there are no more occurrences
|
||||
}
|
||||
}
|
||||
else {
|
||||
setSelection(editor, newCaret, findResult);
|
||||
}
|
||||
}
|
||||
else {
|
||||
setNotFoundStatus(editor);
|
||||
@@ -90,5 +84,10 @@ public class SelectNextOccurrenceAction extends EditorAction {
|
||||
}
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EditorHeaderAction getEquivalentFindPanelAction(EditorSearchComponent searchComponent) {
|
||||
return new AddOccurrenceAction(searchComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+33
-1
@@ -19,8 +19,11 @@ import com.intellij.codeInsight.editorActions.SelectWordUtil;
|
||||
import com.intellij.codeInsight.hint.HintManager;
|
||||
import com.intellij.codeInsight.hint.HintManagerImpl;
|
||||
import com.intellij.codeInsight.hint.HintUtil;
|
||||
import com.intellij.find.EditorSearchComponent;
|
||||
import com.intellij.find.FindBundle;
|
||||
import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.find.FindModel;
|
||||
import com.intellij.find.editorHeaderActions.EditorHeaderAction;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.editor.Caret;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorLastActionTracker;
|
||||
@@ -96,4 +99,33 @@ abstract public class SelectOccurrencesActionHandler extends EditorActionHandler
|
||||
String lastActionId = EditorLastActionTracker.getInstance().getLastActionId();
|
||||
return SELECT_ACTIONS.contains(lastActionId);
|
||||
}
|
||||
|
||||
protected static FindModel getFindModel(String text, boolean wholeWords) {
|
||||
FindModel model = new FindModel();
|
||||
model.setStringToFind(text);
|
||||
model.setCaseSensitive(true);
|
||||
model.setWholeWordsOnly(wholeWords);
|
||||
return model;
|
||||
}
|
||||
|
||||
protected boolean executeEquivalentFindPanelAction(Editor editor, DataContext context) {
|
||||
if (editor.getHeaderComponent() instanceof EditorSearchComponent) {
|
||||
EditorSearchComponent searchComponent = (EditorSearchComponent)editor.getHeaderComponent();
|
||||
EditorHeaderAction action = getEquivalentFindPanelAction(searchComponent);
|
||||
if (action != null) {
|
||||
Presentation presentation = new Presentation();
|
||||
AnActionEvent event = new AnActionEvent(null, context, ActionPlaces.MAIN_MENU, presentation, ActionManager.getInstance(), 0);
|
||||
action.update(event);
|
||||
if (presentation.isEnabled()) {
|
||||
action.actionPerformed(event);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected EditorHeaderAction getEquivalentFindPanelAction(EditorSearchComponent searchComponent) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package com.intellij.openapi.editor.actions;
|
||||
|
||||
import com.intellij.find.EditorSearchComponent;
|
||||
import com.intellij.find.editorHeaderActions.EditorHeaderAction;
|
||||
import com.intellij.find.editorHeaderActions.RemoveOccurrenceAction;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Caret;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
@@ -35,6 +38,8 @@ public class UnselectPreviousOccurrenceAction extends EditorAction {
|
||||
|
||||
@Override
|
||||
public void doExecute(Editor editor, @Nullable Caret caret, DataContext dataContext) {
|
||||
if (executeEquivalentFindPanelAction(editor, dataContext)) return;
|
||||
|
||||
if (editor.getCaretModel().getCaretCount() > 1) {
|
||||
editor.getCaretModel().removeCaret(editor.getCaretModel().getPrimaryCaret());
|
||||
}
|
||||
@@ -44,5 +49,10 @@ public class UnselectPreviousOccurrenceAction extends EditorAction {
|
||||
getAndResetNotFoundStatus(editor);
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EditorHeaderAction getEquivalentFindPanelAction(EditorSearchComponent searchComponent) {
|
||||
return new RemoveOccurrenceAction(searchComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ action.EditorMoveDownAndScrollWithSelection.text=Move Down and Scroll with Selec
|
||||
action.EditorAddOrRemoveCaret.text=Add or Remove Caret
|
||||
action.EditorCloneCaretBelow.text=Clone Caret Below
|
||||
action.EditorCloneCaretAbove.text=Clone Caret Above
|
||||
action.SelectNextOccurrence.text=Select Next Occurrence
|
||||
action.SelectNextOccurrence.text=Add Selection for Next Occurrence
|
||||
action.SelectAllOccurrences.text=Select All Occurrences
|
||||
action.UnselectPreviousOccurrence.text=Unselect Occurrence
|
||||
action.EditorToggleStickySelection.text=Toggle Sticky Selection
|
||||
|
||||
Reference in New Issue
Block a user