From 9fbd5a152f691d09c0523a6f044a29deb5d4dfd1 Mon Sep 17 00:00:00 2001 From: berknam Date: Tue, 30 Jun 2020 03:27:00 +0100 Subject: [PATCH] Implement the rest of the surround plugin - Implement the following keys from the surround plugin: 'cS', 'yS' (operator), 'ySs', 'ySS' (same as 'ySs') and 'gS' (visual mode) - Now the only missing parts of surround plugin is the insert mode mappings, but those aren't that important anyway. - Still missing tests for these new actions --- src/actions/plugins/surround.ts | 110 +++++++++++++++++++++++++++++--- src/state/vimState.ts | 1 + 2 files changed, 103 insertions(+), 8 deletions(-) diff --git a/src/actions/plugins/surround.ts b/src/actions/plugins/surround.ts index 7caa5e846112..14c761abb958 100644 --- a/src/actions/plugins/surround.ts +++ b/src/actions/plugins/surround.ts @@ -122,7 +122,8 @@ async function StartSurroundMode( operatorString: 'change' | 'delete' | 'yank' | undefined = undefined, keys: string[], start: Position | undefined, - end: Position | undefined + end: Position | undefined, + registerMode: RegisterMode | undefined ): Promise { // Only execute the action if the configuration is set if (!configuration.surround || !operatorString || keys.length === 0) { @@ -151,6 +152,7 @@ async function StartSurroundMode( replacement: undefined, range: range, previousMode: vimState.currentMode, + forcedRegisterMode: registerMode, }; if (operatorString === 'yank' && start) { @@ -180,7 +182,14 @@ class BaseSurroundCommand extends BaseCommand { if (!this.operatorString || this.keys.length === 0) { return vimState; } - return StartSurroundMode(vimState, this.operatorString, this.keys, undefined, undefined); + return StartSurroundMode( + vimState, + this.operatorString, + this.keys, + undefined, + undefined, + undefined + ); } public doesActionApply(vimState: VimState, keysPressed: string[]): boolean { @@ -200,6 +209,25 @@ class CommandChangeSurround extends BaseSurroundCommand { operatorString: 'change' | 'delete' | 'yank' | undefined = 'change'; } +@RegisterPluginAction('surround') +class CommandChangeSurroundWithLineBreaks extends BaseSurroundCommand { + modes = [Mode.Normal]; + pluginActionDefaultKeys = ['c', 'S']; + keys = ['CSurround']; + operatorString: 'change' | 'delete' | 'yank' | undefined = 'change'; + + public async exec(position: Position, vimState: VimState): Promise { + return StartSurroundMode( + vimState, + 'change', + this.keys, + undefined, + undefined, + RegisterMode.LineWise + ); + } +} + @RegisterPluginAction('surround') class CommandDeleteSurround extends BaseSurroundCommand { modes = [Mode.Normal]; @@ -220,7 +248,23 @@ class CommandSurroundModeStartVisual extends BaseSurroundCommand { if (vimState.currentMode === Mode.VisualLine) { [start, end] = [start.getLineBegin(), end.getLineEnd()]; } - return StartSurroundMode(vimState, 'yank', this.keys, start, end); + return StartSurroundMode(vimState, 'yank', this.keys, start, end, undefined); + } +} + +@RegisterPluginAction('surround') +class CommandSurroundModeStartVisualWithLineBreaks extends BaseSurroundCommand { + modes = [Mode.Visual, Mode.VisualLine]; + pluginActionDefaultKeys = ['g', 'S']; + keys = ['VgSurround']; + operatorString: 'change' | 'delete' | 'yank' | undefined = 'yank'; + + public async exec(position: Position, vimState: VimState): Promise { + let [start, end] = Position.sorted(vimState.cursorStartPosition, vimState.cursorStopPosition); + if (vimState.currentMode === Mode.VisualLine) { + [start, end] = [start.getLineBegin(), end.getLineEnd()]; + } + return StartSurroundMode(vimState, 'yank', this.keys, start, end, RegisterMode.LineWise); } } @@ -233,7 +277,23 @@ class CommandSurroundModeStartLine extends BaseSurroundCommand { public async exec(position: Position, vimState: VimState): Promise { const start: Position = position.getLineBeginRespectingIndent(); const end: Position = position.getLineEnd().getLastWordEnd().getRight(); - return StartSurroundMode(vimState, 'yank', this.keys, start, end); + return StartSurroundMode(vimState, 'yank', this.keys, start, end, undefined); + } +} + +@RegisterPluginAction('surround') +class CommandSurroundModeStartLineWithLineBreaks extends BaseSurroundCommand { + modes = [Mode.Normal]; + pluginActionDefaultKeys = [ + ['y', 'S', 's'], + ['y', 'S', 'S'], + ]; + keys = ['YSsurround']; + + public async exec(position: Position, vimState: VimState): Promise { + const start: Position = position.getLineBeginRespectingIndent(); + const end: Position = position.getLineEnd().getLastWordEnd().getRight(); + return StartSurroundMode(vimState, 'yank', this.keys, start, end, RegisterMode.LineWise); } } @@ -248,7 +308,7 @@ class SurroundModeStartOperator extends BaseOperator { } public async run(vimState: VimState, start: Position, end: Position): Promise { - return StartSurroundMode(vimState, 'yank', this.keys, start, end); + return StartSurroundMode(vimState, 'yank', this.keys, start, end, undefined); } public doesActionApply(vimState: VimState, keysPressed: string[]): boolean { @@ -260,6 +320,17 @@ class SurroundModeStartOperator extends BaseOperator { } } +@RegisterPluginAction('surround') +class SurroundModeStartOperatorWithLineBreaks extends SurroundModeStartOperator { + modes = [Mode.Normal]; + pluginActionDefaultKeys = ['y', 'S']; + keys = ['YSurround']; + + public async run(vimState: VimState, start: Position, end: Position): Promise { + return StartSurroundMode(vimState, 'yank', this.keys, start, end, RegisterMode.LineWise); + } +} + @RegisterAction export class CommandSurroundAddToReplacement extends BaseCommand { modes = [Mode.SurroundInputMode]; @@ -470,7 +541,10 @@ export class CommandSurroundAddToReplacement extends BaseCommand { stop = stop.getRight(); } - if (vimState.surround.previousMode === Mode.VisualLine) { + if ( + vimState.surround.previousMode === Mode.VisualLine || + vimState.surround.forcedRegisterMode === RegisterMode.LineWise + ) { startReplace = startReplace + '\n'; endReplace = '\n' + endReplace; } @@ -516,6 +590,11 @@ export class CommandSurroundAddToReplacement extends BaseCommand { startReplaceRange = new Range(start, start.getRight()); endReplaceRange = new Range(stop, stop.getRight()); + + if (vimState.surround?.forcedRegisterMode === RegisterMode.LineWise) { + startReplace = startReplace + '\n'; + endReplace = '\n' + endReplace; + } } const pairedMatchings: { @@ -548,6 +627,11 @@ export class CommandSurroundAddToReplacement extends BaseCommand { if (target === open) { CommandSurroundAddToReplacement.RemoveWhitespace(vimState, start, stop); } + + if (vimState.surround?.forcedRegisterMode === RegisterMode.LineWise) { + startReplace = startReplace + '\n'; + endReplace = '\n' + endReplace; + } } if (target === 't') { @@ -579,6 +663,11 @@ export class CommandSurroundAddToReplacement extends BaseCommand { } endDeleteRange = new Range(innerTagContent.stop.getRight(), stop); + + if (vimState.surround?.forcedRegisterMode === RegisterMode.LineWise) { + startReplace = startReplace + '\n'; + endReplace = '\n' + endReplace; + } } if (operator === 'change') { @@ -612,10 +701,15 @@ export class CommandSurroundAddToReplacement extends BaseCommand { return CommandSurroundAddToReplacement.Finish(vimState); } - if (addNewline === 'end-only' || addNewline === 'both') { + let isForcedLineWise = false; + if (vimState.surround?.forcedRegisterMode === RegisterMode.LineWise) { + isForcedLineWise = true; + } + + if (addNewline === 'end-only' || addNewline === 'both' || isForcedLineWise) { endReplace = '\n' + endReplace; } - if (addNewline === 'both') { + if (addNewline === 'both' || isForcedLineWise) { startReplace += '\n'; } diff --git a/src/state/vimState.ts b/src/state/vimState.ts index a499c6c3abc6..91282e76a22d 100644 --- a/src/state/vimState.ts +++ b/src/state/vimState.ts @@ -106,6 +106,7 @@ export class VimState implements vscode.Disposable { replacement: string | undefined; range: Range | undefined; previousMode: Mode; + forcedRegisterMode: RegisterMode | undefined; } = undefined; /**