IDEA-121925 Allow to do multiple selections w/wout multiple carets per selection

This commit is contained in:
Dmitry Batrak
2014-12-22 11:46:59 +03:00
parent 6ebb2f8fbe
commit 3664362a42
12 changed files with 282 additions and 156 deletions
@@ -58,6 +58,7 @@ public interface IdeActions {
@NonNls String ACTION_EDITOR_USE_SOFT_WRAPS = "EditorToggleUseSoftWraps";
@NonNls String ACTION_EDITOR_ADD_OR_REMOVE_CARET= "EditorAddOrRemoveCaret";
@NonNls String ACTION_EDITOR_CREATE_RECTANGULAR_SELECTION= "EditorCreateRectangularSelection";
@NonNls String ACTION_EDITOR_ADD_RECTANGULAR_SELECTION_ON_MOUSE_DRAG= "EditorAddRectangularSelectionOnMouseDrag";
@NonNls String ACTION_EDITOR_CLONE_CARET_BELOW= "EditorCloneCaretBelow";
@NonNls String ACTION_EDITOR_CLONE_CARET_ABOVE= "EditorCloneCaretAbove";
@NonNls String ACTION_EDITOR_TOGGLE_STICKY_SELECTION= "EditorToggleStickySelection";
@@ -32,6 +32,8 @@ import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class EditorModificationUtil {
@@ -484,4 +486,47 @@ public class EditorModificationUtil {
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
}
}
@NotNull
public static List<CaretState> calcBlockSelectionState(@NotNull Editor editor,
@NotNull LogicalPosition blockStart, @NotNull LogicalPosition blockEnd) {
int startLine = Math.max(Math.min(blockStart.line, editor.getDocument().getLineCount() - 1), 0);
int endLine = Math.max(Math.min(blockEnd.line, editor.getDocument().getLineCount() - 1), 0);
int step = endLine < startLine ? -1 : 1;
int count = 1 + Math.abs(endLine - startLine);
List<CaretState> caretStates = new LinkedList<CaretState>();
boolean hasSelection = false;
for (int line = startLine, i = 0; i < count; i++, line += step) {
int startColumn = blockStart.column;
int endColumn = blockEnd.column;
int lineEndOffset = editor.getDocument().getLineEndOffset(line);
LogicalPosition lineEndPosition = editor.offsetToLogicalPosition(lineEndOffset);
int lineWidth = lineEndPosition.column;
if (startColumn > lineWidth && endColumn > lineWidth && !editor.isColumnMode()) {
LogicalPosition caretPos = new LogicalPosition(line, Math.min(startColumn, endColumn));
caretStates.add(new CaretState(caretPos,
lineEndPosition,
lineEndPosition));
}
else {
LogicalPosition startPos = new LogicalPosition(line, editor.isColumnMode() ? startColumn : Math.min(startColumn, lineWidth));
LogicalPosition endPos = new LogicalPosition(line, editor.isColumnMode() ? endColumn : Math.min(endColumn, lineWidth));
int startOffset = editor.logicalPositionToOffset(startPos);
int endOffset = editor.logicalPositionToOffset(endPos);
caretStates.add(new CaretState(endPos, startPos, endPos));
hasSelection |= startOffset != endOffset;
}
}
if (hasSelection && !editor.isColumnMode()) { // filtering out lines without selection
Iterator<CaretState> caretStateIterator = caretStates.iterator();
while(caretStateIterator.hasNext()) {
CaretState state = caretStateIterator.next();
//noinspection ConstantConditions
if (state.getSelectionStart().equals(state.getSelectionEnd())) {
caretStateIterator.remove();
}
}
}
return caretStates;
}
}
@@ -387,4 +387,39 @@ public class KeymapUtil {
}
return false;
}
/**
* Checks whether mouse event's button and modifiers match a shortcut configured in active keymap for given action id.
* Only shortcuts having click count of 1 can be matched, mouse event's click count is ignored.
*/
public static boolean isMouseActionEvent(@NotNull MouseEvent e, @NotNull String actionId) {
KeymapManager keymapManager = KeymapManager.getInstance();
if (keymapManager == null) {
return false;
}
Keymap keymap = keymapManager.getActiveKeymap();
if (keymap == null) {
return false;
}
int button = e.getButton();
int modifiers = e.getModifiersEx();
if (button == MouseEvent.NOBUTTON && e.getID() == MouseEvent.MOUSE_DRAGGED) {
// mouse drag events don't have button field set due to some reason
if ((modifiers & InputEvent.BUTTON1_DOWN_MASK) != 0) {
button = MouseEvent.BUTTON1;
} else if ((modifiers & InputEvent.BUTTON2_DOWN_MASK) != 0) {
button = MouseEvent.BUTTON2;
}
}
String[] actionIds = keymap.getActionIds(new MouseShortcut(button, modifiers, 1));
if (actionIds == null) {
return false;
}
for (String id : actionIds) {
if (actionId.equals(id)) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,31 @@
/*
* 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.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
public class AddRectangularSelectionOnMouseDragAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
// actual logic is implemented in EditorImpl
}
@Override
public void update(AnActionEvent e) {
e.getPresentation().setEnabled(false);
}
}
@@ -54,8 +54,7 @@ import com.intellij.openapi.editor.markup.*;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory;
import com.intellij.openapi.fileEditor.impl.EditorsSplitters;
import com.intellij.openapi.keymap.Keymap;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Queryable;
@@ -288,9 +287,11 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
private final EditorSizeAdjustmentStrategy mySizeAdjustmentStrategy = new EditorSizeAdjustmentStrategy();
private final Disposable myDisposable = Disposer.newDisposable();
private List<CaretState> myCaretStateBeforeLastPress;
private LogicalPosition myLastMousePressedLocation;
private VisualPosition myTargetMultiSelectionPosition;
private boolean myMultiSelectionInProgress;
private boolean myRectangularSelectionInProgress;
private boolean myLastPressCreatedCaret;
// Set when the selection (normal or block one) initiated by mouse drag becomes noticeable (at least one character is selected).
// Reset on mouse press event.
@@ -4177,6 +4178,14 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
myDragOnGutterSelectionStartLine = - 1;
}
boolean columnSelectionDragEvent = isColumnSelectionDragEvent(e);
boolean toggleCaretEvent = isToggleCaretEvent(e);
boolean addRectangularSelectionEvent = isAddRectangularSelectionEvent(e);
boolean columnSelectionDrag = isColumnMode() && !myLastPressCreatedCaret || columnSelectionDragEvent;
if (!columnSelectionDragEvent && toggleCaretEvent && !myLastPressCreatedCaret) {
return; // ignoring drag after removing a caret
}
Rectangle visibleArea = getScrollingModel().getVisibleArea();
int x = e.getX();
@@ -4214,10 +4223,11 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
VisualPosition oldVisLeadSelectionStart = leadCaret.getLeadSelectionPosition();
int oldCaretOffset = getCaretModel().getOffset();
LogicalPosition oldLogicalCaret = getCaretModel().getLogicalPosition();
boolean multiCaretSelection = myCaretModel.supportsMultipleCarets() && (isColumnMode() || e.isAltDown());
boolean multiCaretSelection = myCaretModel.supportsMultipleCarets() && (columnSelectionDrag || toggleCaretEvent);
LogicalPosition newLogicalCaret = getLogicalPositionForScreenPos(x, y, !multiCaretSelection);
if (multiCaretSelection) {
myMultiSelectionInProgress = true;
myRectangularSelectionInProgress = columnSelectionDrag || addRectangularSelectionEvent;
myTargetMultiSelectionPosition = xyToVisualPosition(new Point(Math.max(x, 0), Math.max(y, 0)));
getScrollingModel().scrollTo(newLogicalCaret, ScrollType.RELATIVE);
}
@@ -4235,15 +4245,18 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
selectionModel.setSelection(oldSelectionStart, newCaretOffset);
}
else {
if (isColumnMode() || e.isAltDown()) {
if (columnSelectionDrag || toggleCaretEvent) {
if (myCaretModel.supportsMultipleCarets()) {
if (myLastMousePressedLocation != null && (myCurrentDragIsSubstantial || !newLogicalCaret.equals(myLastMousePressedLocation))) {
setBlockSelectionAndBlockActions(e, myLastMousePressedLocation, newLogicalCaret);
createSelectionTill(newLogicalCaret);
blockActionsIfNeeded(e, myLastMousePressedLocation, newLogicalCaret);
}
} else {
final LogicalPosition blockStart = selectionModel.hasBlockSelection() ? selectionModel.getBlockStart() : oldLogicalCaret;
if (blockStart != null) {
setBlockSelectionAndBlockActions(e, blockStart, getCaretModel().getLogicalPosition());
LogicalPosition endPosition = getCaretModel().getLogicalPosition();
mySelectionModel.setBlockSelection(blockStart, endPosition);
blockActionsIfNeeded(e, blockStart, endPosition);
}
}
}
@@ -4332,6 +4345,39 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
}
private void createSelectionTill(@NotNull LogicalPosition targetPosition) {
List<CaretState> caretStates = new ArrayList<CaretState>(myCaretStateBeforeLastPress);
if (myRectangularSelectionInProgress) {
caretStates.addAll(EditorModificationUtil.calcBlockSelectionState(this, myLastMousePressedLocation, targetPosition));
}
else {
LogicalPosition selectionStart = myLastMousePressedLocation;
LogicalPosition selectionEnd = targetPosition;
if (getMouseSelectionState() != MOUSE_SELECTION_STATE_NONE) {
int newCaretOffset = logicalPositionToOffset(targetPosition);
if (newCaretOffset < mySavedSelectionStart) {
selectionStart = offsetToLogicalPosition(mySavedSelectionEnd);
if (getMouseSelectionState() == MOUSE_SELECTION_STATE_LINE_SELECTED) {
targetPosition = selectionEnd = visualToLogicalPosition(new VisualPosition(offsetToVisualLine(newCaretOffset), 0));
}
}
else {
selectionStart = offsetToLogicalPosition(mySavedSelectionStart);
int selectionEndOffset = Math.max(newCaretOffset, mySavedSelectionEnd);
if (getMouseSelectionState() == MOUSE_SELECTION_STATE_WORD_SELECTED) {
targetPosition = selectionEnd = offsetToLogicalPosition(selectionEndOffset);
}
else if (getMouseSelectionState() == MOUSE_SELECTION_STATE_LINE_SELECTED) {
targetPosition = selectionEnd = visualToLogicalPosition(new VisualPosition(offsetToVisualLine(selectionEndOffset) + 1, 0));
}
}
cancelAutoResetForMouseSelectionState();
}
caretStates.add(new CaretState(targetPosition, selectionStart, selectionEnd));
}
myCaretModel.setCaretsAndSelections(caretStates);
}
private Caret getLeadCaret() {
List<Caret> allCarets = myCaretModel.getAllCarets();
Caret firstCaret = allCarets.get(0);
@@ -4357,8 +4403,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
}
private void setBlockSelectionAndBlockActions(@NotNull MouseEvent mouseDragEvent, @NotNull LogicalPosition startPosition, @NotNull LogicalPosition endPosition) {
mySelectionModel.setBlockSelection(startPosition, endPosition);
private void blockActionsIfNeeded(@NotNull MouseEvent mouseDragEvent, @NotNull LogicalPosition startPosition, @NotNull LogicalPosition endPosition) {
if (myCurrentDragIsSubstantial || !startPosition.equals(endPosition)) {
onSubstantialDrag(mouseDragEvent);
}
@@ -4801,7 +4846,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
myTargetMultiSelectionPosition = pos;
LogicalPosition newLogicalPosition = visualToLogicalPosition(pos);
getScrollingModel().scrollTo(newLogicalPosition, ScrollType.RELATIVE);
mySelectionModel.setBlockSelection(myLastMousePressedLocation, newLogicalPosition);
createSelectionTill(newLogicalPosition);
}
else if (mySelectionModel.hasBlockSelection()) {
mySelectionModel.setBlockSelection(mySelectionModel.getBlockStart(), getCaretModel().getLogicalPosition());
@@ -5521,6 +5566,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
private void runMousePressedCommand(@NotNull final MouseEvent e) {
myLastMousePressedLocation = xyToLogicalPosition(e.getPoint());
myCaretStateBeforeLastPress = isToggleCaretEvent(e) ? myCaretModel.getCaretsAndSelections() : Collections.<CaretState>emptyList();
myCurrentDragIsSubstantial = false;
final int clickOffset = logicalPositionToOffset(myLastMousePressedLocation);
@@ -5831,33 +5877,20 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
}
private static boolean isColumnSelectionDragEvent(@NotNull MouseEvent e) {
return e.isAltDown() && !e.isShiftDown() && !e.isControlDown() && !e.isMetaDown();
}
private static boolean isToggleCaretEvent(@NotNull MouseEvent e) {
return isMouseActionEvent(e, IdeActions.ACTION_EDITOR_ADD_OR_REMOVE_CARET);
return KeymapUtil.isMouseActionEvent(e, IdeActions.ACTION_EDITOR_ADD_OR_REMOVE_CARET) || isAddRectangularSelectionEvent(e);
}
private static boolean isAddRectangularSelectionEvent(@NotNull MouseEvent e) {
return KeymapUtil.isMouseActionEvent(e, IdeActions.ACTION_EDITOR_ADD_RECTANGULAR_SELECTION_ON_MOUSE_DRAG);
}
private static boolean isCreateRectangularSelectionEvent(@NotNull MouseEvent e) {
return isMouseActionEvent(e, IdeActions.ACTION_EDITOR_CREATE_RECTANGULAR_SELECTION);
}
private static boolean isMouseActionEvent(@NotNull MouseEvent e, @NotNull String actionId) {
KeymapManager keymapManager = KeymapManager.getInstance();
if (keymapManager == null) {
return false;
}
Keymap keymap = keymapManager.getActiveKeymap();
if (keymap == null) {
return false;
}
String[] actionIds = keymap.getActionIds(new MouseShortcut(e.getButton(), e.getModifiersEx(), 1));
if (actionIds == null) {
return false;
}
for (String id : actionIds) {
if (actionId.equals(id)) {
return true;
}
}
return false;
return KeymapUtil.isMouseActionEvent(e, IdeActions.ACTION_EDITOR_CREATE_RECTANGULAR_SELECTION);
}
private void selectWordAtCaret(boolean honorCamelCase) {
@@ -211,43 +211,7 @@ public class SelectionModelImpl implements SelectionModel, PrioritizedDocumentLi
@Override
public void setBlockSelection(@NotNull LogicalPosition blockStart, @NotNull LogicalPosition blockEnd) {
if (myEditor.getCaretModel().supportsMultipleCarets()) {
int startLine = Math.max(Math.min(blockStart.line, myEditor.getDocument().getLineCount() - 1), 0);
int endLine = Math.max(Math.min(blockEnd.line, myEditor.getDocument().getLineCount() - 1), 0);
int step = endLine < startLine ? -1 : 1;
int count = 1 + Math.abs(endLine - startLine);
List<CaretState> caretStates = new LinkedList<CaretState>();
boolean hasSelection = false;
for (int line = startLine, i = 0; i < count; i++, line += step) {
int startColumn = blockStart.column;
int endColumn = blockEnd.column;
int lineEndOffset = myEditor.getDocument().getLineEndOffset(line);
LogicalPosition lineEndPosition = myEditor.offsetToLogicalPosition(lineEndOffset);
int lineWidth = lineEndPosition.column;
if (startColumn > lineWidth && endColumn > lineWidth && !myEditor.isColumnMode()) {
LogicalPosition caretPos = new LogicalPosition(line, Math.min(startColumn, endColumn));
caretStates.add(new CaretState(caretPos,
lineEndPosition,
lineEndPosition));
}
else {
LogicalPosition startPos = new LogicalPosition(line, myEditor.isColumnMode() ? startColumn : Math.min(startColumn, lineWidth));
LogicalPosition endPos = new LogicalPosition(line, myEditor.isColumnMode() ? endColumn : Math.min(endColumn, lineWidth));
int startOffset = myEditor.logicalPositionToOffset(startPos);
int endOffset = myEditor.logicalPositionToOffset(endPos);
caretStates.add(new CaretState(endPos, startPos, endPos));
hasSelection |= startOffset != endOffset;
}
}
if (hasSelection && !myEditor.isColumnMode()) { // filtering out lines without selection
Iterator<CaretState> caretStateIterator = caretStates.iterator();
while(caretStateIterator.hasNext()) {
CaretState state = caretStateIterator.next();
//noinspection ConstantConditions
if (state.getSelectionStart().equals(state.getSelectionEnd())) {
caretStateIterator.remove();
}
}
}
List<CaretState> caretStates = EditorModificationUtil.calcBlockSelectionState(myEditor, blockStart, blockEnd);
myEditor.getCaretModel().setCaretsAndSelections(caretStates);
}
else {
@@ -26,7 +26,8 @@ public class ActionShortcutRestrictionsImpl extends ActionShortcutRestrictions {
@NotNull
public ShortcutRestrictions getForActionId(String actionId) {
if (IdeActions.ACTION_EDITOR_ADD_OR_REMOVE_CARET.equals(actionId) ||
IdeActions.ACTION_EDITOR_CREATE_RECTANGULAR_SELECTION.equals(actionId)) {
IdeActions.ACTION_EDITOR_CREATE_RECTANGULAR_SELECTION.equals(actionId) ||
IdeActions.ACTION_EDITOR_ADD_RECTANGULAR_SELECTION_ON_MOUSE_DRAG.equals(actionId)) {
return MOUSE_SINGLE_CLICK_ONLY;
}
if (IdeActions.ACTION_EXPAND_LIVE_TEMPLATE_BY_TAB.equals(actionId)) {
@@ -112,6 +112,7 @@ action.EditorMoveUpAndScrollWithSelection.text=Move Up and Scroll with Selection
action.EditorMoveDownAndScrollWithSelection.text=Move Down and Scroll with Selection
action.EditorAddOrRemoveCaret.text=Add or Remove Caret
action.EditorCreateRectangularSelection.text=Create Rectangular Selection
action.EditorAddRectangularSelectionOnMouseDrag.text=Add Rectangular Selection on Mouse Drag
action.EditorCloneCaretBelow.text=Clone Caret Below
action.EditorCloneCaretAbove.text=Clone Caret Above
action.SelectNextOccurrence.text=Add Selection for Next Occurrence
@@ -121,6 +121,9 @@
<action id="EditorAddOrRemoveCaret">
<mouse-shortcut keystroke="alt shift button1"/>
</action>
<action id="EditorAddRectangularSelectionOnMouseDrag">
<mouse-shortcut keystroke="ctrl alt shift button1"/>
</action>
<action id="EditorCreateRectangularSelection">
<mouse-shortcut keystroke="alt shift button2"/>
</action>
@@ -89,6 +89,7 @@
<action id="EditorMoveDownAndScrollWithSelection" class="com.intellij.openapi.editor.actions.MoveDownWithSelectionAndScrollAction"/>
<action id="EditorAddOrRemoveCaret" class="com.intellij.openapi.editor.actions.AddOrRemoveCaretDummyAction"/>
<action id="EditorCreateRectangularSelection" class="com.intellij.openapi.editor.actions.CreateRectangularSelectionAction"/>
<action id="EditorAddRectangularSelectionOnMouseDrag" class="com.intellij.openapi.editor.actions.AddRectangularSelectionOnMouseDragAction"/>
<action id="EditorCloneCaretBelow" class="com.intellij.openapi.editor.actions.CloneCaretBelow"/>
<action id="EditorCloneCaretAbove" class="com.intellij.openapi.editor.actions.CloneCaretAbove"/>
<action id="EditorToggleStickySelection" class="com.intellij.openapi.editor.actions.ToggleStickySelectionModeAction"/>
@@ -17,12 +17,12 @@ package com.intellij.openapi.editor;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.actionSystem.MouseShortcut;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
import com.intellij.openapi.editor.impl.AbstractEditorTest;
import com.intellij.openapi.keymap.Keymap;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.testFramework.EditorTestUtil;
import com.intellij.testFramework.TestFileType;
import com.intellij.util.ThrowableRunnable;
import java.awt.event.InputEvent;
@@ -43,11 +43,10 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testCaretAddingAndRemoval() throws Exception {
init("some <selection>t<caret>ext</selection>\n" +
"another line",
TestFileType.TEXT);
initText("some <selection>t<caret>ext</selection>\n" +
"another line");
mouse().alt().shift().clickAt(1,1); // alt-shift-click in a 'free space'
mouse().alt().shift().clickAt(1, 1); // alt-shift-click in a 'free space'
checkResultByText("some <selection>t<caret>ext</selection>\n" +
"a<caret>nother line");
@@ -76,7 +75,7 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
doWithAltClickShortcut(new ThrowableRunnable() {
@Override
public void run() throws IOException {
init("<caret>text", TestFileType.TEXT);
initText("<caret>text");
mouse().alt().clickAt(0, 2);
checkResultByText("<caret>te<caret>xt");
}
@@ -87,7 +86,7 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
doWithAltClickShortcut(new ThrowableRunnable() {
@Override
public void run() throws IOException {
init("<selection>some<caret></selection> text", TestFileType.TEXT);
initText("<selection>some<caret></selection> text");
mouse().alt().clickAt(0, 6);
mouse().alt().clickAt(0, 6);
checkResultByText("<selection>some<caret></selection> text");
@@ -96,12 +95,11 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testAltDragStartingFromWithinLine() throws Exception {
init("<caret>line\n" +
"long line\n" +
"very long line\n" +
"long line\n" +
"line",
TestFileType.TEXT);
initText("<caret>line\n" +
"long line\n" +
"very long line\n" +
"long line\n" +
"line");
setEditorVisibleSize(1000, 1000);
mouse().alt().pressAt(1, 6);
@@ -134,12 +132,11 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testMiddleButtonDragStartingFromVirtualSpace() throws Exception {
init("<caret>line\n" +
"long line\n" +
"very long line\n" +
"long line\n" +
"line",
TestFileType.TEXT);
initText("<caret>line\n" +
"long line\n" +
"very long line\n" +
"long line\n" +
"line");
setEditorVisibleSize(1000, 1000);
mouse().middle().pressAt(1, 17);
@@ -172,13 +169,12 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testAltOnOffWhileDragging() throws Exception {
init("line1\n" +
"line2\n" +
"line3",
TestFileType.TEXT);
initText("line1\n" +
"line2\n" +
"line3");
setEditorVisibleSize(1000, 1000);
mouse().clickAt(0, 1).dragTo(1, 2);
mouse().pressAt(0, 1).dragTo(1, 2);
checkResultByText("l<selection>ine1\n" +
"li<caret></selection>ne2\n" +
"line3");
@@ -193,11 +189,9 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testTyping() throws Exception {
init("some<caret> text<caret>\n" +
"some <selection><caret>other</selection> <selection>text<caret></selection>\n" +
"<selection>ano<caret>ther</selection> line",
TestFileType.TEXT
);
initText("some<caret> text<caret>\n" +
"some <selection><caret>other</selection> <selection>text<caret></selection>\n" +
"<selection>ano<caret>ther</selection> line");
type('A');
checkResultByText("someA<caret> textA<caret>\n" +
"some A<caret> A<caret>\n" +
@@ -205,9 +199,8 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testCopyPaste() throws Exception {
init("<selection><caret>one</selection> two \n" +
"<selection><caret>three</selection> four ",
TestFileType.TEXT);
initText("<selection><caret>one</selection> two \n" +
"<selection><caret>three</selection> four ");
executeAction("EditorCopy");
executeAction("EditorLineEnd");
executeAction("EditorPaste");
@@ -216,10 +209,8 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testCutAndPaste() throws Exception {
init("<selection>one<caret></selection> two \n" +
"<selection>three<caret></selection> four ",
TestFileType.TEXT
);
initText("<selection>one<caret></selection> two \n" +
"<selection>three<caret></selection> four ");
executeAction("EditorCut");
executeAction("EditorLineEnd");
executeAction("EditorPaste");
@@ -228,9 +219,8 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testPasteSingleItem() throws Exception {
init("<selection>one<caret></selection> two \n" +
"three four ",
TestFileType.TEXT);
initText("<selection>one<caret></selection> two \n" +
"three four ");
executeAction("EditorCopy");
executeAction("EditorCloneCaretBelow");
executeAction("EditorLineEnd");
@@ -240,12 +230,10 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testCutAndPasteMultiline() throws Exception {
init("one <selection>two \n" +
"three<caret></selection> four \n" +
"five <selection>six \n" +
"seven<caret></selection> eight",
TestFileType.TEXT
);
initText("one <selection>two \n" +
"three<caret></selection> four \n" +
"five <selection>six \n" +
"seven<caret></selection> eight");
executeAction("EditorCut");
executeAction("EditorLineEnd");
executeAction("EditorPaste");
@@ -256,11 +244,10 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testCopyMultilineFromOneCaretPasteIntoTwo() throws Exception {
init("<selection>one\n" +
"two<caret></selection>\n" +
"three\n" +
"four",
TestFileType.TEXT);
initText("<selection>one\n" +
"two<caret></selection>\n" +
"three\n" +
"four");
executeAction("EditorCopy");
executeAction("EditorTextStart");
executeAction("EditorCloneCaretBelow");
@@ -274,11 +261,10 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testCopyPasteDoesNothingWithUnevenSelection() throws Exception {
init("<selection>one\n" +
"two<caret></selection>\n" +
"<selection>three<caret></selection>\n" +
"four",
TestFileType.TEXT);
initText("<selection>one\n" +
"two<caret></selection>\n" +
"<selection>three<caret></selection>\n" +
"four");
executeAction("EditorCopy");
executeAction("EditorPaste");
checkResultByText("one\n" +
@@ -288,50 +274,43 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testEscapeAfterDragDown() throws Exception {
init("line1\n" +
"line2",
TestFileType.TEXT
);
initText("line1\n" +
"line2");
setEditorVisibleSize(1000, 1000);
mouse().alt().clickAt(0, 1).dragTo(1, 2).release();
mouse().alt().pressAt(0, 1).dragTo(1, 2).release();
executeAction("EditorEscape");
checkResultByText("li<caret>ne1\n" +
"line2");
}
public void testEscapeAfterDragUp() throws Exception {
init("line1\n" +
"line2",
TestFileType.TEXT);
initText("line1\n" +
"line2");
setEditorVisibleSize(1000, 1000);
mouse().alt().clickAt(1, 1).dragTo(0, 2).release();
mouse().alt().pressAt(1, 1).dragTo(0, 2).release();
executeAction("EditorEscape");
checkResultByText("line1\n" +
"li<caret>ne2");
}
public void testAltShiftDoubleClick() throws Exception {
init("q<caret>uick brown fox",
TestFileType.TEXT);
initText("q<caret>uick brown fox");
mouse().alt().shift().doubleClickAt(0, 8);
checkResultByText("q<caret>uick <selection>brown<caret></selection> fox");
}
public void testAltShiftDoubleClickAtExistingCaret() throws Exception {
init("q<caret>uick br<caret>own fox",
TestFileType.TEXT);
initText("q<caret>uick br<caret>own fox");
mouse().alt().shift().doubleClickAt(0, 8);
checkResultByText("q<caret>uick brown fox");
}
public void testAltShiftTripleClick() throws Exception {
init("q<caret>uick\n" +
"brown\n" +
"fox",
TestFileType.TEXT
);
initText("q<caret>uick\n" +
"brown\n" +
"fox");
mouse().alt().shift().tripleClickAt(1, 2);
checkResultByText("q<caret>uick\n" +
"<selection>br<caret>own\n" +
@@ -339,10 +318,9 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testAltShiftTripleClickAtExistingCaret() throws Exception {
init("q<caret>uick\n" +
"br<caret>own\n" +
"fox",
TestFileType.TEXT);
initText("q<caret>uick\n" +
"br<caret>own\n" +
"fox");
mouse().alt().shift().tripleClickAt(1, 2);
checkResultByText("q<caret>uick\n" +
"brown\n" +
@@ -350,9 +328,9 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testCaretPositionsRecalculationOnDocumentChange() throws Exception {
init("\n" +
"<selection><caret>word</selection>\n" +
"some long prefix <selection><caret>word</selection>-suffix", TestFileType.TEXT);
initText("\n" +
"<selection><caret>word</selection>\n" +
"some long prefix <selection><caret>word</selection>-suffix");
EditorTestUtil.configureSoftWraps(myEditor, 17); // wrapping right before 'word-suffix'
delete();
@@ -364,12 +342,11 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
}
public void testCreateRectangularSelectionWithMouseClicks() throws Exception {
init("<caret>line\n" +
"long line\n" +
"very long line\n" +
"long line\n" +
"line",
TestFileType.TEXT);
initText("<caret>line\n" +
"long line\n" +
"very long line\n" +
"long line\n" +
"line");
mouse().alt().shift().middle().clickAt(2, 2);
checkResultByText("<selection>li<caret></selection>ne\n" +
"<selection>lo<caret></selection>ng line\n" +
@@ -378,6 +355,35 @@ public class EditorMultiCaretTest extends AbstractEditorTest {
"line");
}
public void testAddingMultipleSelectionsUsingMouse() throws Exception {
initText("s<selection>om<caret></selection>e text\nother text");
setEditorVisibleSize(1000, 1000);
mouse().alt().shift().pressAt(0, 5).dragTo(1, 2).release();
checkResultByText("s<selection>om<caret></selection>e <selection>text\not<caret></selection>her text");
}
public void testAddingMultipleSelectionsUsingMouseInColumnSelectionMode() throws Exception {
initText("s<selection>om<caret></selection>e text\nother text");
setEditorVisibleSize(1000, 1000);
((EditorEx)myEditor).setColumnMode(true);
mouse().alt().shift().pressAt(0, 5).dragTo(1, 2).release();
checkResultByText("s<selection>om<caret></selection>e <selection>text\not<caret></selection>her text");
}
public void testAltShiftDragAfterRemovingCaret() throws Exception {
initText("<selection>a<caret></selection>b<caret>racadabra");
setEditorVisibleSize(1000, 1000);
mouse().alt().shift().pressAt(0, 2).dragTo(0, 3).release();
checkResultByText("<selection>a<caret></selection>bracadabra");
}
public void testAddingRectangualSelectionUsingMouse() throws Exception {
initText("s<selection>om<caret></selection>e text\nother text");
setEditorVisibleSize(1000, 1000);
mouse().ctrl().alt().shift().pressAt(0, 7).dragTo(1, 5).release();
checkResultByText("s<selection>om<caret></selection>e <selection><caret>te</selection>xt\nother<selection><caret> t</selection>ext");
}
private static void doWithAltClickShortcut(ThrowableRunnable runnable) throws Throwable {
Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
MouseShortcut shortcut = new MouseShortcut(1, InputEvent.ALT_DOWN_MASK, 1);
@@ -112,6 +112,11 @@ public class EditorMouseFixture {
return this;
}
public EditorMouseFixture ctrl() {
myModifiers |= InputEvent.CTRL_DOWN_MASK;
return this;
}
public EditorMouseFixture alt() {
myModifiers |= InputEvent.ALT_DOWN_MASK;
return this;