diff --git a/src/actions/actions.ts b/src/actions/actions.ts index c46e7870198..a146a54662d 100644 --- a/src/actions/actions.ts +++ b/src/actions/actions.ts @@ -2794,6 +2794,46 @@ class CommandGoToDefinition extends BaseCommand { } } +@RegisterAction +class CommandGoBackInChangelist extends BaseCommand { + modes = [ModeName.Normal]; + keys = ["g", ";"]; + + public async exec(position: Position, vimState: VimState): Promise { + const originalIndex = vimState.historyTracker.changelistIndex; + const prevPos = vimState.historyTracker.getChangePositionAtindex(originalIndex); + + if (prevPos !== undefined) { + vimState.cursorPosition = prevPos[0]; + if (vimState.historyTracker.getChangePositionAtindex(originalIndex - 1) !== undefined) { + vimState.historyTracker.changelistIndex = originalIndex - 1; + } + } + + return vimState; + } +} + +@RegisterAction +class CommandGoForwardInChangelist extends BaseCommand { + modes = [ModeName.Normal]; + keys = ["g", ","]; + + public async exec(position: Position, vimState: VimState): Promise { + const originalIndex = vimState.historyTracker.changelistIndex; + const nextPos = vimState.historyTracker.getChangePositionAtindex(originalIndex); + + if (nextPos !== undefined) { + vimState.cursorPosition = nextPos[0]; + if (vimState.historyTracker.getChangePositionAtindex(originalIndex + 1) !== undefined) { + vimState.historyTracker.changelistIndex = originalIndex + 1; + } + } + + return vimState; + } +} + // begin insert commands @RegisterAction diff --git a/src/history/historyTracker.ts b/src/history/historyTracker.ts index a076e23f7d5..2ca8f1fe6c5 100644 --- a/src/history/historyTracker.ts +++ b/src/history/historyTracker.ts @@ -157,6 +157,9 @@ export class HistoryTracker { public lastContentChanges: vscode.TextDocumentContentChangeEvent[]; public currentContentChanges: vscode.TextDocumentContentChangeEvent[]; + // Current index in changelist for navigation, resets when a new change is made + public changelistIndex = 0; + public lastInvokedMacro: RecordedState; /** @@ -408,6 +411,9 @@ export class HistoryTracker { this.currentHistoryStep.cursorEnd = cursorPosition; this.oldText = newText; + + // A change has been made, reset the changelist navigation index to the end + this.changelistIndex = this.historySteps.length - 1; } /** @@ -518,6 +524,27 @@ export class HistoryTracker { this.historySteps[this.currentHistoryStepIndex].cursorEnd = pos; } + getChangePositionAtindex(index: number): Position[] | undefined { + if (this.currentHistoryStepIndex === 0) { + return undefined; + } + + let pos = this.getLastHistoryEndPosition(); + pos = undefined; + + if (this.historySteps[index] !== undefined) { + if (this.historySteps[index].changes.length > 0) { + if (this.historySteps[index].changes[0].isAdd) { + pos = [this.historySteps[index].changes[0].end()]; + } else { + pos = [this.historySteps[index].changes[0].start]; + } + } + } + + return pos; + } + /** * Handy for debugging the undo/redo stack. + means our current position, check * means active.