mirror of
https://github.com/VSCodeVim/Vim.git
synced 2024-08-16 15:50:35 +03:00
parent
7a148f519d
commit
5f6ef5fada
@ -355,8 +355,8 @@ moving around:
|
||||
| :white_check_mark: | g~{motion} | switch case for the text that is moved over with {motion} |
|
||||
| :white_check_mark: | gu{motion} | make the text that is moved over with {motion} lowercase |
|
||||
| :white_check_mark: | gU{motion} | make the text that is moved over with {motion} uppercase |
|
||||
| :arrow_down: | {visual}g? | perform rot13 encoding on highlighted text |
|
||||
| :arrow_down: | g?{motion} | perform rot13 encoding on the text that is moved over with {motion} |
|
||||
| :white_check_mark: | {visual}g? | perform rot13 encoding on highlighted text |
|
||||
| :white_check_mark: | g?{motion} | perform rot13 encoding on the text that is moved over with {motion} |
|
||||
| :white_check_mark: | :1234: CTRL-A | add N to the number at or after the cursor |
|
||||
| :white_check_mark: | :1234: CTRL-X | subtract N from the number at or after the cursor |
|
||||
| :white_check_mark: | :1234: <{motion} | move the lines that are moved over with {motion} one shiftwidth left |
|
||||
|
@ -1397,6 +1397,13 @@ export class CommandSearchBackwards extends BaseCommand {
|
||||
isMotion = true;
|
||||
isJump = true;
|
||||
|
||||
public doesActionApply(vimState: VimState, keysPressed: string[]): boolean {
|
||||
// Prevent collision with `g?` (rot13 operator)
|
||||
return (
|
||||
super.doesActionApply(vimState, keysPressed) && vimState.recordedState.operator === undefined
|
||||
);
|
||||
}
|
||||
|
||||
public async exec(position: Position, vimState: VimState): Promise<VimState> {
|
||||
globalState.searchState = new SearchState(
|
||||
SearchDirection.Backward,
|
||||
|
@ -3,7 +3,7 @@ import * as vscode from 'vscode';
|
||||
import { Position, PositionDiff } from './../common/motion/position';
|
||||
import { Range } from './../common/motion/range';
|
||||
import { configuration } from './../configuration/configuration';
|
||||
import { Mode } from './../mode/mode';
|
||||
import { Mode, isVisualMode } from './../mode/mode';
|
||||
import { Register, RegisterMode } from './../register/register';
|
||||
import { VimState } from './../state/vimState';
|
||||
import { TextEditor } from './../textEditor';
|
||||
@ -783,6 +783,59 @@ export class CommentOperator extends BaseOperator {
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterAction
|
||||
export class ROT13Operator extends BaseOperator {
|
||||
public keys = ['g', '?'];
|
||||
public modes = [Mode.Normal, Mode.Visual, Mode.VisualLine, Mode.VisualBlock];
|
||||
|
||||
public async run(vimState: VimState, start: Position, end: Position): Promise<VimState> {
|
||||
let selections: vscode.Selection[];
|
||||
if (isVisualMode(vimState.currentMode)) {
|
||||
selections = vimState.editor.selections;
|
||||
} else if (vimState.currentRegisterMode === RegisterMode.LineWise) {
|
||||
selections = [new vscode.Selection(start.getLineBegin(), end.getLineEnd())];
|
||||
} else {
|
||||
selections = [new vscode.Selection(start, end.getRight())];
|
||||
}
|
||||
|
||||
for (const range of selections) {
|
||||
const original = TextEditor.getText(range);
|
||||
vimState.recordedState.transformations.push({
|
||||
type: 'replaceText',
|
||||
text: ROT13Operator.rot13(original),
|
||||
start: Position.FromVSCodePosition(range.start),
|
||||
end: Position.FromVSCodePosition(range.end),
|
||||
});
|
||||
}
|
||||
|
||||
return vimState;
|
||||
}
|
||||
|
||||
/**
|
||||
* https://en.wikipedia.org/wiki/ROT13
|
||||
*/
|
||||
public static rot13(str: string) {
|
||||
return str
|
||||
.split('')
|
||||
.map((char: string) => {
|
||||
let charCode = char.charCodeAt(0);
|
||||
|
||||
if (char >= 'a' && char <= 'z') {
|
||||
const a = 'a'.charCodeAt(0);
|
||||
charCode = ((charCode - a + 13) % 26) + a;
|
||||
}
|
||||
|
||||
if (char >= 'A' && char <= 'Z') {
|
||||
const A = 'A'.charCodeAt(0);
|
||||
charCode = ((charCode - A + 13) % 26) + A;
|
||||
}
|
||||
|
||||
return String.fromCharCode(charCode);
|
||||
})
|
||||
.join('');
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterAction
|
||||
export class CommentBlockOperator extends BaseOperator {
|
||||
public keys = ['g', 'C'];
|
||||
|
@ -49,7 +49,8 @@ export class SneakForward extends BaseMovement {
|
||||
|
||||
const ignorecase =
|
||||
configuration.sneakUseIgnorecaseAndSmartcase &&
|
||||
configuration.ignorecase && !(configuration.smartcase && /[A-Z]/.test(searchString));
|
||||
configuration.ignorecase &&
|
||||
!(configuration.smartcase && /[A-Z]/.test(searchString));
|
||||
|
||||
// Check for matches
|
||||
if (ignorecase) {
|
||||
@ -112,7 +113,8 @@ export class SneakBackward extends BaseMovement {
|
||||
|
||||
const ignorecase =
|
||||
configuration.sneakUseIgnorecaseAndSmartcase &&
|
||||
configuration.ignorecase && !(configuration.smartcase && /[A-Z]/.test(searchString));
|
||||
configuration.ignorecase &&
|
||||
!(configuration.smartcase && /[A-Z]/.test(searchString));
|
||||
|
||||
// Check for matches
|
||||
if (ignorecase) {
|
||||
|
@ -45,10 +45,7 @@ class VimrcImpl {
|
||||
const mappings = (() => {
|
||||
switch (remap.keyRemappingType) {
|
||||
case 'map':
|
||||
return [
|
||||
config.normalModeKeyBindings,
|
||||
config.visualModeKeyBindings,
|
||||
];
|
||||
return [config.normalModeKeyBindings, config.visualModeKeyBindings];
|
||||
case 'nmap':
|
||||
return [config.normalModeKeyBindings];
|
||||
case 'vmap':
|
||||
|
@ -113,11 +113,11 @@ export class RecordedState {
|
||||
*/
|
||||
public get operator(): BaseOperator {
|
||||
let list = this.actionsRun.filter(a => a instanceof BaseOperator).reverse();
|
||||
return list[0] as any;
|
||||
return list[0] as BaseOperator;
|
||||
}
|
||||
|
||||
public get operators(): BaseOperator[] {
|
||||
return this.actionsRun.filter(a => a instanceof BaseOperator).reverse() as any;
|
||||
return this.actionsRun.filter(a => a instanceof BaseOperator).reverse() as BaseOperator[];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,7 +128,7 @@ export class RecordedState {
|
||||
|
||||
// TODO - disregard <Esc>, then assert this is of length 1.
|
||||
|
||||
return list[0] as any;
|
||||
return list[0] as BaseCommand;
|
||||
}
|
||||
|
||||
public get hasRunAMovement(): boolean {
|
||||
@ -167,7 +167,8 @@ export class RecordedState {
|
||||
mode !== Mode.SearchInProgressMode &&
|
||||
mode !== Mode.CommandlineInProgress &&
|
||||
(this.hasRunAMovement ||
|
||||
mode === Mode.Visual || mode === Mode.VisualLine ||
|
||||
mode === Mode.Visual ||
|
||||
mode === Mode.VisualLine ||
|
||||
(this.operators.length > 1 &&
|
||||
this.operators.reverse()[0].constructor === this.operators.reverse()[1].constructor))
|
||||
);
|
||||
|
@ -21,7 +21,11 @@ suite('Horizontal split', () => {
|
||||
await commandLine.Run(cmd, modeHandler.vimState);
|
||||
await WaitForEditorsToClose(2);
|
||||
|
||||
assert.strictEqual(vscode.window.visibleTextEditors.length, 2, 'Editor did not split in 1 sec');
|
||||
assert.strictEqual(
|
||||
vscode.window.visibleTextEditors.length,
|
||||
2,
|
||||
'Editor did not split in 1 sec'
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -21,7 +21,11 @@ suite('Vertical split', () => {
|
||||
await commandLine.Run(cmd, modeHandler.vimState);
|
||||
await WaitForEditorsToClose(2);
|
||||
|
||||
assert.strictEqual(vscode.window.visibleTextEditors.length, 2, 'Editor did not split in 1 sec');
|
||||
assert.strictEqual(
|
||||
vscode.window.visibleTextEditors.length,
|
||||
2,
|
||||
'Editor did not split in 1 sec'
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
56
test/operator/rot13.test.ts
Normal file
56
test/operator/rot13.test.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import * as assert from 'assert';
|
||||
|
||||
import { getTestingFunctions } from '../testSimplifier';
|
||||
|
||||
import { setupWorkspace, cleanUpWorkspace } from '../testUtils';
|
||||
import { ROT13Operator } from '../../src/actions/operator';
|
||||
|
||||
suite('rot13 operator', () => {
|
||||
const { newTest, newTestOnly, newTestSkip } = getTestingFunctions();
|
||||
|
||||
setup(async () => {
|
||||
await setupWorkspace();
|
||||
});
|
||||
|
||||
teardown(cleanUpWorkspace);
|
||||
|
||||
test('rot13() unit test', () => {
|
||||
const testCases = [
|
||||
['abcdefghijklmnopqrstuvwxyz', 'nopqrstuvwxyzabcdefghijklm'],
|
||||
['ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'NOPQRSTUVWXYZABCDEFGHIJKLM'],
|
||||
['!@#$%^&*()', '!@#$%^&*()'],
|
||||
['âéü', 'âéü'],
|
||||
];
|
||||
for (const [input, output] of testCases) {
|
||||
assert.strictEqual(ROT13Operator.rot13(input), output);
|
||||
}
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: 'g?j works',
|
||||
start: ['a|bc', 'def', 'ghi'],
|
||||
keysPressed: 'g?j',
|
||||
end: ['n|op', 'qrs', 'ghi'],
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: 'g? in visual mode works',
|
||||
start: ['a|bc', 'def', 'ghi'],
|
||||
keysPressed: 'vj$g?',
|
||||
end: ['a|op', 'qrs', 'ghi'],
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: 'g? in visual line mode works',
|
||||
start: ['a|bc', 'def', 'ghi'],
|
||||
keysPressed: 'Vj$g?',
|
||||
end: ['|nop', 'qrs', 'ghi'],
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: 'g? in visual block mode works',
|
||||
start: ['a|bc', 'def', 'ghi'],
|
||||
keysPressed: '<C-v>j$g?',
|
||||
end: ['a|op', 'drs', 'ghi'],
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user