From c8aa92f8792dfa463197e11ea4206e1c47ec51eb Mon Sep 17 00:00:00 2001 From: Ryan Puhalovich Date: Sun, 3 Sep 2023 17:12:36 +1000 Subject: [PATCH] implemented new quit option with tests --- package.json | 5 +++ src/cmd_line/commands/quit.ts | 33 ++++++++------- src/configuration/configuration.ts | 3 ++ src/configuration/iconfiguration.ts | 5 +++ test/cmd_line/quit.test.ts | 66 +++++++++++++++++++++++++++++ test/testConfiguration.ts | 1 + 6 files changed, 97 insertions(+), 16 deletions(-) create mode 100644 test/cmd_line/quit.test.ts diff --git a/package.json b/package.json index 2627221e73c..809f8392ad8 100644 --- a/package.json +++ b/package.json @@ -1114,6 +1114,11 @@ "type": "string", "description": "Path to the shell to use for `!` and `:!` commands.", "default": "" + }, + "vim.closeSplitEditorsOnQuit": { + "type": "boolean", + "description": "When true, `:q` closes all tabs in a split. This behavior mimics the workflow from native Vim.", + "default": false } } }, diff --git a/src/cmd_line/commands/quit.ts b/src/cmd_line/commands/quit.ts index 8bab79c03dc..a67a2ebfcbe 100644 --- a/src/cmd_line/commands/quit.ts +++ b/src/cmd_line/commands/quit.ts @@ -5,6 +5,7 @@ import * as error from '../../error'; import { VimState } from '../../state/vimState'; import { ExCommand } from '../../vimscript/exCommand'; import { bangParser } from '../../vimscript/parserUtils'; +import { configuration } from './../../configuration/configuration'; export interface IQuitCommandArguments { bang?: boolean; @@ -12,20 +13,13 @@ export interface IQuitCommandArguments { } // -// Implements :quit -// http://vimdoc.sourceforge.net/htmldoc/editing.html#:quit +// Implements :quit +// http://vimdoc.sourceforge.net/htmldoc/editing.html#:quit // export class QuitCommand extends ExCommand { public static readonly argParser: (quitAll: boolean) => Parser = ( quitAll: boolean - ) => - bangParser.map( - (bang) => - new QuitCommand({ - bang, - quitAll, - }) - ); + ) => bangParser.map((bang) => new QuitCommand({ bang, quitAll })); public override isRepeatableWithDot = false; @@ -50,12 +44,19 @@ export class QuitCommand extends ExCommand { if (this.arguments.quitAll) { await vscode.commands.executeCommand('workbench.action.closeAllEditors'); - } else { - if (!this.arguments.bang) { - await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); - } else { - await vscode.commands.executeCommand('workbench.action.revertAndCloseActiveEditor'); - } + return; } + + if (this.arguments.bang) { + await vscode.commands.executeCommand('workbench.action.revertAndCloseActiveEditor'); + return; + } + + if (configuration.closeSplitEditorsOnQuit) { + await vscode.commands.executeCommand('workbench.action.closeEditorsInGroup'); + return; + } + + await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); } } diff --git a/src/configuration/configuration.ts b/src/configuration/configuration.ts index 5353b168461..3d15421d52d 100644 --- a/src/configuration/configuration.ts +++ b/src/configuration/configuration.ts @@ -431,6 +431,9 @@ class Configuration implements IConfiguration { wrapscan = true; scroll = 0; + + closeSplitEditorsOnQuit = false; + getScrollLines(visibleRanges: vscode.Range[]): number { return this.scroll === 0 ? Math.ceil((visibleRanges[0].end.line - visibleRanges[0].start.line) / 2) diff --git a/src/configuration/iconfiguration.ts b/src/configuration/iconfiguration.ts index c463bf05ab0..4b5bd9cc7a2 100644 --- a/src/configuration/iconfiguration.ts +++ b/src/configuration/iconfiguration.ts @@ -444,4 +444,9 @@ export interface IConfiguration { * Path to the shell to use for `!` and `:!` commands. */ shell: string; + + /** + * When true, `:q` closes all tabs in a split. This behavior mimics the workflow from native Vim. + */ + closeSplitEditorsOnQuit: boolean; } diff --git a/test/cmd_line/quit.test.ts b/test/cmd_line/quit.test.ts new file mode 100644 index 00000000000..296af3280f6 --- /dev/null +++ b/test/cmd_line/quit.test.ts @@ -0,0 +1,66 @@ +import * as assert from 'assert'; +import * as vscode from 'vscode'; + +import * as testConfiguration from '../testConfiguration'; + +import { getAndUpdateModeHandler } from '../../extension'; +import { ExCommandLine } from '../../src/cmd_line/commandLine'; +import { ModeHandler } from '../../src/mode/modeHandler'; +import { cleanUpWorkspace, setupWorkspace, WaitForEditorsToClose } from './../testUtils'; + +suite('Quit', () => { + let modeHandler: ModeHandler; + + setup(async () => { + const configuration = new testConfiguration.Configuration(); + await setupWorkspace(configuration); + modeHandler = (await getAndUpdateModeHandler())!; + }); + + teardown(cleanUpWorkspace); + + for (const cmd of ['q', 'quit']) { + test(`:${cmd} does not quit the second split`, async () => { + await new ExCommandLine('new', modeHandler.vimState.currentMode).run(modeHandler.vimState); + await new ExCommandLine('enew', modeHandler.vimState.currentMode).run(modeHandler.vimState); + await new ExCommandLine(cmd, modeHandler.vimState.currentMode).run(modeHandler.vimState); + + await WaitForEditorsToClose(2); + + assert.strictEqual( + vscode.window.visibleTextEditors.length, + 2, + 'Editor did not split in 1 sec' + ); + }); + } +}); + +suite('Quit all editors in split', () => { + let modeHandler: ModeHandler; + + setup(async () => { + const configuration = new testConfiguration.Configuration(); + configuration.closeSplitEditorsOnQuit = true; + await setupWorkspace(configuration); + modeHandler = (await getAndUpdateModeHandler())!; + }); + + teardown(cleanUpWorkspace); + + for (const cmd of ['q', 'quit']) { + test(`:${cmd} quits the second split`, async () => { + await new ExCommandLine('new', modeHandler.vimState.currentMode).run(modeHandler.vimState); + await new ExCommandLine('enew', modeHandler.vimState.currentMode).run(modeHandler.vimState); + await new ExCommandLine(cmd, modeHandler.vimState.currentMode).run(modeHandler.vimState); + + await WaitForEditorsToClose(1); + + assert.strictEqual( + vscode.window.visibleTextEditors.length, + 1, + 'Editor did not split in 1 sec' + ); + }); + } +}); diff --git a/test/testConfiguration.ts b/test/testConfiguration.ts index d1b4e6eaa90..052eb1e15d7 100644 --- a/test/testConfiguration.ts +++ b/test/testConfiguration.ts @@ -144,4 +144,5 @@ export class Configuration implements IConfiguration { startofline = true; showMarksInGutter = true; shell = ''; + closeSplitEditorsOnQuit = false; }