diff --git a/ROADMAP.md b/ROADMAP.md index 55afca98c1e..dac9bc0387c 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -145,7 +145,8 @@ Status | Command | Description :arrow_down: | `] | 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 -:arrow_down: | `. | 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 +: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 :arrow_down: | :1234: CTRL-O | go to Nth older position in jump list @@ -221,6 +222,7 @@ Status | Command | Description :white_check_mark: | :1234: i | insert text before the cursor (N times) (also: Insert) :white_check_mark: | :1234: I | insert text before the first non-blank in the line (N times) :white_check_mark: | :1234: gI | insert text in column 1 (N times) +:white_check_mark: | gi | insert at the end of the last change :white_check_mark: | :1234: o | open a new line below the current line, append text (N times) :white_check_mark: | :1234: O | open a new line above the current line, append text (N times) diff --git a/src/actions/commands/actions.ts b/src/actions/commands/actions.ts index 0dced5d6b1b..2a019948df5 100644 --- a/src/actions/commands/actions.ts +++ b/src/actions/commands/actions.ts @@ -2119,6 +2119,39 @@ class CommandGoForwardInChangelist extends BaseCommand { } } +@RegisterAction +class CommandGoLastChange extends BaseCommand { + modes = [ModeName.Normal]; + keys = [['`', '.'], ["'", '.']]; + + public async exec(position: Position, vimState: VimState): Promise { + const lastPos = vimState.historyTracker.getLastHistoryStartPosition(); + + if (lastPos !== undefined) { + vimState.cursorPosition = lastPos[0]; + } + + return vimState; + } +} + +@RegisterAction +class CommandInsertAtLastChange extends BaseCommand { + modes = [ModeName.Normal]; + keys = ['g', 'i']; + + public async exec(position: Position, vimState: VimState): Promise { + const lastPos = vimState.historyTracker.getLastChangeEndPosition(); + + if (lastPos !== undefined) { + vimState.cursorPosition = lastPos; + vimState.currentMode = ModeName.Insert; + } + + return vimState; + } +} + @RegisterAction export class CommandInsertAtFirstCharacter extends BaseCommand { modes = [ModeName.Normal, ModeName.Visual]; diff --git a/src/history/historyTracker.ts b/src/history/historyTracker.ts index 25d50584b24..d9526336e24 100644 --- a/src/history/historyTracker.ts +++ b/src/history/historyTracker.ts @@ -548,6 +548,31 @@ export class HistoryTracker { return this.historySteps[this.currentHistoryStepIndex].cursorEnd; } + /** + * Gets the ending cursor position of the last Change of the last Step. + * + * In practice, this sets the cursor position to the end of + * the most recent text change. + */ + getLastChangeEndPosition(): 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].end(); + } + + getLastHistoryStartPosition(): Position[] | undefined { + if (this.currentHistoryStepIndex === 0) { + return undefined; + } + + return this.historySteps[this.currentHistoryStepIndex].cursorStart; + } + setLastHistoryEndPosition(pos: Position[]) { this.historySteps[this.currentHistoryStepIndex].cursorEnd = pos; }