mirror of
https://github.com/VSCodeVim/Vim.git
synced 2024-10-26 12:06:48 +03:00
Fix <C-o>
behavior when cursor is behind last character in INSERT mode or when using p
next (#8949)
Fixes #8948 Fixes #1791
This commit is contained in:
parent
f7a3ff5e30
commit
c8017c8a80
@ -18,6 +18,16 @@ function firstNonBlankChar(text: string): number {
|
||||
return text.match(/\S/)?.index ?? 0;
|
||||
}
|
||||
|
||||
type GetCursorPositionParams = {
|
||||
document: TextDocument;
|
||||
mode: Mode;
|
||||
replaceRange: vscode.Range;
|
||||
registerMode: RegisterMode;
|
||||
count: number;
|
||||
text: string;
|
||||
returnToInsertAfterCommand: boolean;
|
||||
};
|
||||
|
||||
abstract class BasePutCommand extends BaseCommand {
|
||||
modes = [Mode.Normal, Mode.Visual, Mode.VisualLine, Mode.VisualBlock];
|
||||
override createsUndoPoint = true;
|
||||
@ -61,14 +71,15 @@ abstract class BasePutCommand extends BaseCommand {
|
||||
);
|
||||
}
|
||||
|
||||
const newCursorPosition = this.getCursorPosition(
|
||||
vimState.document,
|
||||
const newCursorPosition = this.getCursorPosition({
|
||||
document: vimState.document,
|
||||
returnToInsertAfterCommand: vimState.returnToInsertAfterCommand,
|
||||
mode,
|
||||
replaceRange,
|
||||
registerMode,
|
||||
count,
|
||||
text,
|
||||
);
|
||||
});
|
||||
|
||||
vimState.recordedState.transformer.moveCursor(
|
||||
PositionDiff.exactPosition(newCursorPosition),
|
||||
@ -314,14 +325,7 @@ abstract class BasePutCommand extends BaseCommand {
|
||||
|
||||
protected abstract shouldAdjustIndent(mode: Mode, registerMode: RegisterMode): boolean;
|
||||
|
||||
protected abstract getCursorPosition(
|
||||
document: TextDocument,
|
||||
mode: Mode,
|
||||
replaceRange: vscode.Range,
|
||||
registerMode: RegisterMode,
|
||||
count: number,
|
||||
text: string,
|
||||
): Position;
|
||||
protected abstract getCursorPosition(params: GetCursorPositionParams): Position;
|
||||
}
|
||||
|
||||
@RegisterAction
|
||||
@ -373,18 +377,23 @@ class PutCommand extends BasePutCommand {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected getCursorPosition(
|
||||
document: TextDocument,
|
||||
mode: Mode,
|
||||
replaceRange: vscode.Range,
|
||||
registerMode: RegisterMode,
|
||||
count: number,
|
||||
text: string,
|
||||
): Position {
|
||||
protected getCursorPosition({
|
||||
mode,
|
||||
replaceRange,
|
||||
registerMode,
|
||||
text,
|
||||
returnToInsertAfterCommand,
|
||||
}: GetCursorPositionParams): Position {
|
||||
const rangeStart = replaceRange.start;
|
||||
if (mode === Mode.Normal || mode === Mode.Visual) {
|
||||
if (registerMode === RegisterMode.CharacterWise) {
|
||||
return text.includes('\n') ? rangeStart : rangeStart.advancePositionByText(text).getLeft();
|
||||
if (text.includes('\n')) {
|
||||
return rangeStart;
|
||||
} else if (returnToInsertAfterCommand) {
|
||||
return rangeStart.advancePositionByText(text);
|
||||
} else {
|
||||
return rangeStart.advancePositionByText(text).getLeft();
|
||||
}
|
||||
} else if (registerMode === RegisterMode.LineWise) {
|
||||
return new Position(rangeStart.line + 1, firstNonBlankChar(text));
|
||||
} else if (registerMode === RegisterMode.BlockWise) {
|
||||
@ -445,14 +454,13 @@ class PutBeforeCommand extends PutCommand {
|
||||
return super.getReplaceRange(mode, cursor, registerMode);
|
||||
}
|
||||
|
||||
protected override getCursorPosition(
|
||||
document: TextDocument,
|
||||
mode: Mode,
|
||||
replaceRange: vscode.Range,
|
||||
registerMode: RegisterMode,
|
||||
count: number,
|
||||
text: string,
|
||||
): Position {
|
||||
protected override getCursorPosition({
|
||||
mode,
|
||||
replaceRange,
|
||||
text,
|
||||
registerMode,
|
||||
...params
|
||||
}: GetCursorPositionParams): Position {
|
||||
const rangeStart = replaceRange.start;
|
||||
if (mode === Mode.Normal || mode === Mode.VisualBlock) {
|
||||
if (registerMode === RegisterMode.LineWise) {
|
||||
@ -460,20 +468,21 @@ class PutBeforeCommand extends PutCommand {
|
||||
}
|
||||
}
|
||||
|
||||
return super.getCursorPosition(document, mode, replaceRange, registerMode, count, text);
|
||||
return super.getCursorPosition({ mode, replaceRange, text, registerMode, ...params });
|
||||
}
|
||||
}
|
||||
|
||||
function PlaceCursorAfterText<TBase extends new (...args: any[]) => PutCommand>(Base: TBase) {
|
||||
return class CursorAfterText extends Base {
|
||||
protected override getCursorPosition(
|
||||
document: TextDocument,
|
||||
mode: Mode,
|
||||
replaceRange: vscode.Range,
|
||||
registerMode: RegisterMode,
|
||||
count: number,
|
||||
text: string,
|
||||
): Position {
|
||||
protected override getCursorPosition({
|
||||
document,
|
||||
mode,
|
||||
replaceRange,
|
||||
registerMode,
|
||||
count,
|
||||
text,
|
||||
...params
|
||||
}: GetCursorPositionParams): Position {
|
||||
const rangeStart = replaceRange.start;
|
||||
if (mode === Mode.Normal || mode === Mode.Visual) {
|
||||
if (registerMode === RegisterMode.CharacterWise) {
|
||||
@ -518,7 +527,15 @@ function PlaceCursorAfterText<TBase extends new (...args: any[]) => PutCommand>(
|
||||
}
|
||||
}
|
||||
|
||||
return super.getCursorPosition(document, mode, replaceRange, registerMode, count, text);
|
||||
return super.getCursorPosition({
|
||||
document,
|
||||
mode,
|
||||
replaceRange,
|
||||
registerMode,
|
||||
count,
|
||||
text,
|
||||
...params,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -584,14 +601,10 @@ function ExCommand<TBase extends new (...args: any[]) => PutCommand>(Base: TBase
|
||||
return new vscode.Range(pos, pos);
|
||||
}
|
||||
|
||||
protected override getCursorPosition(
|
||||
document: TextDocument,
|
||||
mode: Mode,
|
||||
replaceRange: vscode.Range,
|
||||
registerMode: RegisterMode,
|
||||
count: number,
|
||||
text: string,
|
||||
): Position {
|
||||
protected override getCursorPosition({
|
||||
replaceRange,
|
||||
text,
|
||||
}: GetCursorPositionParams): Position {
|
||||
const lines = text.split('\n');
|
||||
return new Position(
|
||||
replaceRange.start.line + lines.length - (this.putBefore() ? 1 : 0),
|
||||
|
@ -908,7 +908,7 @@ export class ModeHandler implements vscode.Disposable, IModeHandler {
|
||||
const documentLineCount = this.vimState.document.lineCount;
|
||||
|
||||
this.vimState.cursors = this.vimState.cursors.map((cursor: Cursor) => {
|
||||
// adjust start/stop
|
||||
// Adjust start/stop
|
||||
if (cursor.start.line >= documentLineCount) {
|
||||
cursor = cursor.withNewStart(documentEndPosition);
|
||||
}
|
||||
@ -916,8 +916,13 @@ export class ModeHandler implements vscode.Disposable, IModeHandler {
|
||||
cursor = cursor.withNewStop(documentEndPosition);
|
||||
}
|
||||
|
||||
// adjust column
|
||||
if (this.vimState.currentMode === Mode.Normal || isVisualMode(this.vimState.currentMode)) {
|
||||
// Adjust column. When getting from insert into normal mode with <C-o>,
|
||||
// the cursor position should remain even if it is behind the last
|
||||
// character in the line
|
||||
if (
|
||||
!this.vimState.returnToInsertAfterCommand &&
|
||||
(this.vimState.currentMode === Mode.Normal || isVisualMode(this.vimState.currentMode))
|
||||
) {
|
||||
const currentLineLength = TextEditor.getLineLength(cursor.stop.line);
|
||||
const currentStartLineLength = TextEditor.getLineLength(cursor.start.line);
|
||||
|
||||
|
@ -323,35 +323,81 @@ suite('Mode Insert', () => {
|
||||
endMode: Mode.Normal,
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: 'Can <Esc> after entering insert mode from <ctrl+o>',
|
||||
start: ['|'],
|
||||
keysPressed: 'i<C-o>i<Esc>',
|
||||
end: ['|'],
|
||||
endMode: Mode.Normal,
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: 'Can perform <ctrl+o> to exit and perform one command in normal',
|
||||
start: ['testtest|'],
|
||||
keysPressed: 'a123<C-o>b123',
|
||||
end: ['123|testtest123'],
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: 'Can <ctrl-o> after entering insert mode from <ctrl-o>',
|
||||
start: ['|'],
|
||||
keysPressed: 'i<C-o>i<C-o>',
|
||||
end: ['|'],
|
||||
endMode: Mode.Normal,
|
||||
});
|
||||
|
||||
newTest({
|
||||
title:
|
||||
'Can perform <ctrl+o> to exit and perform one command in normal at the beginning of a row',
|
||||
'Can perform <Esc> to exit and move cursor back one character from the most right position',
|
||||
start: ['|testtest'],
|
||||
keysPressed: 'i<C-o>l123',
|
||||
end: ['t123|esttest'],
|
||||
keysPressed: 'A<Esc>',
|
||||
end: ['testtes|t'],
|
||||
endMode: Mode.Normal,
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: 'Can perform <Esc> to exit and move cursor back one character from middle of text',
|
||||
start: ['test|test'],
|
||||
keysPressed: 'i<Esc>',
|
||||
end: ['tes|ttest'],
|
||||
endMode: Mode.Normal,
|
||||
});
|
||||
|
||||
suite('<C-o>', () => {
|
||||
newTest({
|
||||
title: 'Can <Esc> after entering insert mode from <ctrl+o>',
|
||||
start: ['|'],
|
||||
keysPressed: 'i<C-o>i<Esc>',
|
||||
end: ['|'],
|
||||
endMode: Mode.Normal,
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: 'Can perform <ctrl-o> after entering insert mode from <ctrl-o>',
|
||||
start: ['test|test'],
|
||||
keysPressed: 'i<C-o>i<C-o>',
|
||||
end: ['test|test'],
|
||||
endMode: Mode.Normal,
|
||||
});
|
||||
|
||||
newTest({
|
||||
title:
|
||||
'Can perform <ctrl-o> to exit and perform one command in normal at the beginning of a line',
|
||||
start: ['|testtest'],
|
||||
keysPressed: 'i<C-o>l123',
|
||||
end: ['t123|esttest'],
|
||||
endMode: Mode.Insert,
|
||||
});
|
||||
|
||||
newTest({
|
||||
title:
|
||||
'Can perform <ctrl-o> to exit and perform one command in normal at the middle of a row',
|
||||
start: ['test|test'],
|
||||
keysPressed: 'i<C-o>l123',
|
||||
end: ['testt123|est'],
|
||||
endMode: Mode.Insert,
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: 'Can perform <ctrl-o> to exit and perform one command in normal at the end of a row',
|
||||
start: ['testtest|'],
|
||||
keysPressed: 'a123<C-o>zz',
|
||||
end: ['testtest123|'],
|
||||
endMode: Mode.Insert,
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: 'Can perform <ctrl-o> to exit and paste',
|
||||
start: ['|XXX', '123456'],
|
||||
keysPressed: 'ye' + 'j' + 'A<C-o>p',
|
||||
end: ['XXX', '123456XXX|'],
|
||||
endMode: Mode.Insert,
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: 'Can perform <ctrl-o> to exit and paste',
|
||||
start: ['|XXX', '123456'],
|
||||
keysPressed: 'ye' + 'j2|' + 'i<C-o>p',
|
||||
end: ['XXX', '12XXX|3456'],
|
||||
endMode: Mode.Insert,
|
||||
});
|
||||
});
|
||||
|
||||
newTest({
|
||||
|
Loading…
Reference in New Issue
Block a user