|
@ -1,12 +1,19 @@ |
|
|
import { TextEditor, Uri, window } from 'vscode'; |
|
|
|
|
|
import { TextEditorComparer, UriComparer } from '../comparers'; |
|
|
|
|
|
import { Commands, CoreCommands } from '../constants'; |
|
|
|
|
|
|
|
|
import { |
|
|
|
|
|
TabInputCustom, |
|
|
|
|
|
TabInputNotebook, |
|
|
|
|
|
TabInputNotebookDiff, |
|
|
|
|
|
TabInputText, |
|
|
|
|
|
TabInputTextDiff, |
|
|
|
|
|
Uri, |
|
|
|
|
|
window, |
|
|
|
|
|
} from 'vscode'; |
|
|
|
|
|
import { UriComparer } from '../comparers'; |
|
|
|
|
|
import { Commands } from '../constants'; |
|
|
import type { Container } from '../container'; |
|
|
import type { Container } from '../container'; |
|
|
import { Logger } from '../logger'; |
|
|
import { Logger } from '../logger'; |
|
|
import { Messages } from '../messages'; |
|
|
import { Messages } from '../messages'; |
|
|
import { RepositoryPicker } from '../quickpicks/repositoryPicker'; |
|
|
import { RepositoryPicker } from '../quickpicks/repositoryPicker'; |
|
|
import { command, executeCoreCommand } from '../system/command'; |
|
|
|
|
|
import { debounce } from '../system/function'; |
|
|
|
|
|
|
|
|
import { command } from '../system/command'; |
|
|
import { Command } from './base'; |
|
|
import { Command } from './base'; |
|
|
|
|
|
|
|
|
export interface CloseUnchangedFilesCommandArgs { |
|
|
export interface CloseUnchangedFilesCommandArgs { |
|
@ -15,8 +22,6 @@ export interface CloseUnchangedFilesCommandArgs { |
|
|
|
|
|
|
|
|
@command() |
|
|
@command() |
|
|
export class CloseUnchangedFilesCommand extends Command { |
|
|
export class CloseUnchangedFilesCommand extends Command { |
|
|
private _onEditorChangedFn: ((editor: TextEditor | undefined) => void) | undefined; |
|
|
|
|
|
|
|
|
|
|
|
constructor(private readonly container: Container) { |
|
|
constructor(private readonly container: Container) { |
|
|
super(Commands.CloseUnchangedFiles); |
|
|
super(Commands.CloseUnchangedFiles); |
|
|
} |
|
|
} |
|
@ -39,114 +44,30 @@ export class CloseUnchangedFilesCommand extends Command { |
|
|
args.uris = status.files.map(f => f.uri); |
|
|
args.uris = status.files.map(f => f.uri); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (args.uris.length === 0) { |
|
|
|
|
|
void executeCoreCommand(CoreCommands.CloseAllEditors); |
|
|
|
|
|
|
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const disposable = window.onDidChangeActiveTextEditor( |
|
|
|
|
|
debounce((e: TextEditor | undefined) => this._onEditorChangedFn?.(e), 50), |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
let editor = window.activeTextEditor; |
|
|
|
|
|
|
|
|
const hasNoChangedFiles = args.uris.length === 0; |
|
|
|
|
|
|
|
|
let count = 0; |
|
|
|
|
|
let loopCount = 0; |
|
|
|
|
|
const editors: TextEditor[] = []; |
|
|
|
|
|
|
|
|
|
|
|
// Find out how many editors there are
|
|
|
|
|
|
while (true) { |
|
|
|
|
|
if (editor != null) { |
|
|
|
|
|
let found = false; |
|
|
|
|
|
for (const e of editors) { |
|
|
|
|
|
if (TextEditorComparer.equals(e, editor, { usePosition: true })) { |
|
|
|
|
|
found = true; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (found) break; |
|
|
|
|
|
|
|
|
|
|
|
// Start counting at the first real editor
|
|
|
|
|
|
count++; |
|
|
|
|
|
editors.push(editor); |
|
|
|
|
|
} else if (count !== 0) { |
|
|
|
|
|
count++; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
editor = await this.nextEditor(); |
|
|
|
|
|
|
|
|
|
|
|
loopCount++; |
|
|
|
|
|
// Break out if we've looped 4 times and haven't found any editors
|
|
|
|
|
|
if (loopCount >= 4 && editors.length === 0) break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (editors.length) { |
|
|
|
|
|
editor = window.activeTextEditor; |
|
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i <= count; i++) { |
|
|
|
|
|
|
|
|
for (const group of window.tabGroups.all) { |
|
|
|
|
|
for (const tab of group.tabs) { |
|
|
if ( |
|
|
if ( |
|
|
editor == null || |
|
|
|
|
|
editor.document.isDirty || |
|
|
|
|
|
// eslint-disable-next-line no-loop-func
|
|
|
|
|
|
args.uris.some(uri => UriComparer.equals(uri, editor?.document.uri)) |
|
|
|
|
|
|
|
|
tab.input instanceof TabInputText || |
|
|
|
|
|
tab.input instanceof TabInputCustom || |
|
|
|
|
|
tab.input instanceof TabInputNotebook |
|
|
) { |
|
|
) { |
|
|
editor = await this.nextEditor(); |
|
|
|
|
|
} else { |
|
|
|
|
|
editor = await this.closeEditor(); |
|
|
|
|
|
|
|
|
const inputUri = tab.input.uri; |
|
|
|
|
|
if (hasNoChangedFiles || !args.uris.some(uri => UriComparer.equals(uri, inputUri))) { |
|
|
|
|
|
void window.tabGroups.close(tab, true); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (tab.input instanceof TabInputTextDiff || tab.input instanceof TabInputNotebookDiff) { |
|
|
|
|
|
const inputUri = tab.input.modified; |
|
|
|
|
|
if (hasNoChangedFiles || !args.uris.some(uri => UriComparer.equals(uri, inputUri))) { |
|
|
|
|
|
void window.tabGroups.close(tab, true); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
disposable.dispose(); |
|
|
|
|
|
} catch (ex) { |
|
|
} catch (ex) { |
|
|
Logger.error(ex, 'CloseUnchangedFilesCommand'); |
|
|
Logger.error(ex, 'CloseUnchangedFilesCommand'); |
|
|
void Messages.showGenericErrorMessage('Unable to close all unchanged files'); |
|
|
void Messages.showGenericErrorMessage('Unable to close all unchanged files'); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private async closeEditor(timeout: number = 500): Promise<TextEditor | undefined> { |
|
|
|
|
|
const editor = window.activeTextEditor; |
|
|
|
|
|
|
|
|
|
|
|
void (await executeCoreCommand(CoreCommands.CloseActiveEditor)); |
|
|
|
|
|
|
|
|
|
|
|
if (editor !== window.activeTextEditor) { |
|
|
|
|
|
return window.activeTextEditor; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return this.waitForEditorChange(timeout); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private async nextEditor(timeout: number = 500): Promise<TextEditor | undefined> { |
|
|
|
|
|
const editor = window.activeTextEditor; |
|
|
|
|
|
|
|
|
|
|
|
void (await executeCoreCommand(CoreCommands.NextEditor)); |
|
|
|
|
|
|
|
|
|
|
|
if (editor !== window.activeTextEditor) { |
|
|
|
|
|
return window.activeTextEditor; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return this.waitForEditorChange(timeout); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private waitForEditorChange(timeout: number = 500): Promise<TextEditor | undefined> { |
|
|
|
|
|
return new Promise<TextEditor | undefined>(resolve => { |
|
|
|
|
|
let timer: ReturnType<typeof setTimeout> | undefined; |
|
|
|
|
|
|
|
|
|
|
|
this._onEditorChangedFn = (editor: TextEditor | undefined) => { |
|
|
|
|
|
if (timer != null) { |
|
|
|
|
|
clearTimeout(timer); |
|
|
|
|
|
timer = undefined; |
|
|
|
|
|
|
|
|
|
|
|
resolve(editor); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
timer = setTimeout(() => { |
|
|
|
|
|
timer = undefined; |
|
|
|
|
|
|
|
|
|
|
|
resolve(window.activeTextEditor); |
|
|
|
|
|
}, timeout); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |