Browse Source

Adds setting to disable liveshare integration

main
Eric Amodio 1 year ago
parent
commit
ac202a7310
8 changed files with 81 additions and 89 deletions
  1. +8
    -1
      package.json
  2. +1
    -0
      src/config.ts
  3. +4
    -2
      src/hovers/hovers.ts
  4. +0
    -38
      src/system/decorators/timeout.ts
  5. +45
    -35
      src/system/promise.ts
  6. +2
    -4
      src/views/nodes/contributorsNode.ts
  7. +1
    -1
      src/views/viewBase.ts
  8. +20
    -8
      src/vsls/vsls.ts

+ 8
- 1
package.json View File

@ -3090,12 +3090,19 @@
"scope": "window",
"order": 40
},
"gitlens.liveshare.enabled": {
"type": "boolean",
"default": true,
"description": "Specifies whether to enable integration with Visual Studio Live Share",
"scope": "window",
"order": 50
},
"gitlens.liveshare.allowGuestAccess": {
"type": "boolean",
"default": true,
"description": "Specifies whether to allow guest access to GitLens features when using Visual Studio Live Share",
"scope": "window",
"order": 50
"order": 51
}
}
},

+ 1
- 0
src/config.ts View File

@ -122,6 +122,7 @@ export interface Config {
};
readonly keymap: KeyMap;
readonly liveshare: {
readonly enabled: boolean;
readonly allowGuestAccess: boolean;
};
readonly menus: boolean | MenuConfig;

+ 4
- 2
src/hovers/hovers.ts View File

@ -16,7 +16,7 @@ import type { GitRemote } from '../git/models/remote';
import type { RemoteProvider } from '../git/remotes/remoteProvider';
import { pauseOnCancelOrTimeout, pauseOnCancelOrTimeoutMapTuplePromise } from '../system/cancellation';
import { configuration } from '../system/configuration';
import { getSettledValue } from '../system/promise';
import { cancellable, getSettledValue } from '../system/promise';
export async function changesMessage(
container: Container,
@ -257,7 +257,9 @@ export async function detailsMessage(
options?.timeout,
)
: undefined,
container.vsls.maybeGetPresence(commit.author.email),
container.vsls.enabled
? cancellable(container.vsls.getContactPresence(commit.author.email), 250, options?.cancellation)
: undefined,
commit.isUncommitted ? commit.getPreviousComparisonUrisForLine(editorLine, uri.sha) : undefined,
commit.message == null ? commit.ensureFullDetails() : undefined,
]);

+ 0
- 38
src/system/decorators/timeout.ts View File

@ -1,38 +0,0 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
import { cancellable, isPromise } from '../promise';
export function timeout(timeout: number): any;
export function timeout(timeoutFromLastArg: true, defaultTimeout?: number): any;
export function timeout(timeoutOrTimeoutFromLastArg: number | boolean, defaultTimeout?: number): any {
let timeout: number | undefined;
let timeoutFromLastArg = false;
if (typeof timeoutOrTimeoutFromLastArg === 'boolean') {
timeoutFromLastArg = timeoutOrTimeoutFromLastArg;
} else {
timeout = timeoutOrTimeoutFromLastArg;
}
return (target: any, key: string, descriptor: PropertyDescriptor) => {
let fn: Function | undefined;
if (typeof descriptor.value === 'function') {
fn = descriptor.value;
}
if (fn == null) throw new Error('Not supported');
descriptor.value = function (this: any, ...args: any[]) {
if (timeoutFromLastArg) {
const lastArg = args[args.length - 1];
if (lastArg != null && typeof lastArg === 'number') {
timeout = lastArg;
} else {
timeout = defaultTimeout;
}
}
const result = fn?.apply(this, args);
if (timeout == null || timeout < 1 || !isPromise(result)) return result;
return cancellable(result, timeout, { onDidCancel: resolve => resolve(undefined) });
};
};
}

+ 45
- 35
src/system/promise.ts View File

