Merge from vscode 6fded8a497cd0142de3a1c607649a5423a091a25

This commit is contained in:
ADS Merger
2020-04-04 04:30:52 +00:00
parent 00cc0074f7
commit 35f1a014d5
184 changed files with 3043 additions and 2285 deletions

View File

@@ -35,6 +35,7 @@ const BUILT_IN_AUTH_DEPENDENTS: AuthDependent[] = [
interface AllowedExtension {
id: string;
name: string;
sessionIds?: string[];
}
function readAllowedExtensions(storageService: IStorageService, providerId: string, accountName: string): AllowedExtension[] {
@@ -85,6 +86,16 @@ export class MainThreadAuthenticationProvider extends Disposable {
quickPick.onDidAccept(() => {
const updatedAllowedList = quickPick.selectedItems.map(item => item.extension);
storageService.store(`${this.id}-${accountName}`, JSON.stringify(updatedAllowedList), StorageScope.GLOBAL);
// Remove sessions of untrusted extensions
const deselectedItems = items.filter(item => !quickPick.selectedItems.includes(item));
deselectedItems.forEach(item => {
const extensionData = allowedExtensions.find(extension => item.extension.id === extension.id);
extensionData?.sessionIds?.forEach(sessionId => {
this.logout(sessionId);
});
});
quickPick.dispose();
});
@@ -275,9 +286,19 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
this.authenticationService.sessionsUpdate(id, event);
}
async $getSessionsPrompt(providerId: string, accountName: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean> {
let allowList = readAllowedExtensions(this.storageService, providerId, accountName);
if (allowList.some(extension => extension.id === extensionId)) {
async $getSessionsPrompt(providerId: string, accountName: string, sessionId: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean> {
const allowList = readAllowedExtensions(this.storageService, providerId, accountName);
const extensionData = allowList.find(extension => extension.id === extensionId);
if (extensionData) {
if (!extensionData.sessionIds) {
extensionData.sessionIds = [];
}
if (!extensionData.sessionIds.find(id => id === sessionId)) {
extensionData.sessionIds.push(sessionId);
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
}
return true;
}
@@ -292,7 +313,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
const allow = choice === 1;
if (allow) {
allowList = allowList.concat({ id: extensionId, name: extensionName });
allowList.push({ id: extensionId, name: extensionName, sessionIds: [sessionId] });
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
}
@@ -313,7 +334,10 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
}
async $setTrustedExtension(providerId: string, accountName: string, extensionId: string, extensionName: string): Promise<void> {
const allowList = readAllowedExtensions(this.storageService, providerId, accountName).concat({ id: extensionId, name: extensionName });
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
const allowList = readAllowedExtensions(this.storageService, providerId, accountName);
if (!allowList.find(allowed => allowed.id === extensionId)) {
allowList.push({ id: extensionId, name: extensionName, sessionIds: [] });
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
}
}
}

View File

@@ -267,7 +267,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
resolveWebview: async (webviewInput): Promise<void> => {
const viewType = webviewPanelViewType.toExternal(webviewInput.viewType);
if (!viewType) {
webviewInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(webviewInput.viewType);
webviewInput.webview.html = MainThreadWebviews.getWebviewResolvedFailedContent(webviewInput.viewType);
return;
}
@@ -288,7 +288,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
await this._proxy.$deserializeWebviewPanel(handle, viewType, webviewInput.getTitle(), state, editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), webviewInput.webview.options);
} catch (error) {
onUnexpectedError(error);
webviewInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
webviewInput.webview.html = MainThreadWebviews.getWebviewResolvedFailedContent(viewType);
}
}
}));
@@ -339,7 +339,15 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
webviewInput.webview.options = options;
webviewInput.webview.extension = extension;
let modelRef = await this.getOrCreateCustomEditorModel(modelType, resource, viewType, cancellation);
let modelRef: IReference<ICustomEditorModel>;
try {
modelRef = await this.getOrCreateCustomEditorModel(modelType, resource, viewType, cancellation);
} catch (error) {
onUnexpectedError(error);
webviewInput.webview.html = MainThreadWebviews.getWebviewResolvedFailedContent(viewType);
return;
}
if (cancellation.isCancellationRequested) {
modelRef.dispose();
return;
@@ -362,7 +370,8 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
await this._proxy.$resolveWebviewEditor(resource, handle, viewType, webviewInput.getTitle(), editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), webviewInput.webview.options, cancellation);
} catch (error) {
onUnexpectedError(error);
webviewInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
webviewInput.webview.html = MainThreadWebviews.getWebviewResolvedFailedContent(viewType);
modelRef.dispose();
return;
}
}
@@ -522,14 +531,14 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
return this._webviewInputs.getInputForHandle(handle);
}
private static getDeserializationFailedContents(viewType: string) {
private static getWebviewResolvedFailedContent(viewType: string) {
return `<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none';">
</head>
<body>${localize('errorMessage', "An error occurred while restoring view:{0}", escape(viewType))}</body>
<body>${localize('errorMessage', "An error occurred while loading view: {0}", escape(viewType))}</body>
</html>`;
}
}
@@ -795,6 +804,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
return undefined;
}
// TODO: handle save untitled case
// TODO: handle cancellation
await createCancelablePromise(token => this._proxy.$onSave(this._editorResource, this.viewType, token));
this.change(() => {
this._savePoint = this._currentEditIndex;
@@ -804,7 +814,8 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
public async saveCustomEditorAs(resource: URI, targetResource: URI, _options?: ISaveOptions): Promise<boolean> {
if (this._editable) {
await this._proxy.$onSaveAs(this._editorResource, this.viewType, targetResource);
// TODO: handle cancellation
await createCancelablePromise(token => this._proxy.$onSaveAs(this._editorResource, this.viewType, targetResource, token));
this.change(() => {
this._savePoint = this._currentEditIndex;
});

View File

@@ -134,7 +134,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors));
const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol));
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol));
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol, extHostStorage));
const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol, extHostCommands));
const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, initData.environment, extHostWorkspace, extHostLogService, extHostApiDeprecation, extHostDocuments));
@@ -585,7 +585,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => {
return extHostWebviews.registerWebviewPanelSerializer(extension, viewType, serializer);
},
registerCustomEditorProvider: (viewType: string, provider: vscode.CustomEditorProvider | vscode.CustomTextEditorProvider, options?: { webviewOptions?: vscode.WebviewPanelOptions }) => {
registerCustomEditorProvider: (viewType: string, provider: vscode.CustomTextEditorProvider, options?: { webviewOptions?: vscode.WebviewPanelOptions }) => {
return extHostWebviews.registerCustomEditorProvider(extension, viewType, provider, options?.webviewOptions);
},
registerCustomEditorProvider2: (viewType: string, provider: vscode.CustomEditorProvider, options?: { webviewOptions?: vscode.WebviewPanelOptions }) => {
checkProposedApiEnabled(extension);
return extHostWebviews.registerCustomEditorProvider(extension, viewType, provider, options?.webviewOptions);
},
registerDecorationProvider(provider: vscode.DecorationProvider) {

View File

@@ -162,7 +162,7 @@ export interface MainThreadAuthenticationShape extends IDisposable {
$registerAuthenticationProvider(id: string, displayName: string): void;
$unregisterAuthenticationProvider(id: string): void;
$onDidChangeSessions(providerId: string, event: modes.AuthenticationSessionsChangeEvent): void;
$getSessionsPrompt(providerId: string, accountName: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean>;
$getSessionsPrompt(providerId: string, accountName: string, sessionId: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean>;
$loginPrompt(providerName: string, extensionName: string): Promise<boolean>;
$setTrustedExtension(providerId: string, accountName: string, extensionId: string, extensionName: string): Promise<void>;
}
@@ -653,7 +653,7 @@ export interface ExtHostWebviewsShape {
$disposeEdits(resourceComponents: UriComponents, viewType: string, editIds: number[]): void;
$onSave(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void>;
$onSaveAs(resource: UriComponents, viewType: string, targetResource: UriComponents): Promise<void>;
$onSaveAs(resource: UriComponents, viewType: string, targetResource: UriComponents, cancellation: CancellationToken): Promise<void>;
$backup(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void>;

View File

@@ -9,6 +9,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import { IMainContext, MainContext, MainThreadAuthenticationShape, ExtHostAuthenticationShape } from 'vs/workbench/api/common/extHost.protocol';
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
import { IExtensionDescription, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
export class ExtHostAuthentication implements ExtHostAuthenticationShape {
private _proxy: MainThreadAuthenticationShape;
@@ -20,7 +21,8 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
private _onDidChangeSessions = new Emitter<{ [providerId: string]: vscode.AuthenticationSessionsChangeEvent }>();
readonly onDidChangeSessions: Event<{ [providerId: string]: vscode.AuthenticationSessionsChangeEvent }> = this._onDidChangeSessions.event;
constructor(mainContext: IMainContext) {
constructor(mainContext: IMainContext,
@IExtHostStorage private readonly storageService: IExtHostStorage) {
this._proxy = mainContext.getProxy(MainContext.MainThreadAuthentication);
}
@@ -33,15 +35,34 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
return ids;
}
private async hasNotBeenReadByOtherExtension(providerId: string, session: vscode.AuthenticationSession, extensionId: string): Promise<boolean> {
const readerId = await this.storageService.getValue(true, `${providerId}-${session.accountName}-${session.id}`);
if (!readerId) {
await this.storageService.setValue(true, `${providerId}-${session.accountName}-${session.id}`, extensionId as any);
return true;
}
return readerId === extensionId;
}
private async isMatchingSession(session: vscode.AuthenticationSession, scopes: string, providerId: string, extensionId: string): Promise<boolean> {
return session.scopes.sort().join(' ') === scopes && (await this.hasNotBeenReadByOtherExtension(providerId, session, extensionId));
}
async getSessions(requestingExtension: IExtensionDescription, providerId: string, scopes: string[]): Promise<readonly vscode.AuthenticationSession[]> {
const provider = this._authenticationProviders.get(providerId);
if (!provider) {
throw new Error(`No authentication provider with id '${providerId}' is currently registered.`);
}
const extensionId = ExtensionIdentifier.toKey(requestingExtension.identifier);
const orderedScopes = scopes.sort().join(' ');
return (await provider.getSessions())
.filter(session => session.scopes.sort().join(' ') === orderedScopes)
const sessions = await provider.getSessions();
const filteredSessions = await Promise.all(sessions.map(session => this.isMatchingSession(session, orderedScopes, providerId, extensionId)));
return sessions
.filter((_, i) => { return filteredSessions[i]; })
.map(session => {
return {
id: session.id,
@@ -51,8 +72,9 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
const isAllowed = await this._proxy.$getSessionsPrompt(
provider.id,
session.accountName,
session.id,
provider.displayName,
ExtensionIdentifier.toKey(requestingExtension.identifier),
extensionId,
requestingExtension.displayName || requestingExtension.name);
if (!isAllowed) {
@@ -77,9 +99,28 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
throw new Error('User did not consent to login.');
}
const newSession = await provider.login(scopes);
await this._proxy.$setTrustedExtension(provider.id, newSession.accountName, ExtensionIdentifier.toKey(requestingExtension.identifier), extensionName);
return newSession;
const session = await provider.login(scopes);
await this._proxy.$setTrustedExtension(provider.id, session.accountName, ExtensionIdentifier.toKey(requestingExtension.identifier), extensionName);
return {
id: session.id,
accountName: session.accountName,
scopes: session.scopes,
getAccessToken: async () => {
const isAllowed = await this._proxy.$getSessionsPrompt(
provider.id,
session.accountName,
session.id,
provider.displayName,
ExtensionIdentifier.toKey(requestingExtension.identifier),
requestingExtension.displayName || requestingExtension.name);
if (!isAllowed) {
throw new Error('User did not consent to token access.');
}
return session.getAccessToken();
}
};
}
registerAuthenticationProvider(provider: vscode.AuthenticationProvider): vscode.Disposable {

View File

@@ -402,11 +402,12 @@ export class NotebookEditorCellEdit {
}
}
insert(index: number, content: string, language: string, type: CellKind, outputs: vscode.CellOutput[], metadata: vscode.NotebookCellMetadata | undefined): void {
insert(index: number, content: string | string[], language: string, type: CellKind, outputs: vscode.CellOutput[], metadata: vscode.NotebookCellMetadata | undefined): void {
this._throwIfFinalized();
const sourceArr = Array.isArray(content) ? content : content.split(/\r|\n|\r\n/g);
let cell = {
source: [content],
source: sourceArr,
language,
cellKind: type,
outputs: (outputs as any[]), // TODO@rebornix

View File

@@ -16,7 +16,7 @@ import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/p
import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
import type * as vscode from 'vscode';
import { Cache } from './cache';
import { assertIsDefined } from 'vs/base/common/types';
import { assertIsDefined, isStringArray } from 'vs/base/common/types';
import { Schemas } from 'vs/base/common/network';
function es5ClassCompat(target: Function): any {
@@ -2420,25 +2420,14 @@ export class SemanticTokensLegend {
public readonly tokenTypes: string[];
public readonly tokenModifiers: string[];
constructor(tokenTypes: string[], tokenModifiers: string[]) {
constructor(tokenTypes: string[], tokenModifiers: string[] = []) {
this.tokenTypes = tokenTypes;
this.tokenModifiers = tokenModifiers;
}
}
function isStrArrayOrUndefined(arg: any): arg is string[] | undefined {
if (typeof arg === 'undefined') {
return true;
}
if (Array.isArray(arg)) {
for (const element of arg) {
if (typeof element !== 'string') {
return false;
}
}
return true;
}
return false;
return ((typeof arg === 'undefined') || isStringArray(arg));
}
export class SemanticTokensBuilder {
@@ -2472,10 +2461,13 @@ export class SemanticTokensBuilder {
}
}
public push(line: number, char: number, length: number, tokenType: number, tokenModifiers: number): void;
public push(line: number, char: number, length: number, tokenType: number, tokenModifiers?: number): void;
public push(range: Range, tokenType: string, tokenModifiers?: string[]): void;
public push(arg0: any, arg1: any, arg2: any, arg3?: any, arg4?: any): void {
if (typeof arg0 === 'number' && typeof arg1 === 'number' && typeof arg2 === 'number' && typeof arg3 === 'number' && typeof arg4 === 'number') {
if (typeof arg0 === 'number' && typeof arg1 === 'number' && typeof arg2 === 'number' && typeof arg3 === 'number' && (typeof arg4 === 'number' || typeof arg4 === 'undefined')) {
if (typeof arg4 === 'undefined') {
arg4 = 0;
}
// 1st overload
return this._pushEncoded(arg0, arg1, arg2, arg3, arg4);
}

View File

@@ -630,10 +630,10 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
return delegate.save(document, cancellation);
}
async $onSaveAs(resourceComponents: UriComponents, viewType: string, targetResource: UriComponents): Promise<void> {
async $onSaveAs(resourceComponents: UriComponents, viewType: string, targetResource: UriComponents, cancellation: CancellationToken): Promise<void> {
const delegate = this.getEditingDelegate(viewType);
const document = this.getCustomDocument(viewType, resourceComponents);
return delegate.saveAs(document, URI.revive(targetResource));
return delegate.saveAs(document, URI.revive(targetResource), cancellation);
}
async $backup(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void> {

View File

@@ -41,10 +41,10 @@ namespace schema {
case 'menuBar/webNavigation': return MenuId.MenubarWebNavigationMenu;
case 'scm/title': return MenuId.SCMTitle;
case 'scm/sourceControl': return MenuId.SCMSourceControl;
case 'scm/resourceState/context': return MenuId.SCMResourceContext;
case 'scm/resourceState/context': return MenuId.SCMResourceContext;//
case 'scm/resourceFolder/context': return MenuId.SCMResourceFolderContext;
case 'scm/resourceGroup/context': return MenuId.SCMResourceGroupContext;
case 'scm/change/title': return MenuId.SCMChangeContext;
case 'scm/change/title': return MenuId.SCMChangeContext;//
case 'statusBar/windowIndicator': return MenuId.StatusBarWindowIndicatorMenu;
case 'view/title': return MenuId.ViewTitle;
case 'view/item/context': return MenuId.ViewItemContext;
@@ -171,6 +171,11 @@ namespace schema {
type: 'array',
items: menuItem
},
'menuBar/webNavigation': {
description: localize('menus.webNavigation', "The top level navigational menu (web only)"),
type: 'array',
items: menuItem
},
'scm/title': {
description: localize('menus.scmTitle', "The Source Control title menu"),
type: 'array',
@@ -191,6 +196,16 @@ namespace schema {
type: 'array',
items: menuItem
},
'scm/resourceFolder/context': {
description: localize('menus.resourceFolderContext', "The Source Control resource folder context menu"),
type: 'array',
items: menuItem
},
'scm/change/title': {
description: localize('menus.changeTitle', "The Source Control inline change menu"),
type: 'array',
items: menuItem
},
'view/title': {
description: localize('view.viewTitle', "The contributed view title menu"),
type: 'array',