diff --git a/src/actions/actions.ts b/src/actions/actions.ts index 4d5df7dc8..68fe8ce1a 100644 --- a/src/actions/actions.ts +++ b/src/actions/actions.ts @@ -3596,19 +3596,9 @@ class ToggleCaseOperator extends BaseOperator { public modes = [ModeName.Visual, ModeName.VisualLine]; public async run(vimState: VimState, start: Position, end: Position): Promise { - const range = new vscode.Range(start, new Position(end.line, end.character + 1)); - const char = TextEditor.getText(range); + const range = new vscode.Range(start, end.getRight()); - // Try lower-case - let toggled = char.toLocaleLowerCase(); - if (toggled === char) { - // Try upper-case - toggled = char.toLocaleUpperCase(); - } - - if (toggled !== char) { - await TextEditor.replace(range, toggled); - } + await ToggleCaseOperator.toggleCase(range); const cursorPosition = start.isBefore(end) ? start : end; vimState.cursorPosition = cursorPosition; @@ -3617,6 +3607,43 @@ class ToggleCaseOperator extends BaseOperator { return vimState; } + + static async toggleCase(range: vscode.Range) { + const text = TextEditor.getText(range); + + let newText = ""; + for (var i = 0; i < text.length; i++) { + var char = text[i]; + // Try lower-case + let toggled = char.toLocaleLowerCase(); + if (toggled === char) { + // Try upper-case + toggled = char.toLocaleUpperCase(); + } + newText += toggled; + } + await TextEditor.replace(range, newText); + } +} + +@RegisterAction +class ToggleCaseVisualBlockOperator extends BaseOperator { + public keys = ["~"]; + public modes = [ModeName.VisualBlock]; + + public async run(vimState: VimState, startPos: Position, endPos: Position): Promise { + for (const { start, end } of Position.IterateLine(vimState)) { + const range = new vscode.Range(start, end); + await ToggleCaseOperator.toggleCase(range); + } + + const cursorPosition = startPos.isBefore(endPos) ? startPos : endPos; + vimState.cursorPosition = cursorPosition; + vimState.cursorStartPosition = cursorPosition; + vimState.currentMode = ModeName.Normal; + + return vimState; + } } @RegisterAction @@ -3626,14 +3653,17 @@ class ToggleCaseWithMotion extends ToggleCaseOperator { } @RegisterAction -class ToggleCaseAndMoveForward extends BaseMovement { +class ToggleCaseAndMoveForward extends BaseCommand { modes = [ModeName.Normal]; keys = ["~"]; + canBeRepeatedWithDot = true; + canBePrefixedWithCount = true; - public async execAction(position: Position, vimState: VimState): Promise { - await new ToggleCaseOperator().run(vimState, position, position); + public async exec(position: Position, vimState: VimState): Promise { + await new ToggleCaseOperator().run(vimState, vimState.cursorPosition, vimState.cursorPosition); - return position.getRight(); + vimState.cursorPosition = vimState.cursorPosition.getRight(); + return vimState; } } diff --git a/test/mode/normalModeTests/dot.test.ts b/test/mode/normalModeTests/dot.test.ts index 65de5ea38..6d7074697 100644 --- a/test/mode/normalModeTests/dot.test.ts +++ b/test/mode/normalModeTests/dot.test.ts @@ -19,10 +19,17 @@ suite("Dot Operator", () => { teardown(cleanUpWorkspace); newTest({ - title: "Can repeat '~'", - start: ['|text'], + title: "Can repeat '~' with ", + start: ['|teXt'], keysPressed: '4~', - end: ['TEX|T'] + end: ['TEx|T'] + }); + + newTest({ + title: "Can repeat '~' with dot", + start: ['|teXt'], + keysPressed: '~...', + end: ['TEx|T'] }); newTest({