Browse Source

Fixes #83 - Close Unchanged Files command can infinitely loop

main
Eric Amodio 7 years ago
parent
commit
2a8dafd9e9
3 changed files with 39 additions and 27 deletions
  1. +9
    -6
      src/activeEditorTracker.ts
  2. +28
    -20
      src/commands/closeUnchangedFiles.ts
  3. +2
    -1
      src/constants.ts

+ 9
- 6
src/activeEditorTracker.ts View File

@ -1,5 +1,6 @@
'use strict';
import { Functions } from './system';
import { commands, Disposable, TextEditor, window } from 'vscode';
import { BuiltInCommands } from './constants';
@ -11,19 +12,20 @@ export class ActiveEditorTracker extends Disposable {
constructor() {
super(() => this.dispose());
this._disposable = window.onDidChangeActiveTextEditor(e => this._resolver && this._resolver(e));
const fn = Functions.debounce((e: TextEditor) => this._resolver && this._resolver(e), 50);
this._disposable = window.onDidChangeActiveTextEditor(fn);
}
dispose() {
this._disposable && this._disposable.dispose();
}
async awaitClose(timeout: number = 500): Promise<TextEditor> {
async awaitClose(timeout: number = 500): Promise<TextEditor | undefined> {
this.close();
return this.wait(timeout);
}
async awaitNext(timeout: number = 500): Promise<TextEditor> {
async awaitNext(timeout: number = 500): Promise<TextEditor | undefined> {
this.next();
return this.wait(timeout);
}
@ -36,15 +38,15 @@ export class ActiveEditorTracker extends Disposable {
return commands.executeCommand(BuiltInCommands.NextEditor);
}
async wait(timeout: number = 500): Promise<TextEditor> {
async wait(timeout: number = 500): Promise<TextEditor | undefined> {
const editor = await new Promise<TextEditor>((resolve, reject) => {
let timer: any;
this._resolver = (editor: TextEditor) => {
this._resolver = (e: TextEditor) => {
if (timer) {
clearTimeout(timer as any);
timer = 0;
resolve(editor);
resolve(e);
}
};
@ -53,6 +55,7 @@ export class ActiveEditorTracker extends Disposable {
timer = 0;
}, timeout) as any;
});
this._resolver = undefined;
return editor;
}

+ 28
- 20
src/commands/closeUnchangedFiles.ts View File

@ -1,8 +1,9 @@
'use strict';
import { TextEditor, Uri, window } from 'vscode';
import { commands, TextEditor, Uri, window } from 'vscode';
import { ActiveEditorTracker } from '../activeEditorTracker';
import { ActiveEditorCommand, Commands, getCommandUri } from './common';
import { TextEditorComparer, UriComparer } from '../comparers';
import { BuiltInCommands } from '../constants';
import { GitService } from '../gitService';
import { Logger } from '../logger';
@ -30,34 +31,41 @@ export class CloseUnchangedFilesCommand extends ActiveEditorCommand {
args.uris = status.files.map(_ => _.Uri);
}
if (args.uris.length === 0) return commands.executeCommand(BuiltInCommands.CloseAllEditors);
const editorTracker = new ActiveEditorTracker();
let active = window.activeTextEditor;
let editor = active;
do {
let count = 0;
let previous = undefined;
let editor = window.activeTextEditor;
while (true) {
if (editor !== undefined) {
if ((editor.document !== undefined && editor.document.isDirty) ||
args.uris.some(_ => UriComparer.equals(_, editor!.document && editor!.document.uri))) {
// If we didn't start with a valid editor, set one once we find it
if (active === undefined) {
active = editor;
}
if (TextEditorComparer.equals(previous, editor, { useId: true, usePosition: true })) {
break;
}
if (editor.document !== undefined &&
(editor.document.isDirty || args.uris.some(_ => UriComparer.equals(_, editor!.document && editor!.document.uri)))) {
previous = editor;
editor = await editorTracker.awaitNext(500);
continue;
}
else {
if (active === editor) {
active = undefined;
}
editor = await editorTracker.awaitClose(500);
}
previous = editor;
editor = await editorTracker.awaitClose(500);
if (previous === undefined && editor === undefined) {
count++;
// This is such a shitty hack, but I can't figure out any other reliable way to know that we've cycled through all the editors :(
if (count >= 4) {
break;
}
}
else {
if (active === editor) {
active = undefined;
}
editor = await editorTracker.awaitClose(500);
count = 0;
}
} while ((active === undefined && editor === undefined) || !TextEditorComparer.equals(active, editor, { useId: true, usePosition: true }));
}
editorTracker.dispose();

+ 2
- 1
src/constants.ts View File

@ -7,9 +7,10 @@ export const QualifiedExtensionId = `eamodio.${ExtensionId}`;
export const ApplicationInsightsKey = 'a9c302f8-6483-4d01-b92c-c159c799c679';
export type BuiltInCommands = 'cursorMove' | 'editor.action.showReferences' | 'editor.action.toggleRenderWhitespace' | 'editorScroll' | 'revealLine' | 'setContext' | 'vscode.diff' | 'vscode.executeDocumentSymbolProvider' | 'vscode.executeCodeLensProvider' | 'vscode.open' | 'vscode.previewHtml' | 'workbench.action.closeActiveEditor' | 'workbench.action.nextEditor';
export type BuiltInCommands = 'cursorMove' | 'editor.action.showReferences' | 'editor.action.toggleRenderWhitespace' | 'editorScroll' | 'revealLine' | 'setContext' | 'vscode.diff' | 'vscode.executeDocumentSymbolProvider' | 'vscode.executeCodeLensProvider' | 'vscode.open' | 'vscode.previewHtml' | 'workbench.action.closeActiveEditor' | 'workbench.action.closeAllEditors' | 'workbench.action.nextEditor';
export const BuiltInCommands = {
CloseActiveEditor: 'workbench.action.closeActiveEditor' as BuiltInCommands,
CloseAllEditors: 'workbench.action.closeAllEditors' as BuiltInCommands,
CursorMove: 'cursorMove' as BuiltInCommands,
Diff: 'vscode.diff' as BuiltInCommands,
EditorScroll: 'editorScroll' as BuiltInCommands,

Loading…
Cancel
Save