@ -69,55 +69,65 @@ export class PromiseCancelledError = Promise> extend
export function cancellable<T>(
promise: Promise<T>,
timeoutOrToken?: number | CancellationToken,
options: {
timeout?: number | CancellationToken,
cancellation?: CancellationToken,
options?: {
cancelMessage?: string;
onDidCancel?(resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void): void;
} = {},
onDidCancel?(
resolve: (value: T | PromiseLike<T>) => void,
reject: (reason?: any) => void,
reason: 'cancelled' | 'timedout',
): void;
},
): Promise<T> {
if (timeoutOrToken == null || (typeof timeoutOrToken === 'number' && timeoutOrToken <= 0)) return promise;
if (timeout == null && cancellation == null) return promise;
return new Promise((resolve, reject) => {
let fulfilled = false;
let timer: ReturnType<typeof setTimeout> | undefined;
let disposable: Disposable | undefined;
if (typeof timeoutOrToken === 'number') {
timer = setTimeout(() => {
if (typeof options.onDidCancel === 'function') {
options.onDidCancel(resolve, reject);
} else {
reject(new PromiseCancelledError(promise, options.cancelMessage ?? 'TIMED OUT'));
}
}, timeoutOrToken);
} else {
disposable = timeoutOrToken.onCancellationRequested(() => {
disposable?.dispose();
if (fulfilled) return;
if (typeof options.onDidCancel === 'function') {
options.onDidCancel(resolve, reject);
} else {
reject(new PromiseCancelledError(promise, options.cancelMessage ?? 'CANCELLED'));
}
});
let disposeCancellation: Disposable | undefined;
let disposeTimeout: Disposable | undefined;
const resolver = (reason: 'cancelled' | 'timedout') => {
disposeCancellation?.dispose();
disposeTimeout?.dispose();
if (fulfilled) return;
if (options?.onDidCancel != null) {
options.onDidCancel(resolve, reject, reason);
} else {
reject(
new PromiseCancelledError(
promise,
options?.cancelMessage ?? (reason === 'cancelled' ? 'CANCELLED' : 'TIMED OUT'),
),
);
}
};
disposeCancellation = cancellation?.onCancellationRequested(() => resolver('cancelled'));
if (timeout != null) {
if (typeof timeout === 'number') {
const timer = setTimeout(() => resolver('timedout'), timeout);
disposeTimeout = { dispose: () => clearTimeout(timer) };
} else {
disposeTimeout = timeout.onCancellationRequested(() => resolver('timedout'));
}
}
promise.then(
() => {
fulfilled = true;
if (timer != null) {
clearTimeout(timer);
}
disposable?.dispose();
disposeCancellation?.dispose();
disposeTimeout?.dispose();
resolve(promise);
},
ex => {
fulfilled = true;
if (timer != null) {
clearTimeout(timer);
}
disposable?.dispose();
disposeCancellation?.dispose();
disposeTimeout?.dispose();
reject(ex);
},
);

+ 2
- 4
src/views/nodes/contributorsNode.ts View File

@ -5,7 +5,6 @@ import type { Repository } from '../../git/models/repository';
import { configuration } from '../../system/configuration';
import { gate } from '../../system/decorators/gate';
import { debug } from '../../system/decorators/log';
import { timeout } from '../../system/decorators/timeout';
import type { ViewsWithContributorsNode } from '../viewBase';
import { MessageNode } from './common';
import { ContributorNode } from './contributorNode';
@ -57,7 +56,7 @@ export class ContributorsNode extends ViewNode<'contributors', ViewsWithContribu
if (contributors.length === 0) return [new MessageNode(this.view, this, 'No contributors could be found.')];
GitContributor.sort(contributors);
const presenceMap = await this.maybeGetPresenceMap(contributors);
const presenceMap = this.view.container.vsls.enabled ? await this.getPresenceMap(contributors) : undefined;
this._children = contributors.map(
c =>
@ -99,8 +98,7 @@ export class ContributorsNode extends ViewNode<'contributors', ViewsWithContribu
}
@debug({ args: false })
@timeout(250)
private async maybeGetPresenceMap(contributors: GitContributor[]) {
private async getPresenceMap(contributors: GitContributor[]) {
// Only get presence for the current user, because it is far too slow otherwise
const email = contributors.find(c => c.current)?.email;
if (email == null) return undefined;

+ 1
- 1
src/views/viewBase.ts View File

@ -579,7 +579,7 @@ export abstract class ViewBase<
await this.loadMoreNodeChildren(node, defaultPageSize);
pagedChildren = await cancellable(Promise.resolve(node.getChildren()), token ?? 60000, {
pagedChildren = await cancellable(Promise.resolve(node.getChildren()), 60000, token, {
onDidCancel: resolve => resolve([]),
});

+ 20
- 8
src/vsls/vsls.ts View File

@ -1,3 +1,4 @@
import type { ConfigurationChangeEvent } from 'vscode';
import { Disposable, extensions, workspace } from 'vscode';
import type { LiveShare, LiveShareExtension, SessionChangeEvent } from '../@types/vsls';
import { Schemes } from '../constants';
@ -5,7 +6,6 @@ import type { Container } from '../container';
import { configuration } from '../system/configuration';
import { setContext } from '../system/context';
import { debug } from '../system/decorators/log';
import { timeout } from '../system/decorators/timeout';
import { once } from '../system/event';
import { Logger } from '../system/logger';
import type { Deferred } from '../system/promise';
@ -43,7 +43,10 @@ export class VslsController implements Disposable {
constructor(private readonly container: Container) {
this._ready = defer<void>();
this._disposable = Disposable.from(once(container.onReady)(this.onReady, this));
this._disposable = Disposable.from(
once(container.onReady)(this.onReady, this),
configuration.onDidChange(this.onConfigurationChanged, this),
);
}
dispose() {
@ -59,6 +62,11 @@ export class VslsController implements Disposable {
}
private async initialize() {
if (!this.enabled) {
void setContext('gitlens:vsls', false);
return;
}
// If we have a vsls: workspace open, we might be a guest, so wait until live share transitions into a mode
if (workspace.workspaceFolders?.some(f => f.uri.scheme === Schemes.Vsls)) {
this.setReadonly(true);
@ -88,6 +96,12 @@ export class VslsController implements Disposable {
}
}
private onConfigurationChanged(e: ConfigurationChangeEvent) {
if (configuration.changed(e, 'liveshare.enabled')) {
void this.initialize();
}
}
private async onLiveShareSessionChanged(api: LiveShare, e: SessionChangeEvent) {
this._host?.dispose();
this._host = undefined;
@ -151,6 +165,10 @@ export class VslsController implements Disposable {
void setContext('gitlens:readonly', value ? true : undefined);
}
get enabled() {
return configuration.get('liveshare.enabled');
}
async guest() {
if (this._guest != null) return this._guest;
@ -196,12 +214,6 @@ export class VslsController implements Disposable {
);
}
@debug()
@timeout(250)
maybeGetPresence(email: string | undefined): Promise<ContactPresence | undefined> {
return this.getContactPresence(email);
}
async invite(email: string | undefined) {
if (email == null) return undefined;

||||||
x
 
000:0
Loading…
Cancel
Save