diff --git a/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/LastActionTracker.java b/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/LastActionTracker.java
new file mode 100644
index 000000000000..b3f18c926e4c
--- /dev/null
+++ b/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/LastActionTracker.java
@@ -0,0 +1,38 @@
+/*
+ * 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.openapi.actionSystem;
+
+import com.intellij.openapi.application.ApplicationManager;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * This component provides the notion of last action. Its purpose is to be able to determine whether some action was performed right after
+ * another specific action.
+ *
+ * It's supposed to be used from EDT only.
+ */
+public abstract class LastActionTracker {
+ public static LastActionTracker getInstance() {
+ return ApplicationManager.getApplication().getComponent(LastActionTracker.class);
+ }
+
+ /**
+ * Returns the id of the previously invoked action or null, if no history exists yet, or last user activity was of
+ * non-action type, like mouse clicking in editor or text typing.
+ */
+ @Nullable
+ public abstract String getLastActionId();
+}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/SelectWordUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/SelectWordUtil.java
index 07923f11d5c5..8253873421fe 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/SelectWordUtil.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/SelectWordUtil.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.
@@ -65,7 +65,7 @@ public class SelectWordUtil {
return SELECTIONERS;
}
- private static final CharCondition JAVA_IDENTIFIER_PART_CONDITION = new CharCondition() {
+ public static final CharCondition JAVA_IDENTIFIER_PART_CONDITION = new CharCondition() {
@Override
public boolean value(char ch) {
return Character.isJavaIdentifierPart(ch);
diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java
new file mode 100644
index 000000000000..d8870484c380
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java
@@ -0,0 +1,156 @@
+/*
+ * 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.openapi.editor.actions;
+
+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.FindBundle;
+import com.intellij.find.FindManager;
+import com.intellij.find.FindModel;
+import com.intellij.find.FindResult;
+import com.intellij.openapi.actionSystem.LastActionTracker;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.IdeActions;
+import com.intellij.openapi.editor.Caret;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.ScrollType;
+import com.intellij.openapi.editor.actionSystem.EditorAction;
+import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.ui.LightweightHint;
+import org.jetbrains.annotations.Nullable;
+
+public class SelectNextOccurrenceAction extends EditorAction {
+ private static final Key NOT_FOUND = Key.create("select.next.occurence.not.found");
+ private static final Key WHOLE_WORDS = Key.create("select.next.occurence.whole.words");
+
+ protected SelectNextOccurrenceAction() {
+ super(new Handler());
+ }
+
+ private static class Handler extends EditorActionHandler {
+ @Override
+ public boolean isEnabled(Editor editor, DataContext dataContext) {
+ return super.isEnabled(editor, dataContext) && editor.getProject() != null && editor.getCaretModel().supportsMultipleCarets();
+ }
+
+ @Override
+ public void execute(Editor editor, @Nullable Caret c, DataContext dataContext) {
+ Caret caret = c == null ? editor.getCaretModel().getPrimaryCaret() : c;
+ TextRange wordSelectionRange = SelectWordUtil.getWordSelectionRange(editor.getDocument().getCharsSequence(),
+ caret.getOffset(),
+ SelectWordUtil.JAVA_IDENTIFIER_PART_CONDITION);
+ boolean notFoundPreviously = getAndResetNotFoundStatus(editor);
+ Boolean wholeWordSearch = isWholeWordSearch(editor);
+ if (caret.hasSelection()) {
+ Project project = editor.getProject();
+ String selectedText = caret.getSelectedText();
+ if (project == null || selectedText == null) {
+ return;
+ }
+ FindManager findManager = FindManager.getInstance(project);
+
+ if (wholeWordSearch == null) {
+ wholeWordSearch = wordSelectionRange != null
+ && wordSelectionRange.getStartOffset() == caret.getSelectionStart()
+ && wordSelectionRange.getEndOffset() == caret.getSelectionEnd();
+ setWholeWordSearch(editor, wholeWordSearch);
+ }
+ FindModel model = new FindModel();
+ model.setStringToFind(caret.getSelectedText());
+ model.setCaseSensitive(true);
+ model.setWholeWordsOnly(wholeWordSearch);
+
+ 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) {
+ // 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);
+ showHint(editor);
+ }
+ }
+ else {
+ if (wordSelectionRange == null) {
+ return;
+ }
+ setSelection(editor, caret, wordSelectionRange);
+ setWholeWordSearch(editor, true);
+ }
+ editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+ }
+
+ private static void setSelection(Editor editor, Caret caret, TextRange selectionRange) {
+ EditorActionUtil.makePositionVisible(editor, selectionRange.getStartOffset());
+ EditorActionUtil.makePositionVisible(editor, selectionRange.getEndOffset());
+ caret.setSelection(selectionRange.getStartOffset(), selectionRange.getEndOffset());
+ }
+
+
+ private static void showHint(final Editor editor) {
+ String message = FindBundle.message("select.next.occurence.not.found.message");
+ final LightweightHint hint = new LightweightHint(HintUtil.createInformationLabel(message));
+ HintManagerImpl.getInstanceImpl().showEditorHint(hint,
+ editor,
+ HintManager.UNDER,
+ HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING,
+ 0,
+ false);
+ }
+
+ private static boolean getAndResetNotFoundStatus(Editor editor) {
+ boolean status = editor.getUserData(NOT_FOUND) != null;
+ editor.putUserData(NOT_FOUND, null);
+ return status && isRepeatedActionInvocation();
+ }
+
+ private static void setNotFoundStatus(Editor editor) {
+ editor.putUserData(NOT_FOUND, Boolean.TRUE);
+ }
+
+ private static Boolean isWholeWordSearch(Editor editor) {
+ if (!isRepeatedActionInvocation()) {
+ editor.putUserData(WHOLE_WORDS, null);
+ }
+ return editor.getUserData(WHOLE_WORDS);
+ }
+
+ private static void setWholeWordSearch(Editor editor, boolean isWholeWordSearch) {
+ editor.putUserData(WHOLE_WORDS, isWholeWordSearch);
+ }
+
+ private static boolean isRepeatedActionInvocation() {
+ String lastActionId = LastActionTracker.getInstance().getLastActionId();
+ return IdeActions.ACTION_SELECT_NEXT_OCCURENCE.equals(lastActionId) || IdeActions.ACTION_UNSELECT_LAST_OCCURENCE.equals(lastActionId);
+ }
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/UnselectLastOccurrenceAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/UnselectLastOccurrenceAction.java
new file mode 100644
index 000000000000..37b6c56a5c4a
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/UnselectLastOccurrenceAction.java
@@ -0,0 +1,48 @@
+/*
+ * 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.openapi.editor.actions;
+
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.editor.Caret;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.ScrollType;
+import com.intellij.openapi.editor.actionSystem.EditorAction;
+import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
+import org.jetbrains.annotations.Nullable;
+
+public class UnselectLastOccurrenceAction extends EditorAction {
+ protected UnselectLastOccurrenceAction() {
+ super(new Handler());
+ }
+
+ private static class Handler extends EditorActionHandler {
+ @Override
+ public boolean isEnabled(Editor editor, DataContext dataContext) {
+ return super.isEnabled(editor, dataContext) && editor.getCaretModel().supportsMultipleCarets();
+ }
+
+ @Override
+ public void execute(Editor editor, @Nullable Caret caret, DataContext dataContext) {
+ if (editor.getCaretModel().getAllCarets().size() > 1) {
+ editor.getCaretModel().removeCaret(editor.getCaretModel().getPrimaryCaret());
+ }
+ else {
+ editor.getSelectionModel().removeSelection();
+ }
+ editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+ }
+ }
+}
diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java
index 7f9e40550a6d..b515b84e8f3f 100644
--- a/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java
+++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.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.
@@ -114,6 +114,8 @@ public interface IdeActions {
@NonNls String ACTION_FIND = "Find";
@NonNls String ACTION_FIND_NEXT = "FindNext";
@NonNls String ACTION_FIND_PREVIOUS = "FindPrevious";
+ @NonNls String ACTION_SELECT_NEXT_OCCURENCE = "SelectNextOccurrence";
+ @NonNls String ACTION_UNSELECT_LAST_OCCURENCE = "UnselectLastOccurrence";
@NonNls String ACTION_COMPILE = "Compile";
@NonNls String ACTION_COMPILE_PROJECT = "CompileProject";
@NonNls String ACTION_MAKE_MODULE = "MakeModule";
diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java
index d8e4246c47ac..caecb4c31d7d 100644
--- a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.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.
@@ -587,6 +587,7 @@ public class HintManagerImpl extends HintManager implements Disposable {
@NotNull LogicalPosition pos2,
@PositionFlags short constraint,
boolean showByBalloon) {
+ if (ApplicationManager.getApplication().isUnitTestMode()) return new Point();
Point p = _getHintPosition(hint, editor, pos1, pos2, constraint, showByBalloon);
JLayeredPane layeredPane = editor.getComponent().getRootPane().getLayeredPane();
Dimension hintSize = hint.getComponent().getPreferredSize();
diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/LastActionTrackerImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/LastActionTrackerImpl.java
new file mode 100644
index 000000000000..7f003654d1f2
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/LastActionTrackerImpl.java
@@ -0,0 +1,116 @@
+/*
+ * 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.openapi.actionSystem.impl;
+
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.actionSystem.ex.AnActionListener;
+import com.intellij.openapi.components.ApplicationComponent;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.editor.event.EditorEventMulticaster;
+import com.intellij.openapi.editor.event.EditorMouseEvent;
+import com.intellij.openapi.editor.event.EditorMouseListener;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class LastActionTrackerImpl extends LastActionTracker implements ApplicationComponent, AnActionListener, EditorMouseListener {
+ private final ActionManager myActionManager;
+ private final EditorEventMulticaster myEditorEventMulticaster;
+
+ private String myLastActionId;
+ private Editor myLastEditor;
+
+ LastActionTrackerImpl(ActionManager actionManager, EditorFactory editorFactory) {
+ myActionManager = actionManager;
+ myEditorEventMulticaster = editorFactory.getEventMulticaster();
+ }
+
+ @Override
+ public void initComponent() {
+ myActionManager.addAnActionListener(this);
+ myEditorEventMulticaster.addEditorMouseListener(this);
+ }
+
+ @Override
+ public void disposeComponent() {
+ myEditorEventMulticaster.removeEditorMouseListener(this);
+ myActionManager.removeAnActionListener(this);
+ }
+
+ @NotNull
+ @Override
+ public String getComponentName() {
+ return "LastActionTracker";
+ }
+
+ @Override
+ @Nullable
+ public String getLastActionId() {
+ return myLastActionId;
+ }
+
+ @Override
+ public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
+ if (CommonDataKeys.EDITOR.getData(dataContext) != myLastEditor) {
+ resetLastAction();
+ }
+ }
+
+ @Override
+ public void afterActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
+ myLastActionId = getActionId(action);
+ myLastEditor = CommonDataKeys.EDITOR.getData(dataContext);
+ }
+
+ @Override
+ public void beforeEditorTyping(char c, DataContext dataContext) {
+ resetLastAction();
+ }
+
+ @Override
+ public void mousePressed(EditorMouseEvent e) {
+ resetLastAction();
+ }
+
+ @Override
+ public void mouseClicked(EditorMouseEvent e) {
+ resetLastAction();
+ }
+
+ @Override
+ public void mouseReleased(EditorMouseEvent e) {
+ resetLastAction();
+ }
+
+ @Override
+ public void mouseEntered(EditorMouseEvent e) {
+
+ }
+
+ @Override
+ public void mouseExited(EditorMouseEvent e) {
+
+ }
+
+ private String getActionId(AnAction action) {
+ return action instanceof ActionStub ? ((ActionStub)action).getId() : myActionManager.getId(action);
+ }
+
+ private void resetLastAction() {
+ myLastActionId = null;
+ myLastEditor = null;
+ }
+}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java
index e86bc16cd437..e0abbf65d3a4 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java
@@ -784,4 +784,21 @@ public class EditorActionUtil {
public static void moveCaretToLineStartIgnoringSoftWraps(@NotNull Editor editor) {
editor.getCaretModel().moveToLogicalPosition(EditorUtil.calcCaretLineRange(editor).first);
}
+
+ /**
+ * This method will make required expansions of collapsed region to make given offset 'visible'.
+ */
+ public static void makePositionVisible(@NotNull final Editor editor, final int offset) {
+ FoldingModel foldingModel = editor.getFoldingModel();
+ FoldRegion collapsedRegionAtOffset;
+ while ((collapsedRegionAtOffset = foldingModel.getCollapsedRegionAtOffset(offset)) != null) {
+ final FoldRegion region = collapsedRegionAtOffset;
+ foldingModel.runBatchFoldingOperation(new Runnable() {
+ @Override
+ public void run() {
+ region.setExpanded(true);
+ }
+ });
+ }
+ }
}
diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties
index ac04bd213af6..fa38ddeae330 100644
--- a/platform/platform-resources-en/src/messages/ActionsBundle.properties
+++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties
@@ -107,6 +107,8 @@ action.EditorMoveUpAndScrollWithSelection.text=Move Up and Scroll with Selection
action.EditorMoveDownAndScrollWithSelection.text=Move Down and Scroll with Selection
action.EditorCloneCaretBelow.text=Clone Caret Below
action.EditorCloneCaretAbove.text=Clone Caret Above
+action.SelectNextOccurence.text=Select Next Occurence
+action.UnselectLastOccurence.text=Unselect Last Occurence
action.EditorToggleStickySelection.text=Toggle Sticky Selection
action.EditorSwapSelectionBoundaries.text=Swap selection boundaries
action.EditorLineStart.text=Move Caret to Line Start
diff --git a/platform/platform-resources-en/src/messages/FindBundle.properties b/platform/platform-resources-en/src/messages/FindBundle.properties
index 20ec7830472d..26959ba14d4b 100644
--- a/platform/platform-resources-en/src/messages/FindBundle.properties
+++ b/platform/platform-resources-en/src/messages/FindBundle.properties
@@ -7,6 +7,7 @@ find.search.again.from.top.hotkey.message={0}, press {1} to search from the top
find.search.again.from.top.action.message={0}, perform \"Find Next\" again to search from the top
find.search.again.from.bottom.hotkey.message={0}, press {1} to search from the bottom
find.search.again.from.bottom.action.message={0}, perform \"Find Previous\" again to search from the bottom
+select.next.occurence.not.found.message=Not found, try again to search from top
find.no.usages.at.cursor.error=Cannot search for usages. \nPosition to an element to find usages for, and try again.
find.what.group=Find
diff --git a/platform/platform-resources/src/componentSets/UICore.xml b/platform/platform-resources/src/componentSets/UICore.xml
index 8d7d5d63e055..042b053f68d4 100644
--- a/platform/platform-resources/src/componentSets/UICore.xml
+++ b/platform/platform-resources/src/componentSets/UICore.xml
@@ -21,6 +21,10 @@
com.intellij.openapi.actionSystem.ActionManager
com.intellij.openapi.actionSystem.impl.ActionManagerImpl
+
+ com.intellij.openapi.actionSystem.LastActionTracker
+ com.intellij.openapi.actionSystem.impl.LastActionTrackerImpl
+
com.intellij.openapi.keymap.KeymapManager
com.intellij.openapi.keymap.impl.KeymapManagerImpl
diff --git a/platform/platform-resources/src/idea/Keymap_Default.xml b/platform/platform-resources/src/idea/Keymap_Default.xml
index 2e91d14985ab..2abce4dfd297 100644
--- a/platform/platform-resources/src/idea/Keymap_Default.xml
+++ b/platform/platform-resources/src/idea/Keymap_Default.xml
@@ -112,6 +112,12 @@
+
+
+
+
+
+
diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml
index 3fe320b77ffc..9902476aab7f 100644
--- a/platform/platform-resources/src/idea/PlatformActions.xml
+++ b/platform/platform-resources/src/idea/PlatformActions.xml
@@ -225,6 +225,8 @@
+
+
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/SelectUnselectOccurrenceActionsTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/SelectUnselectOccurrenceActionsTest.java
new file mode 100644
index 000000000000..58d36578ee37
--- /dev/null
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/SelectUnselectOccurrenceActionsTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.openapi.editor.actions;
+
+import com.intellij.codeInsight.hint.EditorHintListener;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.FoldRegion;
+import com.intellij.openapi.editor.FoldingModel;
+import com.intellij.openapi.fileTypes.FileTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.testFramework.EditorTestUtil;
+import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
+import com.intellij.ui.LightweightHint;
+
+public class SelectUnselectOccurrenceActionsTest extends LightPlatformCodeInsightFixtureTestCase {
+ private int hintCount;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ EditorTestUtil.enableMultipleCarets();
+ EditorHintListener listener = new EditorHintListener() {
+ @Override
+ public void hintShown(Project project, LightweightHint hint, int flags) {
+ hintCount++;
+ }
+ };
+ ApplicationManager.getApplication().getMessageBus().connect(myTestRootDisposable).subscribe(EditorHintListener.TOPIC, listener);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ EditorTestUtil.disableMultipleCarets();
+ super.tearDown();
+ }
+
+ public void testNoInitialSelection() throws Exception {
+ init("some text\n" +
+ "some texts\n" +
+ "another text here"
+ );
+ executeAction();
+ checkResult("some text\n" +
+ "some texts\n" +
+ "another text here");
+ assertEquals(0, hintCount);
+ }
+
+ public void testInitialWholeWordSelection() throws Exception {
+ init("some text\n" +
+ "some texts\n" +
+ "another text here");
+ executeAction();
+ checkResult("some text\n" +
+ "some texts\n" +
+ "another text here");
+ assertEquals(0, hintCount);
+ }
+
+ public void testShowingHint() throws Exception {
+ init("some text\n" +
+ "some texts\n" +
+ "another text here");
+ executeAction();
+ assertEquals(1, hintCount);
+ checkResult("some text\n" +
+ "some texts\n" +
+ "another text here");
+ executeAction();
+ assertEquals(1, hintCount);
+ checkResult("some text\n" +
+ "some texts\n" +
+ "another text here");
+ }
+
+ public void testRevert() throws Exception {
+ init("some text\n" +
+ "some texts\n" +
+ "another text here");
+ executeReverseAction();
+ checkResult("some text\n" +
+ "some texts\n" +
+ "another text here");
+ assertEquals(0, hintCount);
+ }
+
+ public void testRevertSingleSelection() throws Exception {
+ init("some text\n" +
+ "some texts\n" +
+ "another text here");
+ executeReverseAction();
+ checkResult("some text\n" +
+ "some texts\n" +
+ "another text here");
+ assertEquals(0, hintCount);
+ }
+
+ public void testSelectAfterHint() throws Exception {
+ init("some text\n" +
+ "some texts\n" +
+ "another text here");
+ executeAction();
+ checkResult("some text\n" +
+ "some texts\n" +
+ "another text here");
+ assertEquals(1, hintCount);
+ executeAction();
+ checkResult("some text\n" +
+ "some texts\n" +
+ "another text here");
+ assertEquals(1, hintCount);
+ }
+
+ public void testInitialNonWholeWordSelection() throws Exception {
+ init("some text\n" +
+ "some texts\n" +
+ "another text here");
+ executeAction();
+ checkResult("some text\n" +
+ "some texts\n" +
+ "another text here");
+ executeAction();
+ checkResult("some text\n" +
+ "some texts\n" +
+ "another text here");
+ assertEquals(0, hintCount);
+ }
+
+ public void testWholeWordinessIsRememberedAtStart() throws Exception {
+ init("some texts\n" +
+ "another text\n" +
+ "some other texts");
+ executeAction();
+ checkResult("some texts\n" +
+ "another text\n" +
+ "some other texts");
+ executeAction();
+ checkResult("some texts\n" +
+ "another text\n" +
+ "some other texts");
+ assertEquals(0, hintCount);
+ }
+
+ public void testOccurrenceInCollapsedRegion() throws Exception {
+ init("normal line\n" +
+ "collapsed line");
+ final FoldingModel foldingModel = myFixture.getEditor().getFoldingModel();
+ final Document document = myFixture.getEditor().getDocument();
+ foldingModel.runBatchFoldingOperation(new Runnable() {
+ @Override
+ public void run() {
+ FoldRegion foldRegion = foldingModel.addFoldRegion(document.getLineStartOffset(1), document.getLineEndOffset(1), "...");
+ assertNotNull(foldRegion);
+ foldRegion.setExpanded(false);
+ }
+ });
+ executeAction();
+ checkResult("normal line\n" +
+ "collapsed line");
+ FoldRegion[] foldRegions = foldingModel.getAllFoldRegions();
+ assertEquals(1, foldRegions.length);
+ assertTrue(foldRegions[0].isExpanded());
+ }
+
+ private void init(String text) {
+ myFixture.configureByText(FileTypes.PLAIN_TEXT, text);
+ }
+
+ private void checkResult(String text) {
+ myFixture.checkResult(text);
+ }
+
+ private void executeAction() {
+ myFixture.performEditorAction("SelectNextOccurrence");
+ }
+
+ private void executeReverseAction() {
+ myFixture.performEditorAction("UnselectLastOccurrence");
+ }
+}