diff --git a/extensions/git/src/dirtydiff.ts b/extensions/git/src/dirtydiff.ts index 62d4bef1d81..3cce6c700eb 100644 --- a/extensions/git/src/dirtydiff.ts +++ b/extensions/git/src/dirtydiff.ts @@ -5,22 +5,74 @@ 'use strict'; -import { Event, TextEditor, window } from 'vscode'; +import { Event, TextEditor, window, workspace } from 'vscode'; import { IDisposable, dispose, mapEvent } from './util'; type TextEditorsEvent = Event; -export class DirtyDiffDecorator implements IDisposable { +type IDecoration = void; +class ResourceDecorator implements IDisposable { + + private textEditors: TextEditor[] = []; + + constructor(private path: string) { + // console.log(`creating: ${this.path}`); + } + + add(textEditor: TextEditor): void { + this.remove(textEditor); + this.textEditors.push(textEditor); + } + + remove(textEditor: TextEditor): void { + this.textEditors = this.textEditors.filter(e => e !== textEditor); + } + + get count(): number { + return this.textEditors.length; + } + + dispose(): void { + // console.log(`disposing: ${this.path}`); + } +} + +export class DirtyDiff implements IDisposable { + + private textEditors: { editor: TextEditor; path: string; }[] = []; + private decorators: { [uri: string]: ResourceDecorator } = Object.create(null); private disposables: IDisposable[] = []; constructor() { - mapEvent(window.onDidChangeActiveTextEditor, () => window.visibleTextEditors) - (this.onDidVisibleEditorsChange, this, this.disposables); + const onVisibleTextEditorsChange = mapEvent(window.onDidChangeActiveTextEditor, () => window.visibleTextEditors); + onVisibleTextEditorsChange(this.onDidVisibleEditorsChange, this, this.disposables); + this.onDidVisibleEditorsChange(window.visibleTextEditors); + + const watcher = workspace.createFileSystemWatcher('**'); + + this.disposables.push(watcher); } private onDidVisibleEditorsChange(textEditors: TextEditor[]) { - // TODO + const added = textEditors.filter(a => this.textEditors.every(({ editor }) => a !== editor)).map(editor => ({ editor, path: workspace.asRelativePath(editor.document.uri) })); + const removed = this.textEditors.filter(({ editor }) => textEditors.every(b => editor !== b)); + this.textEditors = textEditors.map(editor => ({ editor, path: workspace.asRelativePath(editor.document.uri) })); + + removed.forEach(({ editor, path }) => { + const decorator = this.decorators[path]; + decorator.remove(editor); + + if (decorator.count === 0) { + decorator.dispose(); + delete this.decorators[path]; + } + }); + + added.forEach(({ editor, path }) => { + const decorator = this.decorators[path] || (this.decorators[path] = new ResourceDecorator(path)); + decorator.add(editor); + }); } dispose(): void { diff --git a/extensions/git/src/extension.ts b/extensions/git/src/extension.ts index 650bb4205af..adf9e441941 100644 --- a/extensions/git/src/extension.ts +++ b/extensions/git/src/extension.ts @@ -6,11 +6,11 @@ 'use strict'; import { ExtensionContext } from 'vscode'; -import { DirtyDiffDecorator } from './dirtydiff'; +import { DirtyDiff } from './dirtydiff'; export function activate(context: ExtensionContext) { context.subscriptions.push( - new DirtyDiffDecorator() + new DirtyDiff() ); } diff --git a/extensions/git/src/util.ts b/extensions/git/src/util.ts index d9ca2b75792..756c554374c 100644 --- a/extensions/git/src/util.ts +++ b/extensions/git/src/util.ts @@ -16,10 +16,47 @@ export function dispose(disposables: T[]): T[] { return []; } +export function combinedDisposable(disposables: IDisposable[]): IDisposable { + return { dispose: () => dispose(disposables) }; +} + export function mapEvent(event: Event, map: (i: I) => O): Event { return (listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables); } export function filterEvent(event: Event, filter: (e: T) => boolean): Event { return (listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables); +} + +export function any(...events: Event[]): Event { + return (listener, thisArgs = null, disposables?) => combinedDisposable(events.map(event => event(i => listener.call(thisArgs, i), disposables))); +} + +interface IListener { + (e: T): any; +} + +export class Emitter { + + private listeners: IListener[]; + + get event(): Event { + return (listener: IListener, thisArgs = null, disposables?: IDisposable[]) => { + const _listener = thisArgs ? listener.bind(thisArgs) : listener; + this.listeners.push(_listener); + + const dispose = () => { this.listeners = this.listeners.filter(l => l !== _listener); }; + const result = { dispose }; + + if (disposables) { + disposables.push(result); + } + + return result; + }; + } + + fire(e: T = null): void { + + } } \ No newline at end of file