mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-121925 Allow to do multiple selections w/wout multiple carets per selection
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+31
@@ -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) {
|
||||
|
||||
+1
-37
@@ -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 {
|
||||
|
||||
+2
-1
@@ -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"/>
|
||||
|
||||
+92
-86
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user