Merge from vscode 1ec43773e37997841c5af42b33ddb180e9735bf2

This commit is contained in:
ADS Merger
2020-03-29 01:29:32 +00:00
parent 586ec50916
commit a64304602e
316 changed files with 6524 additions and 11687 deletions

View File

@@ -32,6 +32,23 @@ const BUILT_IN_AUTH_DEPENDENTS: AuthDependent[] = [
}
];
interface AllowedExtension {
id: string;
name: string;
}
function readAllowedExtensions(storageService: IStorageService, providerId: string, accountName: string): AllowedExtension[] {
let trustedExtensions: AllowedExtension[] = [];
try {
const trustedExtensionSrc = storageService.get(`${providerId}-${accountName}`, StorageScope.GLOBAL);
if (trustedExtensionSrc) {
trustedExtensions = JSON.parse(trustedExtensionSrc);
}
} catch (err) { }
return trustedExtensions;
}
export class MainThreadAuthenticationProvider extends Disposable {
private _sessionMenuItems = new Map<string, IDisposable[]>();
private _accounts = new Map<string, string[]>(); // Map account name to session ids
@@ -48,30 +65,25 @@ export class MainThreadAuthenticationProvider extends Disposable {
this.registerCommandsAndContextMenuItems();
}
private setPermissionsForAccount(quickInputService: IQuickInputService, doLogin?: boolean) {
const quickPick = quickInputService.createQuickPick();
private manageTrustedExtensions(quickInputService: IQuickInputService, storageService: IStorageService, accountName: string) {
const quickPick = quickInputService.createQuickPick<{ label: string, extension: AllowedExtension }>();
quickPick.canSelectMany = true;
const items = this.dependents.map(dependent => {
const allowedExtensions = readAllowedExtensions(storageService, this.id, accountName);
const items = allowedExtensions.map(extension => {
return {
label: dependent.label,
description: dependent.scopeDescriptions,
picked: true,
scopes: dependent.scopes
label: extension.name,
extension
};
});
quickPick.items = items;
// TODO read from storage and filter is not doLogin
quickPick.selectedItems = items;
quickPick.title = nls.localize('signInTo', "Sign in to {0}", this.displayName);
quickPick.placeholder = nls.localize('accountPermissions', "Choose what features and extensions to authorize to use this account");
quickPick.title = nls.localize('manageTrustedExtensions', "Manage Trusted Extensions");
quickPick.placeholder = nls.localize('manageExensions', "Choose which extensions can access this account");
quickPick.onDidAccept(() => {
const scopes = quickPick.selectedItems.reduce((previous, current) => previous.concat((current as any).scopes), []);
if (scopes.length && doLogin) {
this.login(scopes);
}
const updatedAllowedList = quickPick.selectedItems.map(item => item.extension);
storageService.store(`${this.id}-${accountName}`, JSON.stringify(updatedAllowedList), StorageScope.GLOBAL);
quickPick.dispose();
});
@@ -87,7 +99,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
this._register(CommandsRegistry.registerCommand({
id: `signIn${this.id}`,
handler: (accessor, args) => {
this.setPermissionsForAccount(accessor.get(IQuickInputService), true);
this.login(this.dependents.reduce((previous: string[], current) => previous.concat(current.scopes), []));
},
}));
@@ -130,19 +142,26 @@ export class MainThreadAuthenticationProvider extends Disposable {
id: `configureSessions${session.id}`,
handler: (accessor, args) => {
const quickInputService = accessor.get(IQuickInputService);
const storageService = accessor.get(IStorageService);
const quickPick = quickInputService.createQuickPick();
const items = [{ label: 'Sign Out' }];
const manage = nls.localize('manageTrustedExtensions', "Manage Trusted Extensions");
const signOut = nls.localize('signOut', "Sign Out");
const items = ([{ label: manage }, { label: signOut }]);
quickPick.items = items;
quickPick.onDidAccept(e => {
const selected = quickPick.selectedItems[0];
if (selected.label === 'Sign Out') {
if (selected.label === signOut) {
const sessionsForAccount = this._accounts.get(session.accountName);
sessionsForAccount?.forEach(sessionId => this.logout(sessionId));
}
if (selected.label === manage) {
this.manageTrustedExtensions(quickInputService, storageService, session.accountName);
}
quickPick.dispose();
});
@@ -185,6 +204,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
disposeables.forEach(disposeable => disposeable.dispose());
this._sessionMenuItems.delete(accountName);
}
this._accounts.delete(accountName);
}
}
});
@@ -242,55 +262,45 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
this.authenticationService.sessionsUpdate(id, event);
}
async $getSessionsPrompt(providerId: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean> {
const alwaysAllow = this.storageService.get(`${extensionId}-${providerId}`, StorageScope.GLOBAL);
if (alwaysAllow) {
return alwaysAllow === 'true';
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)) {
return true;
}
const { choice, checkboxChecked } = await this.dialogService.show(
const { choice } = await this.dialogService.show(
Severity.Info,
nls.localize('confirmAuthenticationAccess', "The extension '{0}' is trying to access authentication information from {1}.", extensionName, providerName),
nls.localize('confirmAuthenticationAccess', "The extension '{0}' is trying to access authentication information for the {1} account '{2}'.", extensionName, providerName, accountName),
[nls.localize('cancel', "Cancel"), nls.localize('allow', "Allow")],
{
cancelId: 0,
checkbox: {
label: nls.localize('neverAgain', "Don't Show Again")
}
cancelId: 0
}
);
const allow = choice === 1;
if (checkboxChecked) {
this.storageService.store(`${extensionId}-${providerId}`, allow ? 'true' : 'false', StorageScope.GLOBAL);
if (allow) {
allowList = allowList.concat({ id: extensionId, name: extensionName });
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
}
return allow;
}
async $loginPrompt(providerId: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean> {
const alwaysAllow = this.storageService.get(`${extensionId}-${providerId}`, StorageScope.GLOBAL);
if (alwaysAllow) {
return alwaysAllow === 'true';
}
const { choice, checkboxChecked } = await this.dialogService.show(
async $loginPrompt(providerName: string, extensionName: string): Promise<boolean> {
const { choice } = await this.dialogService.show(
Severity.Info,
nls.localize('confirmLogin', "The extension '{0}' wants to sign in using {1}.", extensionName, providerName),
[nls.localize('cancel', "Cancel"), nls.localize('continue', "Continue")],
[nls.localize('cancel', "Cancel"), nls.localize('allow', "Allow")],
{
cancelId: 0,
checkbox: {
label: nls.localize('neverAgain', "Don't Show Again")
}
cancelId: 0
}
);
const allow = choice === 1;
if (checkboxChecked) {
this.storageService.store(`${extensionId}-${providerId}`, allow ? 'true' : 'false', StorageScope.GLOBAL);
}
return choice === 1;
}
return allow;
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);
}
}

View File

@@ -8,9 +8,8 @@ import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IEx
import { Disposable } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/browser/notebookService';
import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellsSplice, NotebookCellOutputsSplice, CellKind, NotebookDocumentMetadata, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellOutputsSplice, CellKind, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
@@ -30,16 +29,17 @@ export class MainThreadNotebookDocument extends Disposable {
) {
super();
this._textModel = new NotebookTextModel(handle, viewType, uri);
this._register(this._textModel.onDidModelChange(e => {
this._proxy.$acceptModelChanged(this.uri, e);
}));
}
async deleteCell(uri: URI, index: number): Promise<boolean> {
let deleteExtHostCell = await this._proxy.$deleteCell(this.viewType, uri, index);
if (deleteExtHostCell) {
this._textModel.removeCell(index);
return true;
}
applyEdit(modelVersionId: number, edits: ICellEditOperation[]): boolean {
return this._textModel.applyEdit(modelVersionId, edits);
}
return false;
updateRenderers(renderers: number[]) {
this._textModel.updateRenderers(renderers);
}
dispose() {
@@ -65,6 +65,16 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
this.registerListeners();
}
async $tryApplyEdits(viewType: string, resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[], renderers: number[]): Promise<boolean> {
let controller = this._notebookProviders.get(viewType);
if (controller) {
return controller.tryApplyEdits(resource, modelVersionId, edits, renderers);
}
return false;
}
registerListeners() {
this._register(this._notebookService.onDidChangeActiveEditor(e => {
this._proxy.$updateActiveEditor(e.viewType, e.uri);
@@ -148,11 +158,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
return handle;
}
async $spliceNotebookCells(viewType: string, resource: UriComponents, splices: NotebookCellsSplice[], renderers: number[]): Promise<void> {
let controller = this._notebookProviders.get(viewType);
controller?.spliceNotebookCells(resource, splices, renderers);
}
async $spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void> {
let controller = this._notebookProviders.get(viewType);
controller?.spliceNotebookCellOutputs(resource, cellHandle, splices, renderers);
@@ -201,11 +206,8 @@ export class MainThreadNotebookController implements IMainNotebookController {
mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
if (mainthreadNotebook && mainthreadNotebook.textModel.cells.length === 0) {
// it's empty, we should create an empty template one
const templateCell = await this._proxy.$createEmptyCell(this._viewType, uri, 0, mainthreadNotebook.textModel.languages.length ? mainthreadNotebook.textModel.languages[0] : '', CellKind.Code);
if (templateCell) {
let mainCell = new NotebookCellTextModel(URI.revive(templateCell.uri), templateCell.handle, templateCell.source, templateCell.language, templateCell.cellKind, templateCell.outputs, templateCell.metadata);
mainthreadNotebook.textModel.insertTemplateCell(mainCell);
}
const mainCell = mainthreadNotebook.textModel.createCellTextModel([''], mainthreadNotebook.textModel.languages.length ? mainthreadNotebook.textModel.languages[0] : '', CellKind.Code, [], undefined);
mainthreadNotebook.textModel.insertTemplateCell(mainCell);
}
return mainthreadNotebook?.textModel;
}
@@ -213,10 +215,15 @@ export class MainThreadNotebookController implements IMainNotebookController {
return undefined;
}
spliceNotebookCells(resource: UriComponents, splices: NotebookCellsSplice[], renderers: number[]): void {
async tryApplyEdits(resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[], renderers: number[]): Promise<boolean> {
let mainthreadNotebook = this._mapping.get(URI.from(resource).toString());
mainthreadNotebook?.textModel.updateRenderers(renderers);
mainthreadNotebook?.textModel.$spliceNotebookCells(splices);
if (mainthreadNotebook) {
mainthreadNotebook.updateRenderers(renderers);
return mainthreadNotebook.applyEdit(modelVersionId, edits);
}
return false;
}
spliceNotebookCellOutputs(resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): void {
@@ -259,26 +266,6 @@ export class MainThreadNotebookController implements IMainNotebookController {
document?.textModel.updateRenderers(renderers);
}
async createRawCell(uri: URI, index: number, language: string, type: CellKind): Promise<NotebookCellTextModel | undefined> {
let cell = await this._proxy.$createEmptyCell(this._viewType, uri, index, language, type);
if (cell) {
let mainCell = new NotebookCellTextModel(URI.revive(cell.uri), cell.handle, cell.source, cell.language, cell.cellKind, cell.outputs, cell.metadata);
return mainCell;
}
return undefined;
}
async deleteCell(uri: URI, index: number): Promise<boolean> {
let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
if (mainthreadNotebook) {
return mainthreadNotebook.deleteCell(uri, index);
}
return false;
}
async executeNotebookCell(uri: URI, handle: number): Promise<void> {
return this._proxy.$executeNotebook(this._viewType, uri, handle);
}

View File

@@ -9,7 +9,7 @@ import { localize } from 'vs/nls';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IProgressStep, IProgress } from 'vs/platform/progress/common/progress';
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { ITextFileSaveParticipant, IResolvedTextFileEditorModel, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { ITextFileSaveParticipant, ITextFileService, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
import { SaveReason } from 'vs/workbench/common/editor';
import { ExtHostContext, ExtHostDocumentSaveParticipantShape, IExtHostContext } from '../common/extHost.protocol';
import { canceled } from 'vs/base/common/errors';
@@ -23,9 +23,9 @@ class ExtHostSaveParticipant implements ITextFileSaveParticipant {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentSaveParticipant);
}
async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason; }, _progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
async participate(editorModel: ITextFileEditorModel, env: { reason: SaveReason; }, _progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
if (!shouldSynchronizeModel(editorModel.textEditorModel)) {
if (!editorModel.textEditorModel || !shouldSynchronizeModel(editorModel.textEditorModel)) {
// the model never made it to the extension
// host meaning we cannot participate in its save
return undefined;

View File

@@ -13,6 +13,8 @@ import { ITerminalInstanceService, ITerminalService, ITerminalInstance, ITermina
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
import { IEnvironmentVariableService, ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
@@ -29,8 +31,9 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
extHostContext: IExtHostContext,
@ITerminalService private readonly _terminalService: ITerminalService,
@ITerminalInstanceService readonly terminalInstanceService: ITerminalInstanceService,
@IRemoteAgentService readonly _remoteAgentService: IRemoteAgentService,
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IEnvironmentVariableService private readonly _environmentVariableService: IEnvironmentVariableService,
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
this._remoteAuthority = extHostContext.remoteAuthority;
@@ -71,6 +74,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
if (activeInstance) {
this._proxy.$acceptActiveTerminalChanged(activeInstance.id);
}
if (this._environmentVariableService.collections.size > 0) {
const collectionAsArray = [...this._environmentVariableService.collections.entries()];
const serializedCollections: [string, ISerializableEnvironmentVariableCollection][] = collectionAsArray.map(e => {
return [e[0], serializeEnvironmentVariableCollection(e[1].map)];
});
this._proxy.$initEnvironmentVariableCollections(serializedCollections);
}
this._terminalService.extHostReady(extHostContext.remoteAuthority);
}
@@ -346,6 +356,18 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
}
return terminal;
}
$setEnvironmentVariableCollection(extensionIdentifier: string, persistent: boolean, collection: ISerializableEnvironmentVariableCollection | undefined): void {
if (collection) {
const translatedCollection = {
persistent,
map: deserializeEnvironmentVariableCollection(collection)
};
this._environmentVariableService.set(extensionIdentifier, translatedCollection);
} else {
this._environmentVariableService.delete(extensionIdentifier);
}
}
}
/**

View File

@@ -11,7 +11,7 @@ import { Disposable, DisposableStore, dispose, IDisposable, IReference } from 'v
import { Schemas } from 'vs/base/common/network';
import { basename } from 'vs/base/common/path';
import { isWeb } from 'vs/base/common/platform';
import { isEqual } from 'vs/base/common/resources';
import { isEqual, isEqualOrParent } from 'vs/base/common/resources';
import { escape } from 'vs/base/common/strings';
import { URI, UriComponents } from 'vs/base/common/uri';
import * as modes from 'vs/editor/common/modes';
@@ -35,9 +35,11 @@ import { CustomTextEditorModel } from 'vs/workbench/contrib/customEditor/common/
import { WebviewExtensionDescription, WebviewIcons } from 'vs/workbench/contrib/webview/browser/webview';
import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput';
import { ICreateWebViewShowOptions, IWebviewWorkbenchService, WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
import { IWorkingCopy, IWorkingCopyBackup, IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { extHostNamedCustomer } from '../common/extHostCustomers';
@@ -121,6 +123,8 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
constructor(
context: extHostProtocol.IExtHostContext,
@IExtensionService extensionService: IExtensionService,
@IWorkingCopyService workingCopyService: IWorkingCopyService,
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService,
@ICustomEditorService private readonly _customEditorService: ICustomEditorService,
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
@IEditorService private readonly _editorService: IEditorService,
@@ -164,6 +168,20 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
},
resolveWebview: () => { throw new Error('not implemented'); }
}));
workingCopyFileService.registerWorkingCopyProvider((editorResource) => {
const matchedWorkingCopies: IWorkingCopy[] = [];
for (const workingCopy of workingCopyService.workingCopies) {
if (workingCopy instanceof MainThreadCustomEditorModel) {
if (isEqualOrParent(editorResource, workingCopy.editorResource)) {
matchedWorkingCopies.push(workingCopy);
}
}
}
return matchedWorkingCopies;
});
}
public $createWebviewPanel(
@@ -564,6 +582,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
private _currentEditIndex: number = -1;
private _savePoint: number = -1;
private readonly _edits: Array<number> = [];
private _fromBackup: boolean = false;
public static async create(
instantiationService: IInstantiationService,
@@ -574,7 +593,9 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
cancellation: CancellationToken,
) {
const { editable } = await proxy.$createWebviewCustomEditorDocument(resource, viewType, cancellation);
return instantiationService.createInstance(MainThreadCustomEditorModel, proxy, viewType, resource, editable, getEditors);
const model = instantiationService.createInstance(MainThreadCustomEditorModel, proxy, viewType, resource, editable, getEditors);
await model.init();
return model;
}
constructor(
@@ -587,6 +608,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
@ILabelService private readonly _labelService: ILabelService,
@IFileService private readonly _fileService: IFileService,
@IUndoRedoService private readonly _undoService: IUndoRedoService,
@IBackupFileService private readonly _backupFileService: IBackupFileService,
) {
super();
@@ -595,6 +617,15 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
}
}
get editorResource() {
return this._editorResource;
}
async init(): Promise<void> {
const backup = await this._backupFileService.resolve<CustomDocumentBackupData>(this.resource);
this._fromBackup = !!backup;
}
dispose() {
if (this._editable) {
this._undoService.removeElements(this._editorResource);
@@ -624,7 +655,10 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
}
public isDirty(): boolean {
return this._edits.length > 0 && this._savePoint !== this._currentEditIndex;
if (this._edits.length > 0) {
return this._savePoint !== this._currentEditIndex;
}
return this._fromBackup;
}
private readonly _onDidChangeDirty: Emitter<void> = this._register(new Emitter<void>());