diff --git a/src/actions/actions.ts b/src/actions/actions.ts index dec18ac2ceb..e9f48ab03b5 100644 --- a/src/actions/actions.ts +++ b/src/actions/actions.ts @@ -1006,6 +1006,39 @@ class ActionDeleteLastChar extends BaseCommand { } } + +@RegisterAction +class ActionJoin extends BaseCommand { + modes = [ModeName.Normal]; + keys = ["J"]; + + public async exec(position: Position, vimState: VimState): Promise { + if (position.line === TextEditor.getLineCount() - 1) { + return vimState; // TODO: bell + } + + // TODO(whitespace): need a better way to check for whitespace + const char = TextEditor.getLineAt(position.getNextLineBegin()).text[0]; + const nextLineStartsWithWhitespace = + char === ' ' || char === '\t'; + + const positionToDeleteTo = + nextLineStartsWithWhitespace ? + position.getNextLineBegin().getFirstLineNonBlankChar().getLeft().getLeft() : + position.getLineEnd(); + + if (!nextLineStartsWithWhitespace) { + await TextEditor.insertAt(" ", position.getNextLineBegin()); + } + + return await new DeleteOperator().run( + vimState, + position.getLineEnd(), + positionToDeleteTo + ); + } +} + @RegisterAction class MoveDD extends BaseMovement { modes = [ModeName.Normal]; @@ -1096,7 +1129,7 @@ class MovementAWordTextObject extends BaseMovement { const currentChar = TextEditor.getLineAt(position).text[position.character]; - // TODO - this is a bad way to do this. we need some sort of global + // TODO(whitespace) - this is a bad way to do this. we need some sort of global // white space checking function. if (currentChar === ' ' || currentChar === '\t') { vimState.cursorStartPosition = position.getLastWordEnd().getRight(); @@ -1132,7 +1165,7 @@ class MovementIWordTextObject extends BaseMovement { const currentChar = TextEditor.getLineAt(position).text[position.character]; - // TODO - this is a bad way to do this. we need some sort of global + // TODO(whitespace) - this is a bad way to do this. we need some sort of global // white space checking function. if (currentChar === ' ' || currentChar === '\t') { vimState.cursorStartPosition = position.getLastWordEnd().getRight(); diff --git a/src/mode/modeHandler.ts b/src/mode/modeHandler.ts index 1560af52d12..87052187879 100644 --- a/src/mode/modeHandler.ts +++ b/src/mode/modeHandler.ts @@ -50,9 +50,16 @@ export class VimState { */ public desiredColumn = 0; - public oldDotKeys = []; + /** + * The keystroke sequence that made up our last complete action (that can be + * repeated with '.'). + */ + public previousFullAction = []; - public dotKeys = []; + /** + * The current full action we are building up. + */ + public currentFullAction = []; /** * The position the cursor will be when this action finishes. @@ -302,7 +309,7 @@ export class ModeHandler implements vscode.Disposable { let actionState = vimState.actionState; actionState.actionKeys.push(key); - vimState.dotKeys.push(key); + vimState.currentFullAction.push(key); let action = Actions.getRelevantAction(actionState.actionKeys, vimState); @@ -361,11 +368,11 @@ export class ModeHandler implements vscode.Disposable { // Update dot keys if (vimState.isFullDotAction()) { - vimState.oldDotKeys = vimState.dotKeys; + vimState.previousFullAction = vimState.currentFullAction; } if (vimState.shouldResetCurrentDotKeys()) { - vimState.dotKeys = []; + vimState.currentFullAction = []; } vimState.actionState = new ActionState(vimState); @@ -432,10 +439,10 @@ export class ModeHandler implements vscode.Disposable { case VimCommandActions.MoveFullPageDown: await vscode.commands.executeCommand("cursorPageUp"); break; case VimCommandActions.MoveFullPageUp: await vscode.commands.executeCommand("cursorPageDown"); break; case VimCommandActions.Dot: - const oldDotKeysCopy = vimState.oldDotKeys.slice(0); + const oldDotKeysCopy = vimState.previousFullAction.slice(0); vimState.actionState = new ActionState(vimState); - vimState.dotKeys = []; + vimState.currentFullAction = []; for (let key of oldDotKeysCopy) { vimState = await this.handleKeyEventHelper(key, vimState);