Skip to content

Commit 9a47409

Browse files
committed
Fixes live share support
1 parent f77cf30 commit 9a47409

File tree

7 files changed

+190
-166
lines changed

7 files changed

+190
-166
lines changed

package.json

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@
195195
"onStartupFinished"
196196
],
197197
"capabilities": {
198-
"virtualWorkspaces": false,
198+
"virtualWorkspaces": true,
199199
"untrustedWorkspaces": {
200200
"supported": "limited"
201201
}
@@ -9703,17 +9703,16 @@
97039703
"iconv-lite": "0.6.3",
97049704
"lodash-es": "4.17.21",
97059705
"sortablejs": "1.13.0",
9706-
"vscode-codicons": "0.0.17",
9707-
"vsls": "1.0.3015"
9706+
"vscode-codicons": "0.0.17"
97089707
},
97099708
"devDependencies": {
97109709
"@types/chroma-js": "2.1.3",
97119710
"@types/lodash-es": "4.17.4",
97129711
"@types/node": "14.17.4",
97139712
"@types/sortablejs": "1.10.6",
97149713
"@types/vscode": "1.57.0",
9715-
"@typescript-eslint/eslint-plugin": "4.28.2",
9716-
"@typescript-eslint/parser": "4.28.2",
9714+
"@typescript-eslint/eslint-plugin": "4.28.3",
9715+
"@typescript-eslint/parser": "4.28.3",
97179716
"circular-dependency-plugin": "5.2.2",
97189717
"clean-webpack-plugin": "3.0.0",
97199718
"copy-webpack-plugin": "9.0.1",
@@ -9738,7 +9737,7 @@
97389737
"terser-webpack-plugin": "5.1.4",
97399738
"ts-loader": "9.2.3",
97409739
"typescript": "4.4.0-beta",
9741-
"vsce": "1.95.0",
9740+
"vsce": "1.95.1",
97429741
"webpack": "5.44.0",
97439742
"webpack-bundle-analyzer": "4.4.2",
97449743
"webpack-cli": "4.2.0"

src/@types/vsls.d.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { CancellationToken, Disposable, Event, TreeDataProvider, Uri } from 'vscode';
2+
3+
export interface LiveShareExtension {
4+
getApi(version: string): Promise<LiveShare | null>;
5+
}
6+
7+
export interface LiveShare {
8+
readonly session: Session;
9+
readonly onDidChangeSession: Event<SessionChangeEvent>;
10+
11+
share(options?: ShareOptions): Promise<Uri | null>;
12+
shareService(name: string): Promise<SharedService | null>;
13+
unshareService(name: string): Promise<void>;
14+
getSharedService(name: string): Promise<SharedServiceProxy | null>;
15+
convertLocalUriToShared(localUri: Uri): Uri;
16+
convertSharedUriToLocal(sharedUri: Uri): Uri;
17+
getContacts(emails: string[]): Promise<Contacts>;
18+
}
19+
20+
export const enum Access {
21+
None = 0,
22+
ReadOnly = 1,
23+
ReadWrite = 3,
24+
Owner = 0xff,
25+
}
26+
27+
export const enum Role {
28+
None = 0,
29+
Host = 1,
30+
Guest = 2,
31+
}
32+
33+
export interface Session {
34+
readonly id: string | null;
35+
readonly role: Role;
36+
readonly access: Access;
37+
}
38+
39+
export interface SessionChangeEvent {
40+
readonly session: Session;
41+
}
42+
43+
export interface Contact {
44+
readonly onDidChange: Event<string[]>;
45+
readonly id: string;
46+
readonly email: string;
47+
readonly displayName?: string;
48+
readonly status?: string;
49+
readonly avatarUri?: string;
50+
51+
invite(options?: ContactInviteOptions): Promise<boolean>;
52+
}
53+
54+
export interface Contacts {
55+
readonly contacts: { [email: string]: Contact };
56+
dispose(): Promise<void>;
57+
}
58+
59+
export interface ContactInviteOptions {
60+
useEmail?: boolean;
61+
}
62+
63+
export interface SharedService {
64+
readonly isServiceAvailable: boolean;
65+
readonly onDidChangeIsServiceAvailable: Event<boolean>;
66+
67+
onRequest(name: string, handler: RequestHandler): void;
68+
onNotify(name: string, handler: NotifyHandler): void;
69+
notify(name: string, args: object): void;
70+
}
71+
72+
export interface SharedServiceProxy {
73+
readonly isServiceAvailable: boolean;
74+
readonly onDidChangeIsServiceAvailable: Event<boolean>;
75+
76+
onNotify(name: string, handler: NotifyHandler): void;
77+
request(name: string, args: any[], cancellation?: CancellationToken): Promise<any>;
78+
notify(name: string, args: object): void;
79+
}
80+
81+
export interface SharedServiceProxyError extends Error {}
82+
83+
export interface SharedServiceResponseError extends Error {
84+
remoteStack?: string;
85+
}
86+
87+
export interface RequestHandler {
88+
(args: any[], cancellation: CancellationToken): any | Promise<any>;
89+
}
90+
91+
export interface NotifyHandler {
92+
(args: object): void;
93+
}

src/git/gitService.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
env,
99
Event,
1010
EventEmitter,
11-
Extension,
1211
extensions,
1312
ProgressLocation,
1413
Range,
@@ -4275,10 +4274,9 @@ export class GitService implements Disposable {
42754274
@log()
42764275
static async getBuiltInGitApi(): Promise<BuiltInGitApi | undefined> {
42774276
try {
4278-
const extension = extensions.getExtension('vscode.git') as Extension<GitExtension>;
4277+
const extension = extensions.getExtension<GitExtension>('vscode.git');
42794278
if (extension != null) {
42804279
const gitExtension = extension.isActive ? extension.exports : await extension.activate();
4281-
42824280
return gitExtension.getAPI(1);
42834281
}
42844282
} catch {}

src/vsls/guest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22
import { CancellationToken, Disposable, window, WorkspaceFolder } from 'vscode';
3-
import { LiveShare, SharedServiceProxy } from 'vsls';
3+
import type { LiveShare, SharedServiceProxy } from '../@types/vsls';
44
import { setEnabled } from '../extension';
55
import { GitCommandOptions, Repository, RepositoryChangeEvent } from '../git/git';
66
import { Logger } from '../logger';

src/vsls/host.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22
import { CancellationToken, Disposable, Uri, workspace, WorkspaceFoldersChangeEvent } from 'vscode';
3-
import { LiveShare, SharedService } from 'vsls';
3+
import type { LiveShare, SharedService } from '../@types/vsls';
44
import { Container } from '../container';
55
import { git } from '../git/git';
66
import { GitUri } from '../git/gitUri';

src/vsls/vsls.ts

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
2-
import { Disposable, workspace } from 'vscode';
3-
import { getApi, LiveShare, Role, SessionChangeEvent } from 'vsls';
2+
import { Disposable, extensions, workspace } from 'vscode';
3+
import type { LiveShare, LiveShareExtension, SessionChangeEvent } from '../@types/vsls';
44
import { ContextKeys, DocumentSchemes, setContext } from '../constants';
55
import { Container } from '../container';
66
import { Logger } from '../logger';
@@ -40,7 +40,7 @@ export class VslsController implements Disposable {
4040
private _onReady: (() => void) | undefined;
4141
private _waitForReady: Promise<void> | undefined;
4242

43-
private _api: Promise<LiveShare | null> | undefined;
43+
private _api: Promise<LiveShare | undefined> | undefined;
4444

4545
constructor() {
4646
void this.initialize();
@@ -60,7 +60,7 @@ export class VslsController implements Disposable {
6060
this._waitForReady = new Promise(resolve => (this._onReady = resolve));
6161
}
6262

63-
this._api = getApi();
63+
this._api = this.getLiveShareApi();
6464
const api = await this._api;
6565
if (api == null) {
6666
void setContext(ContextKeys.Vsls, false);
@@ -83,6 +83,18 @@ export class VslsController implements Disposable {
8383
}
8484
}
8585

86+
private async getLiveShareApi(): Promise<LiveShare | undefined> {
87+
try {
88+
const extension = extensions.getExtension<LiveShareExtension>('ms-vsliveshare.vsliveshare');
89+
if (extension != null) {
90+
const liveshareExtension = extension.isActive ? extension.exports : await extension.activate();
91+
return (await liveshareExtension.getApi('1.0.3015')) ?? undefined;
92+
}
93+
} catch {}
94+
95+
return undefined;
96+
}
97+
8698
get isMaybeGuest() {
8799
return this._guest !== undefined || this._waitForReady !== undefined;
88100
}
@@ -112,7 +124,7 @@ export class VslsController implements Disposable {
112124
0: (emails: string[]) => `length=${emails.length}`,
113125
},
114126
})
115-
async getContacts(emails: string[]) {
127+
private async getContacts(emails: string[]) {
116128
const api = await this._api;
117129
if (api == null) return undefined;
118130

@@ -144,7 +156,7 @@ export class VslsController implements Disposable {
144156

145157
@debug()
146158
@timeout(250)
147-
maybeGetPresence(email: string | undefined) {
159+
maybeGetPresence(email: string | undefined): Promise<ContactPresence | undefined> {
148160
return Container.vsls.getContactPresence(email);
149161
}
150162

@@ -178,23 +190,18 @@ export class VslsController implements Disposable {
178190
}
179191

180192
private async onLiveShareSessionChanged(api: LiveShare, e: SessionChangeEvent) {
181-
if (this._host !== undefined) {
182-
this._host.dispose();
183-
}
184-
185-
if (this._guest !== undefined) {
186-
this._guest.dispose();
187-
}
193+
this._host?.dispose();
194+
this._guest?.dispose();
188195

189196
switch (e.session.role) {
190-
case Role.Host:
197+
case 1 /*Role.Host*/:
191198
this.setReadonly(false);
192199
void setContext(ContextKeys.Vsls, 'host');
193200
if (Container.config.liveshare.allowGuestAccess) {
194201
this._host = await VslsHostService.share(api);
195202
}
196203
break;
197-
case Role.Guest:
204+
case 2 /*Role.Guest*/:
198205
this.setReadonly(true);
199206
void setContext(ContextKeys.Vsls, 'guest');
200207
this._guest = await VslsGuestService.connect(api);

0 commit comments

Comments
 (0)