Skip to content

Commit 2c9efbe

Browse files
authored
Merge pull request #52 from edgardmessias/statusbar_switching
Improved workspace events changes
2 parents 331fd95 + b2fa9f1 commit 2c9efbe

File tree

4 files changed

+126
-53
lines changed

4 files changed

+126
-53
lines changed

src/decorators.ts

Lines changed: 95 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,103 @@
1-
export function debounce(func: Function, wait: number, context: any) {
2-
let timer: any = null;
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
35

4-
return function(...args: any[]) {
5-
clearTimeout(timer);
6+
'use strict';
67

7-
timer = setTimeout(() => {
8-
func.apply(context, ...args);
9-
}, wait);
8+
import { done } from './util';
9+
10+
function decorate(decorator: (fn: Function, key: string) => Function): Function {
11+
return (target: any, key: string, descriptor: any) => {
12+
let fnKey: string | null = null;
13+
let fn: Function | null = null;
14+
15+
if (typeof descriptor.value === 'function') {
16+
fnKey = 'value';
17+
fn = descriptor.value;
18+
} else if (typeof descriptor.get === 'function') {
19+
fnKey = 'get';
20+
fn = descriptor.get;
21+
}
22+
23+
if (!fn || !fnKey) {
24+
throw new Error('not supported');
25+
}
26+
27+
descriptor[fnKey] = decorator(fn, key);
28+
};
29+
}
30+
31+
function _memoize(fn: Function, key: string): Function {
32+
const memoizeKey = `$memoize$${key}`;
33+
34+
return function (...args: any[]) {
35+
if (!this.hasOwnProperty(memoizeKey)) {
36+
Object.defineProperty(this, memoizeKey, {
37+
configurable: false,
38+
enumerable: false,
39+
writable: false,
40+
value: fn.apply(this, args)
41+
});
42+
}
43+
44+
return this[memoizeKey];
1045
};
1146
}
1247

13-
export function throttleAsync(fn: Function, key: string, context: any) {
14-
// const currentKey = `$throttle$current$${key}`;
15-
// const nextKey = `$throttle$next$${key}`;
16-
// const trigger = function(...args: any[]) {
17-
// if (this[nextKey]) {
18-
// return this[nextKey];
19-
// }
20-
// if (this[nextKey]) {
21-
// done(this[currentKey]).then(() => {
22-
// this[nextKey] = false;
23-
// return trigger.apply(context, ...args);
24-
// });
25-
// return this[nextKey];
26-
// }
27-
// this[currentKey] = fn.apply(context, args);
28-
// this[currentKey].then(() => {
29-
// this[currentKey] = false;
30-
// });
31-
// return this[currentKey];
32-
// };
33-
// return trigger;
48+
export const memoize = decorate(_memoize);
49+
50+
function _throttle<T>(fn: Function, key: string): Function {
51+
const currentKey = `$throttle$current$${key}`;
52+
const nextKey = `$throttle$next$${key}`;
53+
54+
const trigger = function (...args: any[]) {
55+
if (this[nextKey]) {
56+
return this[nextKey];
57+
}
58+
59+
if (this[currentKey]) {
60+
this[nextKey] = done(this[currentKey]).then(() => {
61+
this[nextKey] = undefined;
62+
return trigger.apply(this, args);
63+
});
64+
65+
return this[nextKey];
66+
}
67+
68+
this[currentKey] = fn.apply(this, args) as Promise<T>;
69+
70+
const clear = () => this[currentKey] = undefined;
71+
done(this[currentKey]).then(clear, clear);
72+
73+
return this[currentKey];
74+
};
75+
76+
return trigger;
3477
}
3578

36-
function done(promise: Promise<void>) {
37-
return promise.then(() => void 0);
79+
export const throttle = decorate(_throttle);
80+
81+
function _sequentialize<T>(fn: Function, key: string): Function {
82+
const currentKey = `__$sequence$${key}`;
83+
84+
return function (...args: any[]) {
85+
const currentPromise = this[currentKey] as Promise<any> || Promise.resolve(null);
86+
const run = async () => await fn.apply(this, args);
87+
this[currentKey] = currentPromise.then(run, run);
88+
return this[currentKey];
89+
};
3890
}
91+
92+
export const sequentialize = decorate(_sequentialize);
93+
94+
export function debounce(delay: number): Function {
95+
return decorate((fn, key) => {
96+
const timerKey = `$debounce$${key}`;
97+
98+
return function (...args: any[]) {
99+
clearTimeout(this[timerKey]);
100+
this[timerKey] = setTimeout(() => fn.apply(this, args), delay);
101+
};
102+
});
103+
}

src/repository.ts

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ import {
1111
Event
1212
} from "vscode";
1313
import { Resource } from "./resource";
14-
import { throttleAsync, debounce } from "./decorators";
15-
import { Repository as BaseRepository } from "./svnRepository";
14+
import { throttle, debounce } from "./decorators";
15+
import { Repository as BaseRepository } from "./svn";
1616
import { SvnStatusBar } from "./statusBar";
17-
import { dispose } from "./util";
17+
import { dispose, anyEvent, filterEvent } from "./util";
18+
import * as path from 'path';
1819

1920
export class Repository {
2021
public watcher: FileSystemWatcher;
@@ -23,8 +24,12 @@ export class Repository {
2324
public notTracked: SourceControlResourceGroup;
2425
private disposables: Disposable[] = [];
2526
public currentBranch = "";
27+
public isSwitchingBranch: boolean = false;
2628
public branches: any[] = [];
2729

30+
private _onDidChangeRepository = new EventEmitter<Uri>();
31+
readonly onDidChangeRepository: Event<Uri> = this._onDidChangeRepository.event;
32+
2833
private _onDidChangeStatus = new EventEmitter<void>();
2934
readonly onDidChangeStatus: Event<void> = this._onDidChangeStatus.event;
3035

@@ -41,8 +46,16 @@ export class Repository {
4146
}
4247

4348
constructor(public repository: BaseRepository) {
44-
this.watcher = workspace.createFileSystemWatcher("**");
45-
this.disposables.push(this.watcher);
49+
const fsWatcher = workspace.createFileSystemWatcher("**");
50+
this.disposables.push(fsWatcher);
51+
52+
const onWorkspaceChange = anyEvent(fsWatcher.onDidChange, fsWatcher.onDidCreate, fsWatcher.onDidDelete);
53+
const onRepositoryChange = filterEvent(onWorkspaceChange, uri => !/^\.\./.test(path.relative(repository.root, uri.fsPath)));
54+
const onRelevantRepositoryChange = filterEvent(onRepositoryChange, uri => !/\/\.svn\/tmp/.test(uri.path));
55+
onRelevantRepositoryChange(this.update, this, this.disposables);
56+
57+
const onRelevantSvnChange = filterEvent(onRelevantRepositoryChange, uri => /\/\.svn\//.test(uri.path));
58+
onRelevantSvnChange(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables);
4659

4760
this.sourceControl = scm.createSourceControl(
4861
"svn",
@@ -76,23 +89,9 @@ export class Repository {
7689
this.notTracked.hideWhenEmpty = true;
7790

7891
this.update();
79-
this.addEventListeners();
80-
}
81-
82-
private addEventListeners() {
83-
const debounceUpdate = debounce(this.update, 1000, this);
84-
85-
this.watcher.onDidChange(() => {
86-
debounceUpdate();
87-
});
88-
this.watcher.onDidCreate(() => {
89-
debounceUpdate();
90-
});
91-
this.watcher.onDidDelete(() => {
92-
debounceUpdate();
93-
});
9492
}
9593

94+
@debounce(1000)
9695
async update() {
9796
let changes: any[] = [];
9897
let notTracked: any[] = [];
@@ -170,7 +169,12 @@ export class Repository {
170169
return this.repository.branch(name);
171170
}
172171

173-
switchBranch(name: string) {
174-
return this.repository.switchBranch(name);
172+
async switchBranch(name: string) {
173+
this.isSwitchingBranch = true;
174+
this._onDidChangeStatus.fire();
175+
const response = await this.repository.switchBranch(name);
176+
this.isSwitchingBranch = false;
177+
this._onDidChangeStatus.fire();
178+
return response;
175179
}
176180
}

src/statusBar.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ export class SvnStatusBar {
1818
}
1919

2020
get commands() {
21-
const title = `$(git-branch) ${this.repository.currentBranch}`;
21+
const icon = (this.repository.isSwitchingBranch)? 'sync~spin' : 'git-branch';
22+
const title = `$(${icon}) ${this.repository.currentBranch}`;
2223

2324
return [
2425
{

src/util.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ export interface BaseDisposable {
44
dispose(): void;
55
}
66

7+
export function done<T>(promise: Promise<T>): Promise<void> {
8+
return promise.then<void>(() => void 0);
9+
}
710
export function anyEvent<T>(...events: Event<T>[]): Event<T> {
811
return (listener, thisArgs = null, disposables?) => {
912
const result = combinedDisposable(

0 commit comments

Comments
 (0)