IDEA-110607 Double clicking space/tab characters should select all space/tab characters until it encounters another type of character

Better word unselect

GitOrigin-RevId: 5519cf57e79052e7472d554631865263531cf7d6
This commit is contained in:
Filipp Vakhitov
2023-02-15 19:29:36 +02:00
committed by intellij-monorepo-bot
parent dd712b6535
commit 92ac1b6044
11 changed files with 117 additions and 69 deletions

View File

@@ -1,7 +1,7 @@
class C {
private void foo() {
<selection>{
<caret>
}</selection>
{
<selection> <caret>
</selection> }
}
}
}

View File

@@ -1,7 +1,7 @@
class C {
private void foo() {
<selection> {
<selection>{
<caret>
}
</selection> }
}
}</selection>
}
}

View File

@@ -1,7 +1,7 @@
class C {
private void foo() <selection>{
{
private void foo() {
<selection> {
<caret>
}
}</selection>
}
</selection> }
}

View File

@@ -0,0 +1,7 @@
class C {
private void foo() <selection>{
{
<caret>
}
}</selection>
}

View File

@@ -857,6 +857,7 @@ advanced.setting.editor.normalize.splits=Equalize proportions in nested splits
advanced.setting.editor.normalize.splits.description=Adjust splitters to keep space equally distributed after split/unsplit.
advanced.setting.editor.open.inactive.splitter=When navigating to a file, prefer selecting existing tab in inactive split pane
advanced.setting.editor.keep.pinned.tabs.on.left=Keep pinned tabs on the left
advanced.setting.editor.selection.expand-whitespaces=Select whitespace characters with 'Extend Selection'
advanced.setting.terminal.buffer.max.lines.count=Terminal scrollback buffer size
advanced.setting.terminal.buffer.max.lines.count.trailingLabel=lines
advanced.setting.terminal.escape.moves.focus.to.editor=Move focus to the editor with Escape

View File

