mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-07 17:23:56 -05:00
Merge from vscode 1ec43773e37997841c5af42b33ddb180e9735bf2
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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>());
|
||||
|
||||
Reference in New Issue
Block a user