mirror of
https://github.com/VSCodeVim/Vim.git
synced 2024-08-17 00:00:26 +03:00
Support [ and
] commands to go to start / end of previously operated text (#4147)
Fixes #2004
This commit is contained in:
parent
e7f1cd7f42
commit
bce62a759d
24
ROADMAP.md
24
ROADMAP.md
@ -132,25 +132,27 @@ Now follows an exhaustive list of every known Vim command that we could find.
|
||||
|
||||
## Marks and motions
|
||||
|
||||
| Status | Command | Description |
|
||||
| ------------------ | ----------------------------------------------------------- | -------------------------------------------------- |
|
||||
| :white_check_mark: | m{a-zA-Z} | mark current position with mark {a-zA-Z} |
|
||||
| Status | Command | Description |
|
||||
| ------------------ | ----------------------------------------------------------- | ------------------------------------------------------ |
|
||||
| :white_check_mark: | m{a-zA-Z} | mark current position with mark {a-zA-Z} |
|
||||
| :white_check_mark: | `{a-z} | go to mark {a-z} within current file |
|
||||
| :white_check_mark: | `{A-Z} | go to mark {A-Z} in any file |
|
||||
| :white_check_mark: | `{0-9} | go to the position where Vim was previously exited |
|
||||
| :white_check_mark: | `` | go to the position before the last jump |
|
||||
| :arrow_down: | `" | go to the position when last editing this file |
|
||||
| :arrow_down: | `[ | go to the start of the previously operated or put text |
|
||||
| :arrow_down: | `] | go to the end of the previously operated or put text |
|
||||
| :white_check_mark: | `[ | go to the start of the previously operated or put text |
|
||||
| :white_check_mark: | '[ | go to the start of the previously operated or put text |
|
||||
| :white_check_mark: | `] | go to the end of the previously operated or put text |
|
||||
| :white_check_mark: | '] | go to the end of the previously operated or put text |
|
||||
| :arrow_down: | `< | go to the start of the (previous) Visual area |
|
||||
| :arrow_down: | `> | go to the end of the (previous) Visual area |
|
||||
| :white_check_mark: | `. | go to the position of the last change in this file |
|
||||
| :white_check_mark: | '. | go to the position of the last change in this file |
|
||||
| :arrow_down: | '{a-zA-Z0-9[]'"<>.} | same as `, but on the first non-blank in the line |
|
||||
| :arrow_down: | :marks | print the active marks |
|
||||
| :white_check_mark: | :1234: CTRL-O | go to Nth older position in jump list |
|
||||
| :white_check_mark: | :1234: CTRL-I | go to Nth newer position in jump list |
|
||||
| :arrow_down: | :ju[mps] | print the jump list |
|
||||
| :white_check_mark: | '. | go to the position of the last change in this file |
|
||||
| :arrow_down: | '{a-zA-Z0-9[]'"<>.} | same as `, but on the first non-blank in the line |
|
||||
| :arrow_down: | :marks | print the active marks |
|
||||
| :white_check_mark: | :1234: CTRL-O | go to Nth older position in jump list |
|
||||
| :white_check_mark: | :1234: CTRL-I | go to Nth newer position in jump list |
|
||||
| :arrow_down: | :ju[mps] | print the jump list |
|
||||
|
||||
## Various motions
|
||||
|
||||
|
@ -3008,6 +3008,38 @@ class CommandGoForwardInChangelist extends BaseCommand {
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterAction
|
||||
class CommandGoStartPrevOperatedText extends BaseCommand {
|
||||
modes = [ModeName.Normal, ModeName.Visual, ModeName.VisualLine, ModeName.VisualBlock];
|
||||
keys = [['`', '['], ["'", '[']];
|
||||
isJump = true;
|
||||
|
||||
public async exec(position: Position, vimState: VimState): Promise<VimState> {
|
||||
const lastPos = vimState.historyTracker.getLastChangeStartPosition();
|
||||
if (lastPos !== undefined) {
|
||||
vimState.cursorStopPosition = lastPos;
|
||||
}
|
||||
|
||||
return vimState;
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterAction
|
||||
class CommandGoEndPrevOperatedText extends BaseCommand {
|
||||
modes = [ModeName.Normal, ModeName.Visual, ModeName.VisualLine, ModeName.VisualBlock];
|
||||
keys = [['`', ']'], ["'", ']']];
|
||||
isJump = true;
|
||||
|
||||
public async exec(position: Position, vimState: VimState): Promise<VimState> {
|
||||
const lastPos = vimState.historyTracker.getLastChangeEndPosition();
|
||||
if (lastPos !== undefined) {
|
||||
vimState.cursorStopPosition = lastPos;
|
||||
}
|
||||
|
||||
return vimState;
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterAction
|
||||
class CommandGoLastChange extends BaseCommand {
|
||||
modes = [ModeName.Normal];
|
||||
|
@ -667,11 +667,18 @@ export class HistoryTracker {
|
||||
if (this.currentHistoryStepIndex === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const lastChangeIndex = this.historySteps[this.currentHistoryStepIndex].changes.length;
|
||||
if (lastChangeIndex === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return this.historySteps[this.currentHistoryStepIndex].changes[lastChangeIndex - 1].end();
|
||||
|
||||
const lastChange = this.historySteps[this.currentHistoryStepIndex].changes[lastChangeIndex - 1];
|
||||
if (lastChange.isAdd) {
|
||||
return lastChange.end();
|
||||
}
|
||||
|
||||
return lastChange.start;
|
||||
}
|
||||
|
||||
getLastHistoryStartPosition(): Position[] | undefined {
|
||||
@ -682,6 +689,19 @@ export class HistoryTracker {
|
||||
return this.historySteps[this.currentHistoryStepIndex].cursorStart;
|
||||
}
|
||||
|
||||
getLastChangeStartPosition(): Position | undefined {
|
||||
if (this.currentHistoryStepIndex === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const lastChangeIndex = this.historySteps[this.currentHistoryStepIndex].changes.length;
|
||||
if (lastChangeIndex === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.historySteps[this.currentHistoryStepIndex].changes[lastChangeIndex - 1].start;
|
||||
}
|
||||
|
||||
setLastHistoryEndPosition(pos: Position[]) {
|
||||
this.historySteps[this.currentHistoryStepIndex].cursorEnd = pos;
|
||||
}
|
||||
|
@ -2071,6 +2071,34 @@ suite('Mode Normal', () => {
|
||||
endMode: ModeName.Normal,
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: '`] go to the end of the previously operated or put text',
|
||||
start: ['hello|'],
|
||||
keysPressed: 'a world<Esc>`]',
|
||||
end: ['hello worl|d'],
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: "'] go to the end of the previously operated or put text",
|
||||
start: ['hello|'],
|
||||
keysPressed: "a world<Esc>']",
|
||||
end: ['hello worl|d'],
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: '`[ go to the start of the previously operated or put text',
|
||||
start: ['hello|'],
|
||||
keysPressed: 'a world<Esc>`[',
|
||||
end: ['hello| world'],
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: "'[ go to the start of the previously operated or put text",
|
||||
start: ['hello|'],
|
||||
keysPressed: "a world<Esc>'[",
|
||||
end: ['hello| world'],
|
||||
});
|
||||
|
||||
suite('can handle gn', () => {
|
||||
test(`gn selects the next match text`, async () => {
|
||||
await modeHandler.handleMultipleKeyEvents('ifoo\nhello world\nhello\nhello'.split(''));
|
||||
|
Loading…
Reference in New Issue
Block a user