(recordedState: RecordedState, action: IBaseAction)
| 730 | } |
| 731 | |
| 732 | private async runAction(recordedState: RecordedState, action: IBaseAction): Promise<void> { |
| 733 | this.internalSelectionsTracker.startIgnoringIntermediateSelections(); |
| 734 | |
| 735 | // We handle the end of selections different to VSCode. In order for VSCode to select |
| 736 | // including the last character we will at the end of 'runAction' shift our stop position |
| 737 | // to the right. So here we shift it back by one so that our actions have our correct |
| 738 | // position instead of the position sent to VSCode. |
| 739 | if (this.vimState.currentMode === Mode.Visual) { |
| 740 | this.vimState.cursors = this.vimState.cursors.map((c) => |
| 741 | c.start.isBefore(c.stop) ? c.withNewStop(c.stop.getLeftThroughLineBreaks(true)) : c, |
| 742 | ); |
| 743 | } |
| 744 | |
| 745 | // Make sure all cursors are within the document's bounds before running any action |
| 746 | // It's not 100% clear to me that this is the correct place to do this, but it should solve a lot of issues |
| 747 | this.vimState.cursors = this.vimState.cursors.map((c) => c.validate(this.vimState.document)); |
| 748 | |
| 749 | let ranRepeatableAction = false; |
| 750 | let ranAction = false; |
| 751 | |
| 752 | if (action instanceof BaseMovement) { |
| 753 | recordedState = await this.executeMovement(action); |
| 754 | ranAction = true; |
| 755 | } else if (action instanceof BaseCommand) { |
| 756 | await action.execCount(this.vimState.cursorStopPosition, this.vimState); |
| 757 | |
| 758 | const transformer = this.vimState.recordedState.transformer; |
| 759 | await executeTransformations(this, transformer.transformations); |
| 760 | |
| 761 | if (action.isCompleteAction) { |
| 762 | ranAction = true; |
| 763 | } |
| 764 | |
| 765 | if (action.createsUndoPoint) { |
| 766 | ranRepeatableAction = true; |
| 767 | } |
| 768 | |
| 769 | if (this.vimState.normalCommandState === NormalCommandState.Finished) { |
| 770 | ranRepeatableAction = true; |
| 771 | } |
| 772 | } else if (action instanceof BaseOperator) { |
| 773 | recordedState.operatorCount = recordedState.count; |
| 774 | } else { |
| 775 | throw new Error('Unknown action type'); |
| 776 | } |
| 777 | |
| 778 | // Update mode (note the ordering allows you to go into search mode, |
| 779 | // then return and have the motion immediately applied to an operator). |
| 780 | const prevMode = this.currentMode; |
| 781 | if (this.vimState.currentMode !== this.currentMode) { |
| 782 | await this.setCurrentMode(this.vimState.currentMode); |
| 783 | |
| 784 | // We don't want to mark any searches as a repeatable action |
| 785 | if ( |
| 786 | this.vimState.currentMode === Mode.Normal && |
| 787 | prevMode !== Mode.SearchInProgressMode && |
| 788 | prevMode !== Mode.EasyMotionInputMode && |
| 789 | prevMode !== Mode.EasyMotionMode && |
no test coverage detected