Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor CommandBuilder, arguments, etc. #979

Merged
merged 29 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1d9e8ac
Remove unused digraph command flag
citizenmatt Jul 23, 2024
599c0ed
Remove unused OperatedRange type
citizenmatt Jul 26, 2024
43a81b1
Introduce sealed classes to represent an argument
citizenmatt Jul 23, 2024
076fc15
Refactor properties for sealed Argument classes
citizenmatt Jul 26, 2024
0636872
Wrap offsets argument as an external action
citizenmatt Jul 28, 2024
9106517
Remove count from motion argument
citizenmatt Jul 30, 2024
e2a37ce
Simplify CommandBuilder
citizenmatt Jul 31, 2024
7ff6bf9
Replace var properties with read only
citizenmatt Jul 31, 2024
6f32a9b
Remove unnecessary copy method
citizenmatt Jul 31, 2024
98ad763
Make Command.rawCount immutable
citizenmatt Jul 31, 2024
868f428
Update comment
citizenmatt Jul 31, 2024
37ef432
Avoid exposing misleading count on command builder
citizenmatt Jul 31, 2024
813d16f
Move register pending state to command builder
citizenmatt Aug 1, 2024
f6c9392
Encapsulate command node state in builder
citizenmatt Aug 1, 2024
a8d5ffb
Remove KeyHandler.isOperatorPending
citizenmatt Aug 2, 2024
d173d50
Start to refactor OperatorArguments
citizenmatt Aug 5, 2024
2a9b340
Add 'whichwrap' to dictionary
citizenmatt Aug 6, 2024
f09a7e7
Deprecate OperatorArguments.isOperatorPending
citizenmatt Aug 10, 2024
8077809
Handle op-pending for space and backspace
citizenmatt Aug 11, 2024
4f2dad8
Remove OperatorArguments.mode usage in block insert
citizenmatt Aug 23, 2024
04dece7
Simplify the logic when yanking during delete
citizenmatt Aug 23, 2024
80ee4e2
Use editor.mode instead of OperatorArguments.mode
citizenmatt Aug 23, 2024
77ae379
Deprecate OperatorArguments.mode
citizenmatt Aug 24, 2024
9db95e8
Remove unnecessary OperatorArguments parameters
citizenmatt Aug 23, 2024
d6a3e15
Remove unused EMPTY_COMMAND
citizenmatt Aug 23, 2024
6288814
Start to encapsulate setting command builder state
citizenmatt Aug 28, 2024
328cd75
Reorder CommandBuilder methods
citizenmatt Aug 28, 2024
7c4a2ca
Ensure builder resets to a root command trie node
citizenmatt Aug 28, 2024
06ff832
Encapsulate the command builder's state flag
citizenmatt Aug 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import com.maddyhome.idea.vim.vimscript.model.expressions.FunctionCallExpression
import com.maddyhome.idea.vim.vimscript.model.expressions.SimpleExpression