@@ -127,7 +127,7 @@ public class SelectWordHandler extends EditorActionHandler.ForEachCaret {
}
}
if (!(element instanceof PsiWhiteSpace && SelectWordUtil.canWhiteSpaceBeExpanded((PsiWhiteSpace) element, caretOffset, caret))) {
if (!(element instanceof PsiWhiteSpace && SelectWordUtil.canWhiteSpaceBeExpanded((PsiWhiteSpace) element, caretOffset, caret, caret.getEditor()))) {
while (element instanceof PsiWhiteSpace || element != null && StringUtil.isEmptyOrSpaces(element.getText())) {
while (element.getNextSibling() == null) {
if (element instanceof PsiFile) return null;

View File

@@ -8,8 +8,10 @@ import com.intellij.lexer.Lexer;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actions.EditorActionUtil;
import com.intellij.openapi.options.advanced.AdvancedSettings;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.util.Processor;
@@ -270,16 +272,24 @@ public final class SelectWordUtil {
* Returns if there is any expandable whitespace belonging to the given psiWhiteSpace
* by any side of a caret at specified cursorPosition
*/
public static boolean canWhiteSpaceBeExpanded(PsiWhiteSpace psiWhiteSpace, int cursorPosition, Caret caret) {
if (caret.hasSelection() && psiWhiteSpace.getTextRange().contains(caret.getSelectionRange())) return false;
public static boolean canWhiteSpaceBeExpanded(@NotNull PsiWhiteSpace psiWhiteSpace, int cursorPosition, @Nullable Caret caret, @NotNull Editor editor) {
if (!AdvancedSettings.getBoolean("editor.selection.expand-whitespaces")) return false;
int beforeOffset = caret.hasSelection()? caret.getSelectionStart() : cursorPosition;
Character charBeforeCursor = getCharBeforeCursorInPsiElement(psiWhiteSpace, beforeOffset);
if (charBeforeCursor != null && isExpandableWhiteSpace(charBeforeCursor)) return true;
TextRange selectionRange = caret != null && caret.hasSelection() ? caret.getSelectionRange() : null;
if (selectionRange != null && !psiWhiteSpace.getTextRange().contains(selectionRange)) return false;
int startOffset = selectionRange == null ? cursorPosition : selectionRange.getStartOffset();
Character charBeforeStartOffset = getCharBeforeCursorInPsiElement(psiWhiteSpace, startOffset);
if (charBeforeStartOffset != null && isExpandableWhiteSpace(charBeforeStartOffset)) return true;
int afterOffset = caret.hasSelection()? caret.getSelectionEnd() : cursorPosition;
Character charAfterCursor = getCharAfterCursorInPsiElement(psiWhiteSpace, afterOffset);
if (charAfterCursor != null && isExpandableWhiteSpace(charAfterCursor)) return true;
int endOffset = selectionRange == null ? cursorPosition : selectionRange.getEndOffset();
Character charBeforeEndOffset = getCharBeforeCursorInPsiElement(psiWhiteSpace, endOffset);
Character charAfterEndOffset = getCharAfterCursorInPsiElement(psiWhiteSpace, endOffset);
if (charAfterEndOffset != null && isExpandableWhiteSpace(charAfterEndOffset)) return true;
if (charBeforeEndOffset != null && isExpandableWhiteSpace(charBeforeEndOffset)
&& charAfterEndOffset != null && Character.isWhitespace(charAfterEndOffset)) {
return true;
}
return false;
}

View File

@@ -32,6 +32,7 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class UnSelectWordHandler extends EditorActionHandler.ForEachCaret {
private final EditorActionHandler myOriginalHandler;
@@ -85,54 +86,23 @@ public class UnSelectWordHandler extends EditorActionHandler.ForEachCaret {
}
}
final TextRange selectionRange = new TextRange(editor.getSelectionModel().getSelectionStart(), editor.getSelectionModel().getSelectionEnd());
MaxRangeProcessor rangeProcessor = new MaxRangeProcessor(selectionRange, editor, cursorOffset);
if (element instanceof PsiWhiteSpace) {
PsiElement nextSibling = element.getNextSibling();
if (nextSibling == null) {
element = element.getParent();
if (element == null || element instanceof PsiFile) {
return;
}
nextSibling = element.getNextSibling();
if (nextSibling == null) {
return;
}
if (SelectWordUtil.canWhiteSpaceBeExpanded((PsiWhiteSpace) element, cursorOffset, null, editor)) {
SelectWordUtil.processRanges(element, text, cursorOffset, editor, rangeProcessor);
}
element = nextSibling;
cursorOffset = element.getTextRange().getStartOffset();
PsiElement sibling = findNextSibling(element);
if (sibling != null) {
int siblingOffset = sibling.getTextRange().getStartOffset();
rangeProcessor.setCursorOffset(siblingOffset);
SelectWordUtil.processRanges(sibling, text, siblingOffset, editor, rangeProcessor);
}
} else {
SelectWordUtil.processRanges(element, text, cursorOffset, editor, rangeProcessor);
}
final TextRange selectionRange = new TextRange(editor.getSelectionModel().getSelectionStart(), editor.getSelectionModel().getSelectionEnd());
final Ref<TextRange> maximumRange = new Ref<>();
final int finalCursorOffset = cursorOffset;
SelectWordUtil.processRanges(element, text, cursorOffset, editor, new Processor<>() {
@Override
public boolean process(TextRange range) {
range = expandToFoldingBoundaries(range);
if (selectionRange.contains(range) && !range.equals(selectionRange) &&
(range.contains(finalCursorOffset) || finalCursorOffset == range.getEndOffset())) {
if (maximumRange.get() == null || range.contains(maximumRange.get())) {
maximumRange.set(range);
}
}
return false;
}
private TextRange expandToFoldingBoundaries(TextRange range) {
int startOffset = range.getStartOffset();
FoldRegion region = editor.getFoldingModel().getCollapsedRegionAtOffset(startOffset);
if (region != null) startOffset = region.getStartOffset();
int endOffset = range.getEndOffset();
region = editor.getFoldingModel().getCollapsedRegionAtOffset(endOffset);
if (region != null && endOffset > region.getStartOffset()) endOffset = region.getEndOffset();
return new TextRange(startOffset, endOffset);
}
});
TextRange range = maximumRange.get();
TextRange range = rangeProcessor.getMaximumRange();
if (range == null) {
editor.getSelectionModel().setSelection(cursorOffset, cursorOffset);
}
@@ -140,4 +110,63 @@ public class UnSelectWordHandler extends EditorActionHandler.ForEachCaret {
editor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset());
}
}
private static @Nullable PsiElement findNextSibling(PsiElement element) {
PsiElement nextSibling = element.getNextSibling();
if (nextSibling == null) {
element = element.getParent();
if (element == null || element instanceof PsiFile) {
return null;
}
nextSibling = element.getNextSibling();
if (nextSibling == null) {
return null;
}
}
return nextSibling;
}
private static class MaxRangeProcessor implements Processor<TextRange> {
private final Ref<TextRange> maximumRange;
private final TextRange selectionRange;
private final Editor editor;
private int cursorOffset;
private void setCursorOffset(int cursorOffset) {
this.cursorOffset = cursorOffset;
}
private MaxRangeProcessor(TextRange selectionRange, Editor editor, int cursorOffset) {
this.maximumRange = new Ref<>();
this.selectionRange = selectionRange;
this.editor = editor;
this.cursorOffset = cursorOffset;
}
@Override
public boolean process(TextRange range) {
range = expandToFoldingBoundaries(range);
if (selectionRange.contains(range) && !range.equals(selectionRange) &&
(range.contains(cursorOffset) || cursorOffset == range.getEndOffset())) {
if (maximumRange.get() == null || range.contains(maximumRange.get())) {
maximumRange.set(range);
}
}
return false;
}
private TextRange expandToFoldingBoundaries(TextRange range) {
int startOffset = range.getStartOffset();
FoldRegion region = editor.getFoldingModel().getCollapsedRegionAtOffset(startOffset);
if (region != null) startOffset = region.getStartOffset();
int endOffset = range.getEndOffset();
region = editor.getFoldingModel().getCollapsedRegionAtOffset(endOffset);
if (region != null && endOffset > region.getStartOffset()) endOffset = region.getEndOffset();
return new TextRange(startOffset, endOffset);
}
private TextRange getMaximumRange() {
return maximumRange.get();
}
}
}

View File

@@ -1385,6 +1385,7 @@
<advancedSetting id="editor.tab.painting" enumClass="com.intellij.openapi.editor.impl.TabCharacterPaintMode" default="HORIZONTAL_LINE" groupKey="group.advanced.settings.editor"/>
<advancedSetting id="editor.distraction.free.margin" default="-1" groupKey="group.advanced.settings.editor"/>
<advancedSetting id="editor.soft.wrap.force.limit" default="100000" groupKey="group.advanced.settings.editor"/>
<advancedSetting id="editor.selection.expand-whitespaces" default="true" groupKey="group.advanced.settings.editor"/>
<advancedSetting id="editor.open.inactive.splitter" default="true" groupKey="group.advanced.settings.editor.tabs"/>
<advancedSetting id="editor.reuse.not.modified.tabs" default="false" groupKey="group.advanced.settings.editor.tabs" service="com.intellij.ide.ui.UISettings" property="reuseNotModifiedTabs"/>
<advancedSetting id="editor.open.tabs.in.main.window" default="false" groupKey="group.advanced.settings.editor.tabs" service="com.intellij.ide.ui.UISettings" property="openTabsInMainWindow"/>

View File

@@ -1,3 +1,3 @@
class SimpleClass <selection>{
<caret>
}</selection>
class SimpleClass {
<selection> <caret>
</selection>}

View File

@@ -1,3 +1,3 @@
<selection>class SimpleClass {
class SimpleClass <selection>{
<caret>
}</selection>