More fixes to gv

This commit is contained in:
Jason Fields 2024-04-07 12:39:33 -04:00
parent 8d9b2b9b2f
commit 5afc95ee02
3 changed files with 61 additions and 26 deletions

View File

@ -936,17 +936,19 @@ class CommandVisualMode extends BaseCommand {
}
@RegisterAction
class CommandReselectVisual extends BaseCommand {
class RestoreVisualSelection extends BaseCommand {
modes = [Mode.Normal];
keys = ['g', 'v'];
public override async exec(position: Position, vimState: VimState): Promise<void> {
// Try to restore selection only if valid
if (vimState.lastVisualSelection !== undefined) {
let { start, end, mode } = vimState.lastVisualSelection;
if (vimState.lastVisualSelection === undefined) {
return;
}
let { start, end, mode } = vimState.lastVisualSelection;
if (mode !== Mode.Visual || !start.isEqual(end)) {
if (end.line <= vimState.document.lineCount - 1) {
if (mode === Mode.Visual && start.isBeforeOrEqual(end)) {
if (mode === Mode.Visual && start.isBefore(end)) {
end = end.getLeftThroughLineBreaks(true);
}

View File

@ -532,26 +532,37 @@ export class HistoryTracker {
if (this.vimState.lastVisualSelection) {
this.vimState.lastVisualSelection.start = position;
} else {
// TODO: Not quite right: only "< should be set.
this.vimState.lastVisualSelection = {
mode: Mode.Visual,
start: position,
end: position.getRight(),
end: position,
};
}
// TODO: Ensure "> is always after "<
if (
this.vimState.lastVisualSelection.mode === Mode.Visual &&
this.vimState.lastVisualSelection.end.isBefore(this.vimState.lastVisualSelection.start)
) {
// HACK: Visual mode representation is stupid
this.vimState.lastVisualSelection.end = this.vimState.lastVisualSelection.start;
}
} else if (markName === '>') {
if (this.vimState.lastVisualSelection) {
this.vimState.lastVisualSelection.end = position.getRight();
} else {
// TODO: Not quite right: only "> should be set.
this.vimState.lastVisualSelection = {
mode: Mode.Visual,
start: position,
start: position.getRight(),
end: position.getRight(),
};
}
// TODO: Ensure "< is always before ">
if (
this.vimState.lastVisualSelection.mode === Mode.Visual &&
this.vimState.lastVisualSelection.start.isAfter(this.vimState.lastVisualSelection.end)
) {
// HACK: Visual mode representation is stupid
this.vimState.lastVisualSelection.start = this.vimState.lastVisualSelection.end.getLeft();
this.vimState.lastVisualSelection.end = this.vimState.lastVisualSelection.start;
}
} else {
const isUppercaseMark = markName.toUpperCase() === markName;
const newMark: IMark = {

View File

@ -44,44 +44,42 @@ suite('Marks', async () => {
endMode: Mode.Normal,
});
suite('"< and ">', () => {
suite("'< and '>", () => {
newTest({
title: '"< set by Visual mode',
title: "'< set by Visual mode",
start: ['one', 't|wo', 'three'],
keysPressed: 'vjl<Esc>' + 'gg' + '`<',
end: ['one', 't|wo', 'three'],
});
newTest({
title: '"> set by Visual mode',
title: "'> set by Visual mode",
start: ['one', 't|wo', 'three'],
keysPressed: 'vjl<Esc>' + 'gg' + '`>',
end: ['one', 'two', 'th|ree'],
});
newTest({
title: '"< set by m<',
title: "'< set by m<",
start: ['one', 't|wo', 'three'],
keysPressed: 'm<' + 'gg' + '`<',
end: ['one', 't|wo', 'three'],
});
newTest({
title: '"> set by m>',
title: "'> set by m>",
start: ['one', 't|wo', 'three'],
keysPressed: 'm>' + 'gg' + '`>',
end: ['one', 't|wo', 'three'],
});
newTestSkip({
// TODO
title: 'gv fails if "< is not set',
newTest({
title: "gv fails if '< is not set",
start: ['one', 't|wo', 'three'],
keysPressed: 'm>' + 'gg' + 'gv',
end: ['|one', 'two', 'three'],
endMode: Mode.Normal,
});
newTestSkip({
// TODO
title: 'gv fails if "> is not set',
newTest({
title: "gv fails if '> is not set",
start: ['one', 't|wo', 'three'],
keysPressed: 'm<' + 'gg' + 'gv',
end: ['|one', 'two', 'three'],
@ -91,17 +89,41 @@ suite('Marks', async () => {
newTest({
title: 'gv is affected by m<',
start: ['one', 't|wo', 'three'],
keysPressed: 'v<Esc>' + 'k' + 'm<' + 'G' + 'gvd',
keysPressed: 'v<Esc>' + 'k' + 'm<' + 'gg' + 'gvd',
end: ['o|o', 'three'],
});
newTest({
title: 'gv is affected by m>',
start: ['one', 't|wo', 'three'],
keysPressed: 'v<Esc>' + 'j' + 'm>' + 'G' + 'gvd',
keysPressed: 'v<Esc>' + 'j' + 'm>' + 'gg' + 'gvd',
end: ['one', 't|ree'],
});
newTestSkip({
// TODO: Seems to work... why does this fail?
title: 'gv is affected by m< and m>',
start: ['one', 't|wo', 'three'],
keysPressed: 'm<' + 'j' + 'm>' + 'gg' + 'gvd',
end: ['one', 't|ree'],
});
// TODO: If m> AFTER "<: "< set to "> and gv fails
// TODO: If m< AFTER ">: "> set to "< and gv fails
newTest({
title: "m< AFTER '> sets '> too",
start: ['one', 't|wo', 'three'],
keysPressed: 'v<Esc>' + 'j' + 'm<' + 'gg' + '`>',
end: ['one', 'two', 't|hree'],
});
newTest({
title: "m> BEFORE '< sets '< too",
start: ['one', 't|wo', 'three'],
keysPressed: 'v<Esc>' + 'k' + 'm>' + 'gg' + '`<',
end: ['o|ne', 'two', 'three'],
});
newTest({
title: "gv fails if '< is after '>",
start: ['one', 't|wo', 'three'],
keysPressed: 'v<Esc>' + 'j' + 'm<' + 'gg' + 'gv',
end: ['|one', 'two', 'three'],
endMode: Mode.Normal,
});
});
});