// todo make it multicaret
private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textRange: TextRange, selectionType: SelectionType): Boolean {
private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textRange: TextRange, motionType: SelectionType): Boolean {
val func = injector.globalOptions().operatorfunc
if (func.isEmpty()) {
VimPlugin.showMessage(MessageHelper.message("E774"))
Expand All @@ -57,9 +57,9 @@ private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textR
if (value is VimFuncref) {
handler = value.handler
}
} catch (ex: ExException) {
} catch (_: ExException) {
// Get the argument for function('...') or funcref('...') for the error message
val functionName = if (expression is FunctionCallExpression && expression.arguments.size > 0) {
val functionName = if (expression is FunctionCallExpression && expression.arguments.isNotEmpty()) {
expression.arguments[0].evaluate(editor, context, scriptContext).toString()
}
else {
Expand All @@ -77,7 +77,7 @@ private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textR
return false
}

val arg = when (selectionType) {
val arg = when (motionType) {
SelectionType.LINE_WISE -> "line"
SelectionType.CHARACTER_WISE -> "char"
SelectionType.BLOCK_WISE -> "block"
Expand All @@ -101,27 +101,21 @@ internal class OperatorAction : VimActionHandler.SingleExecution() {
override val argumentType: Argument.Type = Argument.Type.MOTION

override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val argument = cmd.argument ?: return false
val argument = cmd.argument as? Argument.Motion ?: return false
if (!editor.inRepeatMode) {
argumentCaptured = argument
}
val range = getMotionRange(editor, context, argument, operatorArguments)

if (range != null) {
val selectionType = if (argument.motion.isLinewiseMotion()) {
SelectionType.LINE_WISE
} else {
SelectionType.CHARACTER_WISE
}
return doOperatorAction(editor, context, range, selectionType)
return doOperatorAction(editor, context, range, argument.getMotionType())
}
return false
}

private fun getMotionRange(
editor: VimEditor,
context: ExecutionContext,
argument: Argument,
argument: Argument.Motion,
operatorArguments: OperatorArguments,
): TextRange? {
// Note that we're using getMotionRange2 in order to avoid normalising the linewise range into line start
Expand All @@ -136,7 +130,7 @@ internal class OperatorAction : VimActionHandler.SingleExecution() {
operatorArguments,
)?.normalize()?.let {
// If we're linewise, make sure the end offset isn't just the EOL char
if (argument.motion.isLinewiseMotion() && it.endOffset < editor.fileSize()) {
if (argument.getMotionType() == SelectionType.LINE_WISE && it.endOffset < editor.fileSize()) {
TextRange(it.startOffset, it.endOffset + 1)
} else {
it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ internal class RepeatChangeAction : VimActionHandler.SingleExecution() {

override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val state = injector.vimState
val lastCommand = VimRepeater.lastChangeCommand
var lastCommand = VimRepeater.lastChangeCommand

if (lastCommand == null && Extension.lastExtensionHandler == null) return false

Expand Down Expand Up @@ -57,12 +57,7 @@ internal class RepeatChangeAction : VimActionHandler.SingleExecution() {
)
} else if (!repeatHandler && lastCommand != null) {
if (cmd.rawCount > 0) {
lastCommand.rawCount = cmd.count
val arg = lastCommand.argument
if (arg != null) {
val mot = arg.motion
mot.rawCount = 0
}
lastCommand = lastCommand.copy(rawCount = cmd.rawCount)
}
state.executingCommand = lastCommand

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.api.*;
import com.maddyhome.idea.vim.command.*;
import com.maddyhome.idea.vim.common.CurrentCommandState;
import com.maddyhome.idea.vim.common.TextRange;
import com.maddyhome.idea.vim.extension.ExtensionHandler;
import com.maddyhome.idea.vim.extension.VimExtension;
Expand All @@ -33,7 +34,6 @@

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.EnumSet;

import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping;
import static com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing;
Expand Down Expand Up @@ -64,8 +64,8 @@ public void init() {
*/
private static class BracketPairs {
// NOTE: brackets must match by the position, and ordered by rank (highest to lowest).
@NotNull private final String openBrackets;
@NotNull private final String closeBrackets;
private final @NotNull String openBrackets;
private final @NotNull String closeBrackets;

static class ParseException extends Exception {
public ParseException(@NotNull String message) {
Expand All @@ -87,8 +87,7 @@ private enum ParseState {
* @param bracketPairs comma-separated list of colon-separated bracket pairs.
* @throws ParseException if a syntax error is detected.
*/
@NotNull
static BracketPairs fromBracketPairList(@NotNull final String bracketPairs) throws ParseException {
static @NotNull BracketPairs fromBracketPairList(final @NotNull String bracketPairs) throws ParseException {
StringBuilder openBrackets = new StringBuilder();
StringBuilder closeBrackets = new StringBuilder();
ParseState state = ParseState.OPEN;
Expand Down Expand Up @@ -128,7 +127,7 @@ static BracketPairs fromBracketPairList(@NotNull final String bracketPairs) thro
return new BracketPairs(openBrackets.toString(), closeBrackets.toString());
}

BracketPairs(@NotNull final String openBrackets, @NotNull final String closeBrackets) {
BracketPairs(final @NotNull String openBrackets, final @NotNull String closeBrackets) {
assert openBrackets.length() == closeBrackets.length();
this.openBrackets = openBrackets;
this.closeBrackets = closeBrackets;
Expand Down Expand Up @@ -158,10 +157,9 @@ boolean isOpenBracket(final int ch) {
}
}

public static final BracketPairs DEFAULT_BRACKET_PAIRS = new BracketPairs("(", ")");
private static final BracketPairs DEFAULT_BRACKET_PAIRS = new BracketPairs("(", ")");

@Nullable
private static String bracketPairsVariable() {
private static @Nullable String bracketPairsVariable() {
final Object value = VimPlugin.getVariableService().getGlobalVariableValue("argtextobj_pairs");
if (value instanceof VimString vimValue) {
return vimValue.getValue();
Expand Down Expand Up @@ -192,13 +190,12 @@ static class ArgumentTextObjectHandler extends TextObjectActionHandler {
this.isInner = isInner;
}

@Nullable
@Override
public TextRange getRange(@NotNull VimEditor editor,
@NotNull ImmutableVimCaret caret,
@NotNull ExecutionContext context,
int count,
int rawCount) {
public @Nullable TextRange getRange(@NotNull VimEditor editor,
@NotNull ImmutableVimCaret caret,
@NotNull ExecutionContext context,
int count,
int rawCount) {
BracketPairs bracketPairs = DEFAULT_BRACKET_PAIRS;
final String bracketPairsVar = bracketPairsVariable();
if (bracketPairsVar != null) {
Expand Down Expand Up @@ -236,24 +233,22 @@ public TextRange getRange(@NotNull VimEditor editor,
return new TextRange(finder.getLeftBound(), finder.getRightBound());
}

@NotNull
@Override
public TextObjectVisualType getVisualType() {
public @NotNull TextObjectVisualType getVisualType() {
return TextObjectVisualType.CHARACTER_WISE;
}
}

@Override
public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context, @NotNull OperatorArguments operatorArguments) {
@NotNull KeyHandler keyHandler = KeyHandler.getInstance();
@NotNull KeyHandlerState keyHandlerState = KeyHandler.getInstance().getKeyHandlerState();
int count = Math.max(1, keyHandlerState.getCommandBuilder().getCount());

final ArgumentTextObjectHandler textObjectHandler = new ArgumentTextObjectHandler(isInner);
//noinspection DuplicatedCode
if (!keyHandler.isOperatorPending(editor.getMode(), keyHandlerState)) {
if (!(editor.getMode() instanceof Mode.OP_PENDING)) {
int count0 = operatorArguments.getCount0();
editor.nativeCarets().forEach((VimCaret caret) -> {
final TextRange range = textObjectHandler.getRange(editor, caret, context, count, 0);
final TextRange range = textObjectHandler.getRange(editor, caret, context, Math.max(1, count0), count0);
if (range != null) {
try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
if (editor.getMode() instanceof Mode.VISUAL) {
Expand All @@ -265,8 +260,8 @@ public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context
}
});
} else {
keyHandlerState.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
textObjectHandler, Command.Type.MOTION, EnumSet.noneOf(CommandFlags.class))));
keyHandlerState.getCommandBuilder().pushCommandPart(textObjectHandler);
keyHandlerState.getCommandBuilder().setCommandState(CurrentCommandState.READY);
}
}
}
Expand All @@ -276,9 +271,9 @@ public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context
* position
*/
private static class ArgBoundsFinder {
@NotNull private final CharSequence text;
@NotNull private final Document document;
@NotNull private final BracketPairs brackets;
private final @NotNull CharSequence text;
private final @NotNull Document document;
private final @NotNull BracketPairs brackets;
private int leftBound = Integer.MAX_VALUE;
private int rightBound = Integer.MIN_VALUE;
private int leftBracket;
Expand All @@ -305,7 +300,7 @@ private static class ArgBoundsFinder {
* @param position starting position.
*/
boolean findBoundsAt(int position) throws IllegalStateException {
if (text.length() == 0) {
if (text.isEmpty()) {
error = "empty document";
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ import com.maddyhome.idea.vim.api.getLineEndOffset
import com.maddyhome.idea.vim.api.globalOptions
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.TextObjectVisualType
Expand All @@ -52,7 +50,6 @@ import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.Mode
import com.maddyhome.idea.vim.state.mode.SelectionType
import java.util.*

internal class CommentaryExtension : VimExtension {

Expand Down Expand Up @@ -184,10 +181,8 @@ internal class CommentaryExtension : VimExtension {
override val isRepeatable = true

override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
val command = Command(operatorArguments.count1, CommentaryTextObjectMotionHandler, Command.Type.MOTION, EnumSet.noneOf(CommandFlags::class.java))

val keyState = KeyHandler.getInstance().keyHandlerState
keyState.commandBuilder.completeCommandPart(Argument(command))
keyState.commandBuilder.completeCommandPart(Argument.Motion(CommentaryTextObjectMotionHandler))
}
}

Expand Down
35 changes: 15 additions & 20 deletions src/main/java/com/maddyhome/idea/vim/extension/matchit/Matchit.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.state.mode.Mode
import java.util.*
import java.util.regex.Pattern

Expand Down Expand Up @@ -93,34 +94,29 @@ internal class Matchit : VimExtension {
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
val keyHandler = KeyHandler.getInstance()
val keyState = keyHandler.keyHandlerState
val count = keyState.commandBuilder.count

// Reset the command count so it doesn't transfer onto subsequent commands.
keyState.commandBuilder.resetCount()

// Normally we want to jump to the start of the matching pair. But when moving forward in operator
// pending mode, we want to include the entire match. isInOpPending makes that distinction.
val isInOpPending = keyHandler.isOperatorPending(editor.mode, keyState)

if (isInOpPending) {
if (editor.mode is Mode.OP_PENDING) {
val matchitAction = MatchitAction()
matchitAction.reverse = reverse
matchitAction.isInOpPending = true

keyState.commandBuilder.completeCommandPart(
Argument(
Command(
count,
matchitAction,
Command.Type.MOTION,
EnumSet.noneOf(CommandFlags::class.java),
),
),
)
keyState.commandBuilder.completeCommandPart(Argument.Motion(matchitAction, null))
} else {
editor.sortedCarets().forEach { caret ->
injector.jumpService.saveJumpLocation(editor)
caret.moveToOffset(getMatchitOffset(editor.ij, caret.ij, count, isInOpPending, reverse))
caret.moveToOffset(
getMatchitOffset(
editor.ij,
caret.ij,
operatorArguments.count0,
isInOpPending = false,
reverse
))
}
}
}
Expand Down Expand Up @@ -354,7 +350,7 @@ private object FileTypePatterns {

private val DEFAULT_PAIRS = setOf('(', ')', '[', ']', '{', '}')

private fun getMatchitOffset(editor: Editor, caret: Caret, count: Int, isInOpPending: Boolean, reverse: Boolean): Int {
private fun getMatchitOffset(editor: Editor, caret: Caret, count0: Int, isInOpPending: Boolean, reverse: Boolean): Int {
val virtualFile = EditorHelper.getVirtualFile(editor)
var caretOffset = caret.offset

Expand All @@ -367,9 +363,9 @@ private fun getMatchitOffset(editor: Editor, caret: Caret, count: Int, isInOpPen
val currentChar = editor.document.charsSequence[caretOffset]
var motionOffset: Int? = null

if (count > 0) {
if (count0 > 0) {
// Matchit doesn't affect the percent motion, so we fall back to the default behavior.
motionOffset = VimPlugin.getMotion().moveCaretToLinePercent(editor.vim, caret.vim, count)
motionOffset = VimPlugin.getMotion().moveCaretToLinePercent(editor.vim, caret.vim, count0)
} else {
// Check the simplest case first.
if (DEFAULT_PAIRS.contains(currentChar)) {
Expand Down Expand Up @@ -400,8 +396,7 @@ private fun getMatchitOffset(editor: Editor, caret: Caret, count: Int, isInOpPen

private fun getMotionOffset(motion: Motion): Int? {
return when (motion) {
is Motion.AbsoluteOffset -> motion.offset
is Motion.AdjustedOffset -> motion.offset
is Motion.AdjustedOffset, is Motion.AbsoluteOffset -> motion.offset
is Motion.Error, is Motion.NoMotion -> null
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ package com.maddyhome.idea.vim.extension.replacewithregister

import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.ImmutableVimCaret
Expand Down Expand Up @@ -166,18 +165,13 @@ private fun doReplace(editor: Editor, context: DataContext, caret: ImmutableVimC
putToLine = -1,
)
val vimEditor = editor.vim
val keyHandler = KeyHandler.getInstance()
ClipboardOptionHelper.IdeaputDisabler().use {
VimPlugin.getPut().putText(
vimEditor,
context.vim,
putData,
operatorArguments = OperatorArguments(
keyHandler.isOperatorPending(vimEditor.mode, keyHandler.keyHandlerState),
0,
editor.vim.mode,
),
operatorArguments = OperatorArguments(0, editor.vim.mode),
saveToRegister = false
)
}
}
}
Loading