Make O (insert line above) match the current line's indentation (#7424)

Fixes #7423
This commit is contained in:
Alex Mai 2022-02-01 13:43:37 -08:00 committed by GitHub
parent 6865b4d2ed
commit 01b9853fc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 119 additions and 6 deletions

2
.vscode/tasks.json vendored
View File

@ -15,7 +15,7 @@
},
{
"type": "gulp",
"task": "build",
"task": "build-dev",
"problemMatcher": []
}
]

View File

@ -1529,17 +1529,35 @@ export class CommandInsertNewLineAbove extends BaseCommand {
await vimState.setCurrentMode(Mode.Insert);
const count = vimState.recordedState.count || 1;
const charPos = position.getLineBeginRespectingIndent(vimState.document).character;
for (let i = 0; i < count; i++) {
await vscode.commands.executeCommand('editor.action.insertLineBefore');
}
vimState.cursors = getCursorsAfterSync(vimState.editor);
for (let i = 0; i < count; i++) {
const newPos = new Position(
vimState.cursors[0].start.line + i,
vimState.cursors[0].start.character
);
const indentAmt = Math.max(charPos - vimState.cursors[0].start.character, 0);
const firstPos = new Position(vimState.cursors[0].start.line, charPos);
vimState.cursors[0] = new Cursor(firstPos, firstPos);
vimState.recordedState.transformer.addTransformation({
type: 'insertText',
text: TextEditor.setIndentationLevel('', indentAmt),
position: firstPos,
cursorIndex: 0,
manuallySetCursorPositions: true,
});
for (let i = 1; i < count; i++) {
const newPos = new Position(vimState.cursors[0].start.line + i, charPos);
vimState.cursors.push(new Cursor(newPos, newPos));
vimState.recordedState.transformer.addTransformation({
type: 'insertText',
text: TextEditor.setIndentationLevel('', indentAmt),
position: newPos,
cursorIndex: i,
manuallySetCursorPositions: true,
});
}
vimState.cursors = vimState.cursors.reverse();
vimState.isFakeMultiCursor = true;

View File

@ -0,0 +1,95 @@
import * as assert from 'assert';
import { Position, window } from 'vscode';
import { getCurrentParagraphBeginning, getCurrentParagraphEnd } from '../../src/textobject/paragraph';
import { WordType } from '../../src/textobject/word';
import { TextEditor } from '../../src/textEditor';
import { assertEqualLines, cleanUpWorkspace, setupWorkspace } from '../testUtils';
import { ModeHandler } from '../../src/mode/modeHandler';
import { getAndUpdateModeHandler } from '../../extension';
import * as vscode from 'vscode';
import { Configuration } from '../testConfiguration';
suite('insertLineBefore', () => {
let modeHandler: ModeHandler;
suiteSetup(async () => {
const configuration = new Configuration();
configuration.tabstop = 4;
configuration.expandtab = true;
await setupWorkspace(configuration);
await setupWorkspace();
modeHandler = (await getAndUpdateModeHandler())!;
});
suiteTeardown(cleanUpWorkspace);
test('tabs are added to match previous line even if line above does not match', async () => {
// Setup the test
await modeHandler.handleMultipleKeyEvents(['<Esc>', 'g', 'g', 'd', 'G']);
await modeHandler.handleMultipleKeyEvents('i\na'.split(''));
await modeHandler.handleMultipleKeyEvents(['<Esc>']);
await modeHandler.handleMultipleKeyEvents('2G>>ob\nc'.split(''));
// This is the current state of the document
//
// a
// b
// c
await modeHandler.handleMultipleKeyEvents(['<Esc>', '2', 'G', 'O', 'a']);
const text = vscode.window.activeTextEditor?.document.getText().split('\n');
assert.ok(text);
assert.strictEqual(text[1].replace(/[\n\r]/g, ''), text[2].replace(/[\n\r]/g, ''));
});
test('no extra whitespace added when insertLineBefore inserts correct amount', async () => {
await modeHandler.handleMultipleKeyEvents(['<Esc>', 'g', 'g', 'd', 'G']);
await modeHandler.handleMultipleKeyEvents('i\na'.split(''));
await modeHandler.handleMultipleKeyEvents(['<Esc>']);
await modeHandler.handleMultipleKeyEvents('2G>>ob\nc'.split(''));
// This is the current state of the document
//
// a
// b
// c
await modeHandler.handleMultipleKeyEvents(['<Esc>', '3', 'G', 'O', 'b']);
const text = vscode.window.activeTextEditor?.document.getText().split('\n');
assert.ok(text);
assert.strictEqual(text[2].replace(/[\n\r]/g, ''), text[3].replace(/[\n\r]/g, ''));
});
test('works at the top of the document', async () => {
await modeHandler.handleMultipleKeyEvents(['<Esc>', 'g', 'g', 'd', 'G']);
await modeHandler.handleMultipleKeyEvents('ia'.split(''));
await modeHandler.handleMultipleKeyEvents(['<Esc>']);
await modeHandler.handleMultipleKeyEvents('gg>>'.split(''));
// This is the current state of the document
// a
await modeHandler.handleMultipleKeyEvents(['<Esc>', 'g', 'g', 'O', 'a']);
const text = vscode.window.activeTextEditor?.document.getText().split('\n');
assert.ok(text);
assert.strictEqual(text[0].replace(/[\n\r]/g, ''), text[1].replace(/[\n\r]/g, ''));
});
test('works with multiple cursors', async () => {
await modeHandler.handleMultipleKeyEvents(['<Esc>', 'g', 'g', 'd', 'G']);
await modeHandler.handleMultipleKeyEvents('oa'.split(''));
await modeHandler.handleMultipleKeyEvents(['<Esc>']);
await modeHandler.handleMultipleKeyEvents('2G>>'.split(''));
// This is the current state of the document
//
// a
await modeHandler.handleMultipleKeyEvents(['<Esc>', '2', 'G', '2', 'O', 'a']);
// After
//
// a
// a
// a
const text = vscode.window.activeTextEditor?.document.getText().split('\n');
assert.ok(text);
assert.strictEqual(text[1].replace(/[\n\r]/g, ''), text[2].replace(/[\n\r]/g, ''));
assert.strictEqual(text[2].replace(/[\n\r]/g, ''), text[3].replace(/[\n\r]/g, ''));
});
});