mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-09 17:52:34 -05:00
Merge from vscode 4d91d96e5e121b38d33508cdef17868bab255eae
This commit is contained in:
committed by
AzureDataStudio
parent
a971aee5bd
commit
5e7071e466
@@ -41,6 +41,7 @@ import './mainThreadMessageService';
|
||||
import './mainThreadOutputService';
|
||||
import './mainThreadProgress';
|
||||
import './mainThreadQuickOpen';
|
||||
import './mainThreadRemoteConnectionData';
|
||||
import './mainThreadSaveParticipant';
|
||||
import './mainThreadSCM';
|
||||
import './mainThreadSearch';
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import * as nls from 'vs/nls';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
@@ -12,15 +12,13 @@ import { ExtHostAuthenticationShape, ExtHostContext, IExtHostContext, MainContex
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { fromNow } from 'vs/base/common/date';
|
||||
|
||||
const VSO_ALLOWED_EXTENSIONS = ['github.vscode-pull-request-github', 'github.vscode-pull-request-github-insiders', 'vscode.git'];
|
||||
const VSO_ALLOWED_EXTENSIONS = ['github.vscode-pull-request-github', 'github.vscode-pull-request-github-insiders', 'vscode.git', 'ms-vsonline.vsonline'];
|
||||
|
||||
interface IAccountUsage {
|
||||
extensionId: string;
|
||||
@@ -71,7 +69,6 @@ function addAccountUsage(storageService: IStorageService, providerId: string, ac
|
||||
}
|
||||
|
||||
export class MainThreadAuthenticationProvider extends Disposable {
|
||||
private _sessionMenuItems = new Map<string, IDisposable[]>();
|
||||
private _accounts = new Map<string, string[]>(); // Map account name to session ids
|
||||
private _sessions = new Map<string, string>(); // Map account id to name
|
||||
|
||||
@@ -82,7 +79,9 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
public readonly supportsMultipleAccounts: boolean,
|
||||
private readonly notificationService: INotificationService,
|
||||
private readonly storageKeysSyncRegistryService: IStorageKeysSyncRegistryService,
|
||||
private readonly storageService: IStorageService
|
||||
private readonly storageService: IStorageService,
|
||||
private readonly quickInputService: IQuickInputService,
|
||||
private readonly dialogService: IDialogService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -95,11 +94,11 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
return !!this._sessions.size;
|
||||
}
|
||||
|
||||
private manageTrustedExtensions(quickInputService: IQuickInputService, storageService: IStorageService, accountName: string) {
|
||||
const quickPick = quickInputService.createQuickPick<{ label: string, description: string, extension: AllowedExtension }>();
|
||||
public manageTrustedExtensions(accountName: string) {
|
||||
const quickPick = this.quickInputService.createQuickPick<{ label: string, description: string, extension: AllowedExtension }>();
|
||||
quickPick.canSelectMany = true;
|
||||
const allowedExtensions = readAllowedExtensions(storageService, this.id, accountName);
|
||||
const usages = readAccountUsages(storageService, this.id, accountName);
|
||||
const allowedExtensions = readAllowedExtensions(this.storageService, this.id, accountName);
|
||||
const usages = readAccountUsages(this.storageService, this.id, accountName);
|
||||
const items = allowedExtensions.map(extension => {
|
||||
const usage = usages.find(usage => extension.id === usage.extensionId);
|
||||
return {
|
||||
@@ -118,7 +117,7 @@ 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);
|
||||
this.storageService.store(`${this.id}-${accountName}`, JSON.stringify(updatedAllowedList), StorageScope.GLOBAL);
|
||||
|
||||
quickPick.dispose();
|
||||
});
|
||||
@@ -146,69 +145,23 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
this._accounts.set(session.account.displayName, [session.id]);
|
||||
}
|
||||
|
||||
const menuItem = MenuRegistry.appendMenuItem(MenuId.AccountsContext, {
|
||||
group: '1_accounts',
|
||||
command: {
|
||||
id: `configureSessions${session.id}`,
|
||||
title: `${session.account.displayName} (${this.displayName})`
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
this.storageKeysSyncRegistryService.registerStorageKey({ key: `${this.id}-${session.account.displayName}`, version: 1 });
|
||||
|
||||
const manageCommand = CommandsRegistry.registerCommand({
|
||||
id: `configureSessions${session.id}`,
|
||||
handler: (accessor, args) => {
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
const storageService = accessor.get(IStorageService);
|
||||
const dialogService = accessor.get(IDialogService);
|
||||
|
||||
const quickPick = quickInputService.createQuickPick();
|
||||
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 === signOut) {
|
||||
this.signOut(dialogService, session);
|
||||
}
|
||||
|
||||
if (selected.label === manage) {
|
||||
this.manageTrustedExtensions(quickInputService, storageService, session.account.displayName);
|
||||
}
|
||||
|
||||
quickPick.dispose();
|
||||
});
|
||||
|
||||
quickPick.onDidHide(_ => {
|
||||
quickPick.dispose();
|
||||
});
|
||||
|
||||
quickPick.show();
|
||||
},
|
||||
});
|
||||
|
||||
this._sessionMenuItems.set(session.account.displayName, [menuItem, manageCommand]);
|
||||
}
|
||||
|
||||
async signOut(dialogService: IDialogService, session: modes.AuthenticationSession): Promise<void> {
|
||||
const accountUsages = readAccountUsages(this.storageService, this.id, session.account.displayName);
|
||||
const sessionsForAccount = this._accounts.get(session.account.displayName);
|
||||
async signOut(accountName: string): Promise<void> {
|
||||
const accountUsages = readAccountUsages(this.storageService, this.id, accountName);
|
||||
const sessionsForAccount = this._accounts.get(accountName);
|
||||
|
||||
const result = await dialogService.confirm({
|
||||
title: nls.localize('signOutConfirm', "Sign out of {0}", session.account.displayName),
|
||||
const result = await this.dialogService.confirm({
|
||||
title: nls.localize('signOutConfirm', "Sign out of {0}", accountName),
|
||||
message: accountUsages.length
|
||||
? nls.localize('signOutMessagve', "The account {0} has been used by: \n\n{1}\n\n Sign out of these features?", session.account.displayName, accountUsages.map(usage => usage.extensionName).join('\n'))
|
||||
: nls.localize('signOutMessageSimple', "Sign out of {0}?", session.account.displayName)
|
||||
? nls.localize('signOutMessagve', "The account {0} has been used by: \n\n{1}\n\n Sign out of these features?", accountName, accountUsages.map(usage => usage.extensionName).join('\n'))
|
||||
: nls.localize('signOutMessageSimple', "Sign out of {0}?", accountName)
|
||||
});
|
||||
|
||||
if (result.confirmed) {
|
||||
sessionsForAccount?.forEach(sessionId => this.logout(sessionId));
|
||||
removeAccountUsage(this.storageService, this.id, session.account.displayName);
|
||||
removeAccountUsage(this.storageService, this.id, accountName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,11 +183,6 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
sessionsForAccount.splice(sessionIndex);
|
||||
|
||||
if (!sessionsForAccount.length) {
|
||||
const disposeables = this._sessionMenuItems.get(accountName);
|
||||
if (disposeables) {
|
||||
disposeables.forEach(disposeable => disposeable.dispose());
|
||||
this._sessionMenuItems.delete(accountName);
|
||||
}
|
||||
this._accounts.delete(accountName);
|
||||
}
|
||||
}
|
||||
@@ -251,12 +199,6 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
await this._proxy.$logout(this.id, sessionId);
|
||||
this.notificationService.info(nls.localize('signedOut', "Successfully signed out."));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
this._sessionMenuItems.forEach(item => item.forEach(d => d.dispose()));
|
||||
this._sessionMenuItems.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadAuthentication)
|
||||
@@ -294,7 +236,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||
}
|
||||
|
||||
async $registerAuthenticationProvider(id: string, displayName: string, supportsMultipleAccounts: boolean): Promise<void> {
|
||||
const provider = new MainThreadAuthenticationProvider(this._proxy, id, displayName, supportsMultipleAccounts, this.notificationService, this.storageKeysSyncRegistryService, this.storageService);
|
||||
const provider = new MainThreadAuthenticationProvider(this._proxy, id, displayName, supportsMultipleAccounts, this.notificationService, this.storageKeysSyncRegistryService, this.storageService, this.quickInputService, this.dialogService);
|
||||
await provider.initialize();
|
||||
this.authenticationService.registerAuthenticationProvider(id, provider);
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
|
||||
|
||||
async $postMessage(handle: number, value: any): Promise<boolean> {
|
||||
const inset = this.getInset(handle);
|
||||
inset.webview.sendMessage(value);
|
||||
inset.webview.postMessage(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ICommandService, CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ExtHostContext, MainThreadCommandsShape, ExtHostCommandsShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
@@ -28,7 +28,7 @@ export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._commandRegistrations.forEach(value => value.dispose());
|
||||
dispose(this._commandRegistrations.values());
|
||||
this._commandRegistrations.clear();
|
||||
|
||||
this._generateCommandsDocumentationRegistration.dispose();
|
||||
|
||||
@@ -21,6 +21,7 @@ import { COMMENTS_VIEW_ID, COMMENTS_VIEW_TITLE } from 'vs/workbench/contrib/comm
|
||||
import { ViewContainer, IViewContainersRegistry, Extensions as ViewExtensions, ViewContainerLocation, IViewsRegistry, IViewsService, IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
|
||||
export class MainThreadCommentThread implements modes.CommentThread {
|
||||
@@ -458,6 +459,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments
|
||||
ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [COMMENTS_VIEW_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]),
|
||||
storageId: COMMENTS_VIEW_TITLE,
|
||||
hideIfEmpty: true,
|
||||
icon: Codicon.commentDiscussion.classNames,
|
||||
order: 10,
|
||||
}, ViewContainerLocation.Panel);
|
||||
|
||||
@@ -467,6 +469,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments
|
||||
canToggleVisibility: false,
|
||||
ctorDescriptor: new SyncDescriptor(CommentsPanel),
|
||||
canMoveView: true,
|
||||
containerIcon: Codicon.commentDiscussion.classNames,
|
||||
focusCommand: {
|
||||
id: 'workbench.action.focusCommentsPanel'
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
const folderUri = folder ? uri.revive(folder) : undefined;
|
||||
const launch = this.debugService.getConfigurationManager().getLaunch(folderUri);
|
||||
const debugOptions: IDebugSessionOptions = {
|
||||
noDebug: false,
|
||||
noDebug: options.noDebug,
|
||||
parentSession: this.getSession(options.parentSessionID),
|
||||
repl: options.repl
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
@@ -35,8 +35,8 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._resourceContentProvider.forEach(p => p.dispose());
|
||||
this._pendingUpdate.forEach(source => source.dispose());
|
||||
dispose(this._resourceContentProvider.values());
|
||||
dispose(this._pendingUpdate.values());
|
||||
}
|
||||
|
||||
$registerTextContentProvider(handle: number, scheme: string): void {
|
||||
|
||||
@@ -16,7 +16,7 @@ import { ExtHostContext, ExtHostDocumentsShape, IExtHostContext, MainThreadDocum
|
||||
import { ITextEditorModel } from 'vs/workbench/common/editor';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { toLocalResource, isEqualOrParent, extUri } from 'vs/base/common/resources';
|
||||
import { toLocalResource, extUri, IExtUri } from 'vs/base/common/resources';
|
||||
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
|
||||
|
||||
@@ -26,8 +26,9 @@ export class BoundModelReferenceCollection {
|
||||
private _length = 0;
|
||||
|
||||
constructor(
|
||||
private readonly _extUri: IExtUri,
|
||||
private readonly _maxAge: number = 1000 * 60 * 3,
|
||||
private readonly _maxLength: number = 1024 * 1024 * 80
|
||||
private readonly _maxLength: number = 1024 * 1024 * 80,
|
||||
) {
|
||||
//
|
||||
}
|
||||
@@ -38,7 +39,7 @@ export class BoundModelReferenceCollection {
|
||||
|
||||
remove(uri: URI): void {
|
||||
for (const entry of [...this._data] /* copy array because dispose will modify it */) {
|
||||
if (isEqualOrParent(entry.uri, uri)) {
|
||||
if (this._extUri.isEqualOrParent(entry.uri, uri)) {
|
||||
entry.dispose();
|
||||
}
|
||||
}
|
||||
@@ -85,7 +86,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
private _modelToDisposeMap: { [modelUrl: string]: IDisposable; };
|
||||
private readonly _proxy: ExtHostDocumentsShape;
|
||||
private readonly _modelIsSynced = new Set<string>();
|
||||
private readonly _modelReferenceCollection = new BoundModelReferenceCollection();
|
||||
private readonly _modelReferenceCollection: BoundModelReferenceCollection;
|
||||
|
||||
constructor(
|
||||
documentsAndEditors: MainThreadDocumentsAndEditors,
|
||||
@@ -105,11 +106,12 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
this._environmentService = environmentService;
|
||||
this._uriIdentityService = uriIdentityService;
|
||||
|
||||
this._modelReferenceCollection = this._toDispose.add(new BoundModelReferenceCollection(uriIdentityService.extUri));
|
||||
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocuments);
|
||||
|
||||
this._toDispose.add(documentsAndEditors.onDocumentAdd(models => models.forEach(this._onModelAdded, this)));
|
||||
this._toDispose.add(documentsAndEditors.onDocumentRemove(urls => urls.forEach(this._onModelRemoved, this)));
|
||||
this._toDispose.add(this._modelReferenceCollection);
|
||||
this._toDispose.add(modelService.onModelModeChanged(this._onModelModeChanged, this));
|
||||
|
||||
this._toDispose.add(textFileService.files.onDidSave(e => {
|
||||
|
||||
@@ -29,38 +29,39 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
namespace delta {
|
||||
|
||||
export function ofSets<T>(before: Set<T>, after: Set<T>): { removed: T[], added: T[] } {
|
||||
const removed: T[] = [];
|
||||
const added: T[] = [];
|
||||
before.forEach(element => {
|
||||
for (let element of before) {
|
||||
if (!after.has(element)) {
|
||||
removed.push(element);
|
||||
}
|
||||
});
|
||||
after.forEach(element => {
|
||||
}
|
||||
for (let element of after) {
|
||||
if (!before.has(element)) {
|
||||
added.push(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
return { removed, added };
|
||||
}
|
||||
|
||||
export function ofMaps<K, V>(before: Map<K, V>, after: Map<K, V>): { removed: V[], added: V[] } {
|
||||
const removed: V[] = [];
|
||||
const added: V[] = [];
|
||||
before.forEach((value, index) => {
|
||||
for (let [index, value] of before) {
|
||||
if (!after.has(index)) {
|
||||
removed.push(value);
|
||||
}
|
||||
});
|
||||
after.forEach((value, index) => {
|
||||
}
|
||||
for (let [index, value] of after) {
|
||||
if (!before.has(index)) {
|
||||
added.push(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
return { removed, added };
|
||||
}
|
||||
}
|
||||
@@ -265,11 +266,11 @@ class MainThreadDocumentAndEditorStateComputer {
|
||||
}
|
||||
|
||||
if (candidate) {
|
||||
editors.forEach(snapshot => {
|
||||
for (const snapshot of editors.values()) {
|
||||
if (candidate === snapshot.editor) {
|
||||
activeEditor = snapshot.id;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,6 +332,7 @@ export class MainThreadDocumentsAndEditors {
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService,
|
||||
@IUriIdentityService uriIdentityService: IUriIdentityService,
|
||||
@IClipboardService private readonly _clipboardService: IClipboardService,
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentsAndEditors);
|
||||
|
||||
@@ -365,7 +367,7 @@ export class MainThreadDocumentsAndEditors {
|
||||
// added editors
|
||||
for (const apiEditor of delta.addedEditors) {
|
||||
const mainThreadEditor = new MainThreadTextEditor(apiEditor.id, apiEditor.editor.getModel(),
|
||||
apiEditor.editor, { onGainedFocus() { }, onLostFocus() { } }, this._modelService);
|
||||
apiEditor.editor, { onGainedFocus() { }, onLostFocus() { } }, this._modelService, this._clipboardService);
|
||||
|
||||
this._textEditors.set(apiEditor.id, mainThreadEditor);
|
||||
addedEditors.push(mainThreadEditor);
|
||||
|
||||
@@ -17,6 +17,9 @@ import { IApplyEditsOptions, IEditorPropertiesChangeData, IResolvedTextEditorCon
|
||||
import { IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { equals } from 'vs/base/common/arrays';
|
||||
import { CodeEditorStateFlag, EditorState } from 'vs/editor/browser/core/editorState';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { SnippetParser } from 'vs/editor/contrib/snippet/snippetParser';
|
||||
|
||||
export interface IFocusTracker {
|
||||
onGainedFocus(): void;
|
||||
@@ -159,6 +162,7 @@ export class MainThreadTextEditor {
|
||||
private readonly _id: string;
|
||||
private _model: ITextModel;
|
||||
private readonly _modelService: IModelService;
|
||||
private readonly _clipboardService: IClipboardService;
|
||||
private readonly _modelListeners = new DisposableStore();
|
||||
private _codeEditor: ICodeEditor | null;
|
||||
private readonly _focusTracker: IFocusTracker;
|
||||
@@ -172,7 +176,8 @@ export class MainThreadTextEditor {
|
||||
model: ITextModel,
|
||||
codeEditor: ICodeEditor,
|
||||
focusTracker: IFocusTracker,
|
||||
modelService: IModelService
|
||||
modelService: IModelService,
|
||||
clipboardService: IClipboardService,
|
||||
) {
|
||||
this._id = id;
|
||||
this._model = model;
|
||||
@@ -180,6 +185,7 @@ export class MainThreadTextEditor {
|
||||
this._properties = null;
|
||||
this._focusTracker = focusTracker;
|
||||
this._modelService = modelService;
|
||||
this._clipboardService = clipboardService;
|
||||
|
||||
this._onPropertiesChanged = new Emitter<IEditorPropertiesChangeData>();
|
||||
|
||||
@@ -454,12 +460,23 @@ export class MainThreadTextEditor {
|
||||
return true;
|
||||
}
|
||||
|
||||
insertSnippet(template: string, ranges: readonly IRange[], opts: IUndoStopOptions) {
|
||||
async insertSnippet(template: string, ranges: readonly IRange[], opts: IUndoStopOptions) {
|
||||
|
||||
if (!this._codeEditor) {
|
||||
if (!this._codeEditor || !this._codeEditor.hasModel()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if clipboard is required and only iff read it (async)
|
||||
let clipboardText: string | undefined;
|
||||
const needsTemplate = SnippetParser.guessNeedsClipboard(template);
|
||||
if (needsTemplate) {
|
||||
const state = new EditorState(this._codeEditor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position);
|
||||
clipboardText = await this._clipboardService.readText();
|
||||
if (!state.validate(this._codeEditor)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const snippetController = SnippetController2.get(this._codeEditor);
|
||||
|
||||
// // cancel previous snippet mode
|
||||
@@ -471,7 +488,11 @@ export class MainThreadTextEditor {
|
||||
this._codeEditor.focus();
|
||||
|
||||
// make modifications
|
||||
snippetController.insert(template, { overwriteBefore: 0, overwriteAfter: 0, undoStopBefore: opts.undoStopBefore, undoStopAfter: opts.undoStopAfter });
|
||||
snippetController.insert(template, {
|
||||
overwriteBefore: 0, overwriteAfter: 0,
|
||||
undoStopBefore: opts.undoStopBefore, undoStopAfter: opts.undoStopAfter,
|
||||
clipboardText
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
// preserve pre 1.38 behaviour to not make group active when preserveFocus: true
|
||||
// but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633
|
||||
activation: options.preserveFocus ? EditorActivation.RESTORE : undefined,
|
||||
ignoreOverrides: uri?.fsPath?.toLowerCase().endsWith('ipynb') || uri?.fsPath?.toLowerCase().endsWith('sql') ? false : true // {{SQL CARBON EDIT}}
|
||||
override: uri?.fsPath?.toLowerCase().endsWith('ipynb') || uri?.fsPath?.toLowerCase().endsWith('sql') ? undefined : false // {{SQL CARBON EDIT}}
|
||||
};
|
||||
|
||||
const input: IResourceEditorInput = {
|
||||
@@ -306,7 +306,7 @@ CommandsRegistry.registerCommand('_workbench.openWith', (accessor: ServicesAcces
|
||||
const [resource, id, options, position] = args;
|
||||
|
||||
const group = editorGroupsService.getGroup(viewColumnToEditorGroup(editorGroupsService, position)) ?? editorGroupsService.activeGroup;
|
||||
const textOptions = options ? { ...options, ignoreOverrides: true } : { ignoreOverrides: true };
|
||||
const textOptions: ITextEditorOptions = options ? { ...options, override: false } : { override: false };
|
||||
|
||||
const input = editorService.createEditorInput({ resource });
|
||||
return openEditorWith(input, id, textOptions, group, editorService, configurationService, quickInputService);
|
||||
|
||||
@@ -25,7 +25,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._fileProvider.forEach(value => value.dispose());
|
||||
dispose(this._fileProvider.values());
|
||||
this._fileProvider.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IExtHostContext, ExtHostNotebookShape, ExtHostContext, INotebookDocumentsAndEditorsDelta, INotebookModelAddedData } from '../common/extHost.protocol';
|
||||
import { Disposable, IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
@@ -17,6 +18,8 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { IRelativePattern } from 'vs/base/common/glob';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IUndoRedoService, UndoRedoElementType } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
|
||||
export class MainThreadNotebookDocument extends Disposable {
|
||||
private _textModel: NotebookTextModel;
|
||||
@@ -29,11 +32,15 @@ export class MainThreadNotebookDocument extends Disposable {
|
||||
private readonly _proxy: ExtHostNotebookShape,
|
||||
public handle: number,
|
||||
public viewType: string,
|
||||
public supportBackup: boolean,
|
||||
public uri: URI,
|
||||
readonly notebookService: INotebookService
|
||||
@INotebookService readonly notebookService: INotebookService,
|
||||
@IUndoRedoService readonly undoRedoService: IUndoRedoService
|
||||
|
||||
) {
|
||||
super();
|
||||
this._textModel = new NotebookTextModel(handle, viewType, uri);
|
||||
|
||||
this._textModel = new NotebookTextModel(handle, viewType, supportBackup, uri);
|
||||
this._register(this._textModel.onDidModelChangeProxy(e => {
|
||||
this._proxy.$acceptModelChanged(this.uri, e);
|
||||
this._proxy.$acceptEditorPropertiesChanged(uri, { selections: { selections: this._textModel.selections }, metadata: null });
|
||||
@@ -44,7 +51,7 @@ export class MainThreadNotebookDocument extends Disposable {
|
||||
}));
|
||||
}
|
||||
|
||||
async applyEdit(modelVersionId: number, edits: ICellEditOperation[]): Promise<boolean> {
|
||||
async applyEdit(modelVersionId: number, edits: ICellEditOperation[], emitToExtHost: boolean): Promise<boolean> {
|
||||
await this.notebookService.transformEditsOutputs(this.textModel, edits);
|
||||
return this._textModel.$applyEdit(modelVersionId, edits);
|
||||
}
|
||||
@@ -53,6 +60,22 @@ export class MainThreadNotebookDocument extends Disposable {
|
||||
await this.notebookService.transformSpliceOutputs(this.textModel, splices);
|
||||
this._textModel.$spliceNotebookCellOutputs(cellHandle, splices);
|
||||
}
|
||||
|
||||
handleEdit(editId: number, label: string | undefined): void {
|
||||
this.undoRedoService.pushElement({
|
||||
type: UndoRedoElementType.Resource,
|
||||
resource: this._textModel.uri,
|
||||
label: label ?? nls.localize('defaultEditLabel', "Edit"),
|
||||
undo: async () => {
|
||||
await this._proxy.$undoNotebook(this._textModel.viewType, this._textModel.uri, editId, this._textModel.isDirty);
|
||||
},
|
||||
redo: async () => {
|
||||
await this._proxy.$redoNotebook(this._textModel.viewType, this._textModel.uri, editId, this._textModel.isDirty);
|
||||
},
|
||||
});
|
||||
this._textModel.setDirty(true);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._textModel.dispose();
|
||||
super.dispose();
|
||||
@@ -60,6 +83,22 @@ export class MainThreadNotebookDocument extends Disposable {
|
||||
}
|
||||
|
||||
class DocumentAndEditorState {
|
||||
static ofSets<T>(before: Set<T>, after: Set<T>): { removed: T[], added: T[] } {
|
||||
const removed: T[] = [];
|
||||
const added: T[] = [];
|
||||
before.forEach(element => {
|
||||
if (!after.has(element)) {
|
||||
removed.push(element);
|
||||
}
|
||||
});
|
||||
after.forEach(element => {
|
||||
if (!before.has(element)) {
|
||||
added.push(element);
|
||||
}
|
||||
});
|
||||
return { removed, added };
|
||||
}
|
||||
|
||||
static ofMaps<K, V>(before: Map<K, V>, after: Map<K, V>): { removed: V[], added: V[] } {
|
||||
const removed: V[] = [];
|
||||
const added: V[] = [];
|
||||
@@ -86,15 +125,16 @@ class DocumentAndEditorState {
|
||||
|
||||
return {
|
||||
addedDocuments: [],
|
||||
addedEditors: apiEditors
|
||||
addedEditors: apiEditors,
|
||||
visibleEditors: [...after.visibleEditors].map(editor => editor[0])
|
||||
};
|
||||
}
|
||||
// const documentDelta = delta.ofSets(before.documents, after.documents);
|
||||
const documentDelta = DocumentAndEditorState.ofSets(before.documents, after.documents);
|
||||
const editorDelta = DocumentAndEditorState.ofMaps(before.textEditors, after.textEditors);
|
||||
const addedAPIEditors = editorDelta.added.map(add => ({
|
||||
id: add.getId(),
|
||||
documentUri: add.uri!,
|
||||
selections: add.textModel!.selections
|
||||
selections: add.textModel!.selections || []
|
||||
}));
|
||||
|
||||
const removedAPIEditors = editorDelta.removed.map(removed => removed.getId());
|
||||
@@ -102,17 +142,46 @@ class DocumentAndEditorState {
|
||||
// const oldActiveEditor = before.activeEditor !== after.activeEditor ? before.activeEditor : undefined;
|
||||
const newActiveEditor = before.activeEditor !== after.activeEditor ? after.activeEditor : undefined;
|
||||
|
||||
const visibleEditorDelta = DocumentAndEditorState.ofMaps(before.visibleEditors, after.visibleEditors);
|
||||
|
||||
return {
|
||||
addedDocuments: documentDelta.added.map(e => {
|
||||
return {
|
||||
viewType: e.viewType,
|
||||
handle: e.handle,
|
||||
uri: e.uri,
|
||||
metadata: e.metadata,
|
||||
versionId: e.versionId,
|
||||
cells: e.cells.map(cell => ({
|
||||
handle: cell.handle,
|
||||
uri: cell.uri,
|
||||
source: cell.textBuffer.getLinesContent(),
|
||||
language: cell.language,
|
||||
cellKind: cell.cellKind,
|
||||
outputs: cell.outputs,
|
||||
metadata: cell.metadata
|
||||
})),
|
||||
// attachedEditor: editorId ? {
|
||||
// id: editorId,
|
||||
// selections: document.textModel.selections
|
||||
// } : undefined
|
||||
};
|
||||
}),
|
||||
removedDocuments: documentDelta.removed.map(e => e.uri),
|
||||
addedEditors: addedAPIEditors,
|
||||
removedEditors: removedAPIEditors,
|
||||
newActiveEditor: newActiveEditor
|
||||
newActiveEditor: newActiveEditor,
|
||||
visibleEditors: visibleEditorDelta.added.length === 0 && visibleEditorDelta.removed.length === 0
|
||||
? undefined
|
||||
: [...after.visibleEditors].map(editor => editor[0])
|
||||
};
|
||||
}
|
||||
|
||||
constructor(
|
||||
readonly documents: Set<URI>,
|
||||
readonly documents: Set<NotebookTextModel>,
|
||||
readonly textEditors: Map<string, IEditor>,
|
||||
readonly activeEditor: string | null | undefined,
|
||||
readonly visibleEditors: Map<string, IEditor>
|
||||
) {
|
||||
//
|
||||
}
|
||||
@@ -132,7 +201,8 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
@INotebookService private _notebookService: INotebookService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IAccessibilityService private readonly accessibilityService: IAccessibilityService
|
||||
@IAccessibilityService private readonly accessibilityService: IAccessibilityService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService
|
||||
|
||||
) {
|
||||
super();
|
||||
@@ -150,29 +220,77 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
return false;
|
||||
}
|
||||
|
||||
private _isDeltaEmpty(delta: INotebookDocumentsAndEditorsDelta) {
|
||||
if (delta.addedDocuments !== undefined && delta.addedDocuments.length > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (delta.removedDocuments !== undefined && delta.removedDocuments.length > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (delta.addedEditors !== undefined && delta.addedEditors.length > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (delta.removedEditors !== undefined && delta.removedEditors.length > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (delta.visibleEditors !== undefined && delta.visibleEditors.length > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (delta.newActiveEditor !== undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private _emitDelta(delta: INotebookDocumentsAndEditorsDelta) {
|
||||
if (this._isDeltaEmpty(delta)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._proxy.$acceptDocumentAndEditorsDelta(delta);
|
||||
}
|
||||
|
||||
registerListeners() {
|
||||
this._notebookService.listNotebookEditors().forEach((e) => {
|
||||
this._addNotebookEditor(e);
|
||||
});
|
||||
|
||||
this._register(this._notebookService.onDidChangeActiveEditor(e => {
|
||||
this._proxy.$acceptDocumentAndEditorsDelta({
|
||||
newActiveEditor: e
|
||||
});
|
||||
this._updateState();
|
||||
}));
|
||||
|
||||
this._register(this._notebookService.onDidChangeVisibleEditors(e => {
|
||||
this._proxy.$acceptDocumentAndEditorsDelta({
|
||||
visibleEditors: e
|
||||
});
|
||||
if (this._notebookProviders.size > 0) {
|
||||
if (!this._currentState) {
|
||||
// no current state means we didn't even create editors in ext host yet.
|
||||
return;
|
||||
}
|
||||
|
||||
// we can't simply update visibleEditors as we need to check if we should create editors first.
|
||||
this._updateState();
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this._notebookService.onNotebookEditorAdd(editor => {
|
||||
this._addNotebookEditor(editor);
|
||||
}));
|
||||
|
||||
this._register(this._notebookService.onNotebookEditorRemove(editor => {
|
||||
this._removeNotebookEditor(editor);
|
||||
this._register(this._notebookService.onNotebookEditorsRemove(editors => {
|
||||
this._removeNotebookEditor(editors);
|
||||
}));
|
||||
|
||||
this._register(this._notebookService.onNotebookDocumentAdd(() => {
|
||||
this._updateState();
|
||||
}));
|
||||
|
||||
this._register(this._notebookService.onNotebookDocumentRemove(() => {
|
||||
this._updateState();
|
||||
}));
|
||||
|
||||
const updateOrder = () => {
|
||||
@@ -201,9 +319,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
}
|
||||
|
||||
async addNotebookDocument(data: INotebookModelAddedData) {
|
||||
await this._proxy.$acceptDocumentAndEditorsDelta({
|
||||
addedDocuments: [data]
|
||||
});
|
||||
this._updateState();
|
||||
}
|
||||
|
||||
private _addNotebookEditor(e: IEditor) {
|
||||
@@ -219,39 +335,58 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
this._updateState(notebookEditor);
|
||||
}
|
||||
|
||||
private _removeNotebookEditor(e: IEditor) {
|
||||
const sub = this._toDisposeOnEditorRemove.get(e.getId());
|
||||
if (sub) {
|
||||
this._toDisposeOnEditorRemove.delete(e.getId());
|
||||
sub.dispose();
|
||||
this._updateState();
|
||||
}
|
||||
private _removeNotebookEditor(editors: IEditor[]) {
|
||||
editors.forEach(e => {
|
||||
const sub = this._toDisposeOnEditorRemove.get(e.getId());
|
||||
if (sub) {
|
||||
this._toDisposeOnEditorRemove.delete(e.getId());
|
||||
sub.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
this._updateState();
|
||||
}
|
||||
|
||||
private async _updateState(focusedNotebookEditor?: IEditor) {
|
||||
const documents = new Set<URI>();
|
||||
this._notebookService.listNotebookDocuments().forEach(document => {
|
||||
documents.add(document.uri);
|
||||
});
|
||||
|
||||
const editors = new Map<string, IEditor>();
|
||||
let activeEditor: string | null = null;
|
||||
|
||||
for (const editor of this._notebookService.listNotebookEditors()) {
|
||||
if (editor.hasModel()) {
|
||||
editors.set(editor.getId(), editor);
|
||||
if (editor.hasFocus()) {
|
||||
activeEditor = editor.getId();
|
||||
}
|
||||
}
|
||||
const activeEditorPane = this.editorService.activeEditorPane as any | undefined;
|
||||
if (activeEditorPane?.isNotebookEditor) {
|
||||
const notebookEditor = (activeEditorPane.getControl() as INotebookEditor);
|
||||
activeEditor = notebookEditor && notebookEditor.hasModel() ? notebookEditor!.getId() : null;
|
||||
}
|
||||
|
||||
if (!activeEditor && focusedNotebookEditor) {
|
||||
const documentEditorsMap = new Map<string, IEditor>();
|
||||
|
||||
const editors = new Map<string, IEditor>();
|
||||
this._notebookService.listNotebookEditors().forEach(editor => {
|
||||
if (editor.hasModel()) {
|
||||
editors.set(editor.getId(), editor);
|
||||
documentEditorsMap.set(editor.textModel!.uri.toString(), editor);
|
||||
}
|
||||
});
|
||||
|
||||
const visibleEditorsMap = new Map<string, IEditor>();
|
||||
this.editorService.visibleEditorPanes.forEach(editor => {
|
||||
if ((editor as any).isNotebookEditor) {
|
||||
const nbEditorWidget = (editor as any).getControl() as INotebookEditor;
|
||||
if (nbEditorWidget && editors.has(nbEditorWidget.getId())) {
|
||||
visibleEditorsMap.set(nbEditorWidget.getId(), nbEditorWidget);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const documents = new Set<NotebookTextModel>();
|
||||
this._notebookService.listNotebookDocuments().forEach(document => {
|
||||
documents.add(document);
|
||||
});
|
||||
|
||||
if (!activeEditor && focusedNotebookEditor && focusedNotebookEditor.hasModel()) {
|
||||
activeEditor = focusedNotebookEditor.getId();
|
||||
}
|
||||
|
||||
// editors always have view model attached, which means there is already a document in exthost.
|
||||
const newState = new DocumentAndEditorState(documents, editors, activeEditor);
|
||||
const newState = new DocumentAndEditorState(documents, editors, activeEditor, visibleEditorsMap);
|
||||
const delta = DocumentAndEditorState.compute(this._currentState, newState);
|
||||
// const isEmptyChange = (!delta.addedDocuments || delta.addedDocuments.length === 0)
|
||||
// && (!delta.removedDocuments || delta.removedDocuments.length === 0)
|
||||
@@ -261,7 +396,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
|
||||
// if (!isEmptyChange) {
|
||||
this._currentState = newState;
|
||||
await this._proxy.$acceptDocumentAndEditorsDelta(delta);
|
||||
await this._emitDelta(delta);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -275,8 +410,8 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
this._notebookService.unregisterNotebookRenderer(id);
|
||||
}
|
||||
|
||||
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, kernel: INotebookKernelInfoDto | undefined): Promise<void> {
|
||||
let controller = new MainThreadNotebookController(this._proxy, this, viewType, kernel, this._notebookService);
|
||||
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, kernel: INotebookKernelInfoDto | undefined): Promise<void> {
|
||||
let controller = new MainThreadNotebookController(this._proxy, this, viewType, supportBackup, kernel, this._notebookService, this._instantiationService);
|
||||
this._notebookProviders.set(viewType, controller);
|
||||
this._notebookService.registerNotebookController(viewType, extension, controller);
|
||||
return;
|
||||
@@ -355,6 +490,16 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
controller?.handleEdit(resource, editId, label);
|
||||
}
|
||||
|
||||
$onContentChange(resource: UriComponents, viewType: string): void {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
controller?.handleNotebookChange(resource);
|
||||
}
|
||||
}
|
||||
|
||||
export class MainThreadNotebookController implements IMainNotebookController {
|
||||
@@ -365,13 +510,15 @@ export class MainThreadNotebookController implements IMainNotebookController {
|
||||
private readonly _proxy: ExtHostNotebookShape,
|
||||
private _mainThreadNotebook: MainThreadNotebooks,
|
||||
private _viewType: string,
|
||||
private _supportBackup: boolean,
|
||||
readonly kernel: INotebookKernelInfoDto | undefined,
|
||||
readonly notebookService: INotebookService,
|
||||
readonly _instantiationService: IInstantiationService
|
||||
|
||||
) {
|
||||
}
|
||||
|
||||
async createNotebook(viewType: string, uri: URI, backup: INotebookTextModelBackup | undefined, forceReload: boolean, editorId?: string): Promise<NotebookTextModel | undefined> {
|
||||
async createNotebook(viewType: string, uri: URI, backup: INotebookTextModelBackup | undefined, forceReload: boolean, editorId?: string, backupId?: string): Promise<NotebookTextModel | undefined> {
|
||||
let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
|
||||
|
||||
if (mainthreadNotebook) {
|
||||
@@ -383,15 +530,15 @@ export class MainThreadNotebookController implements IMainNotebookController {
|
||||
|
||||
mainthreadNotebook.textModel.languages = data.languages;
|
||||
mainthreadNotebook.textModel.metadata = data.metadata;
|
||||
mainthreadNotebook.textModel.$applyEdit(mainthreadNotebook.textModel.versionId, [
|
||||
await mainthreadNotebook.applyEdit(mainthreadNotebook.textModel.versionId, [
|
||||
{ editType: CellEditType.Delete, count: mainthreadNotebook.textModel.cells.length, index: 0 },
|
||||
{ editType: CellEditType.Insert, index: 0, cells: data.cells }
|
||||
]);
|
||||
], true);
|
||||
}
|
||||
return mainthreadNotebook.textModel;
|
||||
}
|
||||
|
||||
let document = new MainThreadNotebookDocument(this._proxy, MainThreadNotebookController.documentHandle++, viewType, uri, this.notebookService);
|
||||
let document = this._instantiationService.createInstance(MainThreadNotebookDocument, this._proxy, MainThreadNotebookController.documentHandle++, viewType, this._supportBackup, uri);
|
||||
this._mapping.set(document.uri.toString(), document);
|
||||
|
||||
if (backup) {
|
||||
@@ -399,14 +546,16 @@ export class MainThreadNotebookController implements IMainNotebookController {
|
||||
document.textModel.metadata = backup.metadata;
|
||||
document.textModel.languages = backup.languages;
|
||||
|
||||
document.textModel.$applyEdit(document.textModel.versionId, [
|
||||
// restored from backup, update the text model without emitting any event to exthost
|
||||
await document.applyEdit(document.textModel.versionId, [
|
||||
{
|
||||
editType: CellEditType.Insert,
|
||||
index: 0,
|
||||
cells: backup.cells || []
|
||||
}
|
||||
]);
|
||||
], false);
|
||||
|
||||
// create document in ext host with cells data
|
||||
await this._mainThreadNotebook.addNotebookDocument({
|
||||
viewType: document.viewType,
|
||||
handle: document.handle,
|
||||
@@ -432,7 +581,7 @@ export class MainThreadNotebookController implements IMainNotebookController {
|
||||
}
|
||||
|
||||
// open notebook document
|
||||
const data = await this._proxy.$resolveNotebookData(viewType, uri);
|
||||
const data = await this._proxy.$resolveNotebookData(viewType, uri, backupId);
|
||||
if (!data) {
|
||||
return undefined; // {{SQL CARBON EDIT}}
|
||||
}
|
||||
@@ -473,11 +622,15 @@ export class MainThreadNotebookController implements IMainNotebookController {
|
||||
return document.textModel;
|
||||
}
|
||||
|
||||
async resolveNotebookEditor(viewType: string, uri: URI, editorId: string) {
|
||||
await this._proxy.$resolveNotebookEditor(viewType, uri, editorId);
|
||||
}
|
||||
|
||||
async tryApplyEdits(resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[], renderers: number[]): Promise<boolean> {
|
||||
let mainthreadNotebook = this._mapping.get(URI.from(resource).toString());
|
||||
|
||||
if (mainthreadNotebook) {
|
||||
return await mainthreadNotebook.applyEdit(modelVersionId, edits);
|
||||
return await mainthreadNotebook.applyEdit(modelVersionId, edits, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -503,6 +656,7 @@ export class MainThreadNotebookController implements IMainNotebookController {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO@rebornix, remove cell should use emitDelta as well to ensure document/editor events are sent together
|
||||
await this._proxy.$acceptDocumentAndEditorsDelta({ removedDocuments: [notebook.uri] });
|
||||
document.dispose();
|
||||
this._mapping.delete(URI.from(notebook.uri).toString());
|
||||
@@ -515,6 +669,11 @@ export class MainThreadNotebookController implements IMainNotebookController {
|
||||
document?.textModel.handleUnknownChange();
|
||||
}
|
||||
|
||||
handleEdit(resource: UriComponents, editId: number, label: string | undefined): void {
|
||||
let document = this._mapping.get(URI.from(resource).toString());
|
||||
document?.handleEdit(editId, label);
|
||||
}
|
||||
|
||||
updateLanguages(resource: UriComponents, languages: string[]) {
|
||||
let document = this._mapping.get(URI.from(resource).toString());
|
||||
document?.textModel.updateLanguages(languages);
|
||||
@@ -540,7 +699,11 @@ export class MainThreadNotebookController implements IMainNotebookController {
|
||||
|
||||
async saveAs(uri: URI, target: URI, token: CancellationToken): Promise<boolean> {
|
||||
return this._proxy.$saveNotebookAs(this._viewType, uri, target, token);
|
||||
}
|
||||
|
||||
async backup(uri: URI, token: CancellationToken): Promise<string | undefined> {
|
||||
const backupId = await this._proxy.$backup(this._viewType, uri, token);
|
||||
return backupId;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, IExtHostContext, ExtHostExtensionServiceShape } from '../common/extHost.protocol';
|
||||
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
@extHostCustomer
|
||||
export class MainThreadRemoteConnectionData extends Disposable {
|
||||
|
||||
private readonly _proxy: ExtHostExtensionServiceShape;
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IWorkbenchEnvironmentService protected readonly _environmentService: IWorkbenchEnvironmentService,
|
||||
@IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService
|
||||
) {
|
||||
super();
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostExtensionService);
|
||||
|
||||
const remoteAuthority = this._environmentService.configuration.remoteAuthority;
|
||||
if (remoteAuthority) {
|
||||
this._register(remoteAuthorityResolverService.onDidChangeConnectionData(() => {
|
||||
const connectionData = remoteAuthorityResolverService.getConnectionData(remoteAuthority);
|
||||
if (connectionData) {
|
||||
this._proxy.$updateRemoteConnectionData(connectionData);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
@@ -139,7 +138,7 @@ class RemoteSearchProvider implements ISearchResultProvider, IDisposable {
|
||||
|
||||
return Promise.resolve(searchP).then((result: ISearchCompleteStats) => {
|
||||
this._searches.delete(search.id);
|
||||
return { results: values(search.matches), stats: result.stats, limitHit: result.limitHit };
|
||||
return { results: Array.from(search.matches.values()), stats: result.stats, limitHit: result.limitHit };
|
||||
}, err => {
|
||||
this._searches.delete(search.id);
|
||||
return Promise.reject(err);
|
||||
|
||||
@@ -32,7 +32,7 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
|
||||
if (accessibilityInformation) {
|
||||
ariaLabel = accessibilityInformation.label;
|
||||
} else {
|
||||
ariaLabel = text.indexOf('$(') === -1 ? text : tooltip || text;
|
||||
ariaLabel = text && text.indexOf('$(') === -1 ? text : tooltip || text;
|
||||
}
|
||||
const entry: IStatusbarEntry = { text, tooltip, command, color, ariaLabel };
|
||||
|
||||
|
||||
@@ -510,41 +510,41 @@ export class MainThreadTask implements MainThreadTaskShape {
|
||||
});
|
||||
}
|
||||
|
||||
public $executeTask(value: TaskHandleDTO | TaskDTO): Promise<TaskExecutionDTO> {
|
||||
return new Promise<TaskExecutionDTO>((resolve, reject) => {
|
||||
if (TaskHandleDTO.is(value)) {
|
||||
const workspaceFolder = typeof value.workspaceFolder === 'string' ? value.workspaceFolder : this._workspaceContextServer.getWorkspaceFolder(URI.revive(value.workspaceFolder));
|
||||
if (workspaceFolder) {
|
||||
this._taskService.getTask(workspaceFolder, value.id, true).then((task: Task | undefined) => {
|
||||
if (!task) {
|
||||
reject(new Error('Task not found'));
|
||||
} else {
|
||||
this._taskService.run(task).then(undefined, reason => {
|
||||
// eat the error, it has already been surfaced to the user and we don't care about it here
|
||||
});
|
||||
const result: TaskExecutionDTO = {
|
||||
id: value.id,
|
||||
task: TaskDTO.from(task)
|
||||
};
|
||||
resolve(result);
|
||||
}
|
||||
}, (_error) => {
|
||||
reject(new Error('Task not found'));
|
||||
});
|
||||
} else {
|
||||
reject(new Error('No workspace folder'));
|
||||
public async $getTaskExecution(value: TaskHandleDTO | TaskDTO): Promise<TaskExecutionDTO> {
|
||||
if (TaskHandleDTO.is(value)) {
|
||||
const workspaceFolder = typeof value.workspaceFolder === 'string' ? value.workspaceFolder : this._workspaceContextServer.getWorkspaceFolder(URI.revive(value.workspaceFolder));
|
||||
if (workspaceFolder) {
|
||||
const task = await this._taskService.getTask(workspaceFolder, value.id, true);
|
||||
if (task) {
|
||||
return {
|
||||
id: task._id,
|
||||
task: TaskDTO.from(task)
|
||||
};
|
||||
}
|
||||
throw new Error('Task not found');
|
||||
} else {
|
||||
const task = TaskDTO.to(value, this._workspaceContextServer, true)!;
|
||||
this._taskService.run(task).then(undefined, reason => {
|
||||
// eat the error, it has already been surfaced to the user and we don't care about it here
|
||||
});
|
||||
const result: TaskExecutionDTO = {
|
||||
id: task._id,
|
||||
task: TaskDTO.from(task)
|
||||
};
|
||||
resolve(result);
|
||||
throw new Error('No workspace folder');
|
||||
}
|
||||
} else {
|
||||
const task = TaskDTO.to(value, this._workspaceContextServer, true)!;
|
||||
return {
|
||||
id: task._id,
|
||||
task: TaskDTO.from(task)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public $executeTask(value: TaskDTO): Promise<TaskExecutionDTO> {
|
||||
return new Promise<TaskExecutionDTO>((resolve, reject) => {
|
||||
const task = TaskDTO.to(value, this._workspaceContextServer, true)!;
|
||||
this._taskService.run(task).then(undefined, reason => {
|
||||
// eat the error, it has already been surfaced to the user and we don't care about it here
|
||||
});
|
||||
const result: TaskExecutionDTO = {
|
||||
id: task._id,
|
||||
task: TaskDTO.from(task)
|
||||
};
|
||||
resolve(result);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
private _proxy: ExtHostTerminalServiceShape;
|
||||
private _remoteAuthority: string | null;
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
private readonly _terminalProcesses = new Map<number, Promise<ITerminalProcessExtHostProxy>>();
|
||||
private readonly _terminalProcessesReady = new Map<number, (proxy: ITerminalProcessExtHostProxy) => void>();
|
||||
private readonly _terminalProcessProxies = new Map<number, ITerminalProcessExtHostProxy>();
|
||||
private _dataEventTracker: TerminalDataEventTracker | undefined;
|
||||
private _linkHandler: IDisposable | undefined;
|
||||
|
||||
@@ -106,7 +105,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
isExtensionTerminal: launchConfig.isExtensionTerminal
|
||||
};
|
||||
const terminal = this._terminalService.createTerminal(shellLaunchConfig);
|
||||
this._terminalProcesses.set(terminal.id, new Promise<ITerminalProcessExtHostProxy>(r => this._terminalProcessesReady.set(terminal.id, r)));
|
||||
return Promise.resolve({
|
||||
id: terminal.id,
|
||||
name: terminal.title
|
||||
@@ -232,13 +230,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
}
|
||||
|
||||
const proxy = request.proxy;
|
||||
const ready = this._terminalProcessesReady.get(proxy.terminalId);
|
||||
if (ready) {
|
||||
ready(proxy);
|
||||
this._terminalProcessesReady.delete(proxy.terminalId);
|
||||
} else {
|
||||
this._terminalProcesses.set(proxy.terminalId, Promise.resolve(proxy));
|
||||
}
|
||||
this._terminalProcessProxies.set(proxy.terminalId, proxy);
|
||||
const shellLaunchConfigDto: IShellLaunchConfigDto = {
|
||||
name: request.shellLaunchConfig.name,
|
||||
executable: request.shellLaunchConfig.executable,
|
||||
@@ -246,7 +238,16 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
cwd: request.shellLaunchConfig.cwd,
|
||||
env: request.shellLaunchConfig.env
|
||||
};
|
||||
this._proxy.$spawnExtHostProcess(proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed);
|
||||
|
||||
this._proxy.$spawnExtHostProcess(
|
||||
proxy.terminalId,
|
||||
shellLaunchConfigDto,
|
||||
request.activeWorkspaceRootUri,
|
||||
request.cols,
|
||||
request.rows,
|
||||
request.isWorkspaceShellAllowed
|
||||
).then(request.callback);
|
||||
|
||||
proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data));
|
||||
proxy.onResize(dimensions => this._proxy.$acceptProcessResize(proxy.terminalId, dimensions.cols, dimensions.rows));
|
||||
proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate));
|
||||
@@ -257,13 +258,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
|
||||
private _onRequestStartExtensionTerminal(request: IStartExtensionTerminalRequest): void {
|
||||
const proxy = request.proxy;
|
||||
const ready = this._terminalProcessesReady.get(proxy.terminalId);
|
||||
if (!ready) {
|
||||
this._terminalProcesses.set(proxy.terminalId, Promise.resolve(proxy));
|
||||
} else {
|
||||
ready(proxy);
|
||||
this._terminalProcessesReady.delete(proxy.terminalId);
|
||||
}
|
||||
this._terminalProcessProxies.set(proxy.terminalId, proxy);
|
||||
|
||||
// Note that onReisze is not being listened to here as it needs to fire when max dimensions
|
||||
// change, excluding the dimension override
|
||||
@@ -271,7 +266,12 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
columns: request.cols,
|
||||
rows: request.rows
|
||||
} : undefined;
|
||||
this._proxy.$startExtensionTerminal(proxy.terminalId, initialDimensions);
|
||||
|
||||
this._proxy.$startExtensionTerminal(
|
||||
proxy.terminalId,
|
||||
initialDimensions
|
||||
).then(request.callback);
|
||||
|
||||
proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data));
|
||||
proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate));
|
||||
proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(proxy.terminalId));
|
||||
@@ -280,38 +280,38 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
}
|
||||
|
||||
public $sendProcessTitle(terminalId: number, title: string): void {
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitTitle(title));
|
||||
this._getTerminalProcess(terminalId).emitTitle(title);
|
||||
}
|
||||
|
||||
public $sendProcessData(terminalId: number, data: string): void {
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitData(data));
|
||||
this._getTerminalProcess(terminalId).emitData(data);
|
||||
}
|
||||
|
||||
public $sendProcessReady(terminalId: number, pid: number, cwd: string): void {
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitReady(pid, cwd));
|
||||
this._getTerminalProcess(terminalId).emitReady(pid, cwd);
|
||||
}
|
||||
|
||||
public $sendProcessExit(terminalId: number, exitCode: number | undefined): void {
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitExit(exitCode));
|
||||
this._terminalProcesses.delete(terminalId);
|
||||
this._getTerminalProcess(terminalId).emitExit(exitCode);
|
||||
this._terminalProcessProxies.delete(terminalId);
|
||||
}
|
||||
|
||||
public $sendOverrideDimensions(terminalId: number, dimensions: ITerminalDimensions | undefined): void {
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitOverrideDimensions(dimensions));
|
||||
this._getTerminalProcess(terminalId).emitOverrideDimensions(dimensions);
|
||||
}
|
||||
|
||||
public $sendProcessInitialCwd(terminalId: number, initialCwd: string): void {
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitInitialCwd(initialCwd));
|
||||
this._getTerminalProcess(terminalId).emitInitialCwd(initialCwd);
|
||||
}
|
||||
|
||||
public $sendProcessCwd(terminalId: number, cwd: string): void {
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitCwd(cwd));
|
||||
this._getTerminalProcess(terminalId).emitCwd(cwd);
|
||||
}
|
||||
|
||||
public $sendResolvedLaunchConfig(terminalId: number, shellLaunchConfig: IShellLaunchConfig): void {
|
||||
const instance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (instance) {
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitResolvedShellLaunchConfig(shellLaunchConfig));
|
||||
this._getTerminalProcess(terminalId).emitResolvedShellLaunchConfig(shellLaunchConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,7 +324,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
sw.stop();
|
||||
sum += sw.elapsed();
|
||||
}
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitLatency(sum / COUNT));
|
||||
this._getTerminalProcess(terminalId).emitLatency(sum / COUNT);
|
||||
}
|
||||
|
||||
private _isPrimaryExtHost(): boolean {
|
||||
@@ -349,8 +349,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
}
|
||||
}
|
||||
|
||||
private _getTerminalProcess(terminalId: number): Promise<ITerminalProcessExtHostProxy> {
|
||||
const terminal = this._terminalProcesses.get(terminalId);
|
||||
private _getTerminalProcess(terminalId: number): ITerminalProcessExtHostProxy {
|
||||
const terminal = this._terminalProcessProxies.get(terminalId);
|
||||
if (!terminal) {
|
||||
throw new Error(`Unknown terminal: ${terminalId}`);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { onUnexpectedError, isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, DisposableStore, dispose, IDisposable, IReference } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
@@ -252,7 +252,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
|
||||
public async $postMessage(handle: extHostProtocol.WebviewPanelHandle, message: any): Promise<boolean> {
|
||||
const webview = this.getWebviewInput(handle);
|
||||
webview.webview.sendMessage(message);
|
||||
webview.webview.postMessage(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -280,8 +280,8 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
if (webviewInput.webview.state) {
|
||||
try {
|
||||
state = JSON.parse(webviewInput.webview.state);
|
||||
} catch {
|
||||
// noop
|
||||
} catch (e) {
|
||||
console.error('Could not load webview state', e, webviewInput.webview.state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -925,7 +925,12 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
|
||||
this._backupId = backupId;
|
||||
}
|
||||
} catch (e) {
|
||||
// Make sure state has not changed in the meantime
|
||||
if (isPromiseCanceledError(e)) {
|
||||
// This is expected
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Otherwise it could be a real error. Make sure state has not changed in the meantime.
|
||||
if (this._hotExitState === pendingState) {
|
||||
this._hotExitState = HotExitState.NotAllowed;
|
||||
}
|
||||
|
||||
@@ -97,12 +97,12 @@ CommandsRegistry.registerCommand({
|
||||
|
||||
export class DiffAPICommand {
|
||||
public static readonly ID = 'vscode.diff';
|
||||
public static execute(executor: ICommandsExecutor, left: URI, right: URI, label: string, options?: vscode.TextDocumentShowOptions): Promise<any> {
|
||||
public static execute(executor: ICommandsExecutor, left: URI, right: URI, label: string, options?: typeConverters.TextEditorOpenOptions): Promise<any> {
|
||||
return executor.executeCommand('_workbench.diff', [
|
||||
left, right,
|
||||
label,
|
||||
undefined,
|
||||
typeConverters.TextEditorOptions.from(options),
|
||||
typeConverters.TextEditorOpenOptions.from(options),
|
||||
options ? typeConverters.ViewColumn.from(options.viewColumn) : undefined
|
||||
]);
|
||||
}
|
||||
@@ -111,7 +111,7 @@ CommandsRegistry.registerCommand(DiffAPICommand.ID, adjustHandler(DiffAPICommand
|
||||
|
||||
export class OpenAPICommand {
|
||||
public static readonly ID = 'vscode.open';
|
||||
public static execute(executor: ICommandsExecutor, resource: URI, columnOrOptions?: vscode.ViewColumn | vscode.TextDocumentShowOptions, label?: string): Promise<any> {
|
||||
public static execute(executor: ICommandsExecutor, resource: URI, columnOrOptions?: vscode.ViewColumn | typeConverters.TextEditorOpenOptions, label?: string): Promise<any> {
|
||||
let options: ITextEditorOptions | undefined;
|
||||
let position: EditorViewColumn | undefined;
|
||||
|
||||
@@ -119,7 +119,7 @@ export class OpenAPICommand {
|
||||
if (typeof columnOrOptions === 'number') {
|
||||
position = typeConverters.ViewColumn.from(columnOrOptions);
|
||||
} else {
|
||||
options = typeConverters.TextEditorOptions.from(columnOrOptions);
|
||||
options = typeConverters.TextEditorOpenOptions.from(columnOrOptions);
|
||||
position = typeConverters.ViewColumn.from(columnOrOptions.viewColumn);
|
||||
}
|
||||
}
|
||||
@@ -136,14 +136,14 @@ CommandsRegistry.registerCommand(OpenAPICommand.ID, adjustHandler(OpenAPICommand
|
||||
|
||||
export class OpenWithAPICommand {
|
||||
public static readonly ID = 'vscode.openWith';
|
||||
public static execute(executor: ICommandsExecutor, resource: URI, viewType: string, columnOrOptions?: vscode.ViewColumn | vscode.TextDocumentShowOptions): Promise<any> {
|
||||
public static execute(executor: ICommandsExecutor, resource: URI, viewType: string, columnOrOptions?: vscode.ViewColumn | typeConverters.TextEditorOpenOptions): Promise<any> {
|
||||
let options: ITextEditorOptions | undefined;
|
||||
let position: EditorViewColumn | undefined;
|
||||
|
||||
if (typeof columnOrOptions === 'number') {
|
||||
position = typeConverters.ViewColumn.from(columnOrOptions);
|
||||
} else if (typeof columnOrOptions !== 'undefined') {
|
||||
options = typeConverters.TextEditorOptions.from(columnOrOptions);
|
||||
options = typeConverters.TextEditorOpenOptions.from(columnOrOptions);
|
||||
}
|
||||
|
||||
return executor.executeCommand('_workbench.openWith', [
|
||||
|
||||
@@ -93,12 +93,14 @@ const defaultConfigurationExtPoint = ExtensionsRegistry.registerExtensionPoint<I
|
||||
description: nls.localize('vscode.extension.contributes.defaultConfiguration', 'Contributes default editor configuration settings by language.'),
|
||||
type: 'object',
|
||||
patternProperties: {
|
||||
'\\[.*\\]$': {
|
||||
'^\\[.*\\]$': {
|
||||
type: 'object',
|
||||
default: {},
|
||||
$ref: resourceLanguageSettingsSchemaId,
|
||||
}
|
||||
}
|
||||
},
|
||||
errorMessage: nls.localize('config.property.defaultConfiguration.languageExpected', "Language selector expected (e.g. [\"java\"])"),
|
||||
additionalProperties: false
|
||||
}
|
||||
});
|
||||
defaultConfigurationExtPoint.setHandler((extensions, { added, removed }) => {
|
||||
|
||||
@@ -135,7 +135,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
|
||||
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
|
||||
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
|
||||
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment));
|
||||
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment, extensionStoragePaths));
|
||||
const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol));
|
||||
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol));
|
||||
const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol, extHostCommands));
|
||||
@@ -458,16 +458,12 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
get terminals() {
|
||||
return extHostTerminalService.terminals;
|
||||
},
|
||||
showTextDocument(documentOrUri: vscode.TextDocument | vscode.Uri, columnOrOptions?: vscode.ViewColumn | vscode.TextDocumentShowOptions, preserveFocus?: boolean): Thenable<vscode.TextEditor> {
|
||||
let documentPromise: Promise<vscode.TextDocument>;
|
||||
if (URI.isUri(documentOrUri)) {
|
||||
documentPromise = Promise.resolve(workspace.openTextDocument(documentOrUri));
|
||||
} else {
|
||||
documentPromise = Promise.resolve(<vscode.TextDocument>documentOrUri);
|
||||
}
|
||||
return documentPromise.then(document => {
|
||||
return extHostEditors.showTextDocument(document, columnOrOptions, preserveFocus);
|
||||
});
|
||||
async showTextDocument(documentOrUri: vscode.TextDocument | vscode.Uri, columnOrOptions?: vscode.ViewColumn | vscode.TextDocumentShowOptions, preserveFocus?: boolean): Promise<vscode.TextEditor> {
|
||||
const document = await (URI.isUri(documentOrUri)
|
||||
? Promise.resolve(workspace.openTextDocument(documentOrUri))
|
||||
: Promise.resolve(<vscode.TextDocument>documentOrUri));
|
||||
|
||||
return extHostEditors.showTextDocument(document, columnOrOptions, preserveFocus);
|
||||
},
|
||||
createTextEditorDecorationType(options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType {
|
||||
return extHostEditors.createTextEditorDecorationType(options);
|
||||
@@ -602,11 +598,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => {
|
||||
return extHostWebviews.registerWebviewPanelSerializer(extension, viewType, serializer);
|
||||
},
|
||||
registerCustomEditorProvider: (viewType: string, provider: vscode.CustomTextEditorProvider, options: { webviewOptions?: vscode.WebviewPanelOptions } = {}) => {
|
||||
return extHostWebviews.registerCustomEditorProvider(extension, viewType, provider, options);
|
||||
},
|
||||
registerCustomEditorProvider2: (viewType: string, provider: vscode.CustomReadonlyEditorProvider, options: { webviewOptions?: vscode.WebviewPanelOptions, supportsMultipleEditorsPerDocument?: boolean } = {}) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
registerCustomEditorProvider: (viewType: string, provider: vscode.CustomTextEditorProvider | vscode.CustomReadonlyEditorProvider, options: { webviewOptions?: vscode.WebviewPanelOptions, supportsMultipleEditorsPerDocument?: boolean } = {}) => {
|
||||
return extHostWebviews.registerCustomEditorProvider(extension, viewType, provider, options);
|
||||
},
|
||||
registerDecorationProvider(provider: vscode.DecorationProvider) {
|
||||
@@ -946,10 +938,16 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.onDidCloseNotebookDocument;
|
||||
},
|
||||
get notebookDocuments(): vscode.NotebookDocument[] {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.notebookDocuments;
|
||||
},
|
||||
get visibleNotebookEditors() {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.visibleNotebookEditors;
|
||||
},
|
||||
get onDidChangeVisibleNotebookEditors() {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.onDidChangeVisibleNotebookEditors;
|
||||
},
|
||||
registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider) => {
|
||||
@@ -964,10 +962,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.registerNotebookOutputRenderer(type, extension, outputFilter, renderer);
|
||||
},
|
||||
get activeNotebookDocument(): vscode.NotebookDocument | undefined {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.activeNotebookDocument;
|
||||
},
|
||||
get activeNotebookEditor(): vscode.NotebookEditor | undefined {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.activeNotebookEditor;
|
||||
|
||||
@@ -31,7 +31,7 @@ import { LogLevel } from 'vs/platform/log/common/log';
|
||||
import { IMarkerData } from 'vs/platform/markers/common/markers';
|
||||
import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress';
|
||||
import * as quickInput from 'vs/platform/quickinput/common/quickInput';
|
||||
import { RemoteAuthorityResolverErrorCode, ResolverResult, TunnelDescription } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { RemoteAuthorityResolverErrorCode, ResolverResult, TunnelDescription, IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import * as statusbar from 'vs/workbench/services/statusbar/common/statusbar';
|
||||
import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';
|
||||
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
|
||||
@@ -41,7 +41,7 @@ import * as tasks from 'vs/workbench/api/common/shared/tasks';
|
||||
import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views';
|
||||
import { IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder';
|
||||
import { ITerminalDimensions, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ITerminalDimensions, IShellLaunchConfig, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId, IRPCProtocol } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import * as search from 'vs/workbench/services/search/common/search';
|
||||
@@ -51,7 +51,7 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
|
||||
import { TunnelOptions } from 'vs/platform/remote/common/tunnel';
|
||||
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
import { INotebookMimeTypeSelector, IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent, NotebookDataDto, INotebookKernelInfoDto, IMainCellDto, IOutputRenderRequest, IOutputRenderResponse, IRawOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { INotebookMimeTypeSelector, IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent, NotebookDataDto, INotebookKernelInfoDto, IMainCellDto, IOutputRenderRequest, IOutputRenderResponse } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { Dto } from 'vs/base/common/types';
|
||||
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
|
||||
@@ -103,7 +103,7 @@ export interface IInitData {
|
||||
logsLocation: URI;
|
||||
logFile: URI;
|
||||
autoStart: boolean;
|
||||
remote: { isRemote: boolean; authority: string | undefined; };
|
||||
remote: { isRemote: boolean; authority: string | undefined; connectionData: IRemoteConnectionData | null; };
|
||||
uiKind: UIKind;
|
||||
}
|
||||
|
||||
@@ -697,11 +697,11 @@ export type NotebookCellsSplice = [
|
||||
export type NotebookCellOutputsSplice = [
|
||||
number /* start */,
|
||||
number /* delete count */,
|
||||
IRawOutput[]
|
||||
IProcessedOutput[]
|
||||
];
|
||||
|
||||
export interface MainThreadNotebookShape extends IDisposable {
|
||||
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, kernelInfoDto: INotebookKernelInfoDto | undefined): Promise<void>;
|
||||
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, kernelInfoDto: INotebookKernelInfoDto | undefined): Promise<void>;
|
||||
$onNotebookChange(viewType: string, resource: UriComponents): Promise<void>;
|
||||
$unregisterNotebookProvider(viewType: string): Promise<void>;
|
||||
$registerNotebookRenderer(extension: NotebookExtensionDescription, type: string, selectors: INotebookMimeTypeSelector, preloads: UriComponents[]): Promise<void>;
|
||||
@@ -714,6 +714,9 @@ export interface MainThreadNotebookShape extends IDisposable {
|
||||
$updateNotebookCellMetadata(viewType: string, resource: UriComponents, handle: number, metadata: NotebookCellMetadata | undefined): Promise<void>;
|
||||
$spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void>;
|
||||
$postMessage(handle: number, value: any): Promise<boolean>;
|
||||
|
||||
$onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void;
|
||||
$onContentChange(resource: UriComponents, viewType: string): void;
|
||||
}
|
||||
|
||||
export interface MainThreadUrlsShape extends IDisposable {
|
||||
@@ -778,7 +781,8 @@ export interface MainThreadTaskShape extends IDisposable {
|
||||
$registerTaskProvider(handle: number, type: string): Promise<void>;
|
||||
$unregisterTaskProvider(handle: number): Promise<void>;
|
||||
$fetchTasks(filter?: tasks.TaskFilterDTO): Promise<tasks.TaskDTO[]>;
|
||||
$executeTask(task: tasks.TaskHandleDTO | tasks.TaskDTO): Promise<tasks.TaskExecutionDTO>;
|
||||
$getTaskExecution(value: tasks.TaskHandleDTO | tasks.TaskDTO): Promise<tasks.TaskExecutionDTO>;
|
||||
$executeTask(task: tasks.TaskDTO): Promise<tasks.TaskExecutionDTO>;
|
||||
$terminateTask(id: string): Promise<void>;
|
||||
$registerTaskSystem(scheme: string, info: tasks.TaskSystemInfoDTO): void;
|
||||
$customExecutionComplete(id: string, result?: number): Promise<void>;
|
||||
@@ -855,6 +859,7 @@ export interface IDebugConfiguration {
|
||||
export interface IStartDebuggingOptions {
|
||||
parentSessionID?: DebugSessionUUID;
|
||||
repl?: IDebugSessionReplMode;
|
||||
noDebug?: boolean;
|
||||
}
|
||||
|
||||
export interface MainThreadDebugServiceShape extends IDisposable {
|
||||
@@ -1051,6 +1056,7 @@ export interface ExtHostExtensionServiceShape {
|
||||
$activateByEvent(activationEvent: string): Promise<void>;
|
||||
$activate(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<boolean>;
|
||||
$setRemoteEnvironment(env: { [key: string]: string | null; }): Promise<void>;
|
||||
$updateRemoteConnectionData(connectionData: IRemoteConnectionData): Promise<void>;
|
||||
|
||||
$deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void>;
|
||||
|
||||
@@ -1393,8 +1399,8 @@ export interface ExtHostTerminalServiceShape {
|
||||
$acceptTerminalTitleChange(id: number, name: string): void;
|
||||
$acceptTerminalDimensions(id: number, cols: number, rows: number): void;
|
||||
$acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void;
|
||||
$spawnExtHostProcess(id: number, shellLaunchConfig: IShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents | undefined, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void;
|
||||
$startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void;
|
||||
$spawnExtHostProcess(id: number, shellLaunchConfig: IShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents | undefined, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<ITerminalLaunchError | undefined>;
|
||||
$startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise<ITerminalLaunchError | undefined>;
|
||||
$acceptProcessInput(id: number, data: string): void;
|
||||
$acceptProcessResize(id: number, cols: number, rows: number): void;
|
||||
$acceptProcessShutdown(id: number, immediate: boolean): void;
|
||||
@@ -1583,11 +1589,13 @@ export interface INotebookDocumentsAndEditorsDelta {
|
||||
}
|
||||
|
||||
export interface ExtHostNotebookShape {
|
||||
$resolveNotebookData(viewType: string, uri: UriComponents): Promise<NotebookDataDto | undefined>;
|
||||
$resolveNotebookData(viewType: string, uri: UriComponents, backupId?: string): Promise<NotebookDataDto | undefined>;
|
||||
$resolveNotebookEditor(viewType: string, uri: UriComponents, editorId: string): Promise<void>;
|
||||
$executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, useAttachedKernel: boolean, token: CancellationToken): Promise<void>;
|
||||
$executeNotebook2(kernelId: string, viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void>;
|
||||
$saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean>;
|
||||
$saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean>;
|
||||
$backup(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string | undefined>;
|
||||
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
|
||||
$renderOutputs(uriComponents: UriComponents, id: string, request: IOutputRenderRequest<UriComponents>): Promise<IOutputRenderResponse<UriComponents> | undefined>;
|
||||
$renderOutputs2<T>(uriComponents: UriComponents, id: string, request: IOutputRenderRequest<T>): Promise<IOutputRenderResponse<T> | undefined>;
|
||||
@@ -1595,6 +1603,9 @@ export interface ExtHostNotebookShape {
|
||||
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent): void;
|
||||
$acceptEditorPropertiesChanged(uriComponents: UriComponents, data: INotebookEditorPropertiesChangeData): void;
|
||||
$acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta): Promise<void>;
|
||||
$undoNotebook(viewType: string, uri: UriComponents, editId: number, isDirty: boolean): Promise<void>;
|
||||
$redoNotebook(viewType: string, uri: UriComponents, editId: number, isDirty: boolean): Promise<void>;
|
||||
|
||||
}
|
||||
|
||||
export interface ExtHostStorageShape {
|
||||
|
||||
@@ -10,7 +10,7 @@ import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
|
||||
export interface IExtHostApiDeprecationService {
|
||||
_serviceBrand: undefined;
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
report(apiId: string, extension: IExtensionDescription, migrationSuggestion: string): void;
|
||||
}
|
||||
@@ -19,7 +19,7 @@ export const IExtHostApiDeprecationService = createDecorator<IExtHostApiDeprecat
|
||||
|
||||
export class ExtHostApiDeprecationService implements IExtHostApiDeprecationService {
|
||||
|
||||
_serviceBrand: undefined;
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly _reportedUsages = new Set<string>();
|
||||
private readonly _telemetryShape: extHostProtocol.MainThreadTelemetryShape;
|
||||
@@ -63,7 +63,7 @@ export class ExtHostApiDeprecationService implements IExtHostApiDeprecationServi
|
||||
|
||||
|
||||
export const NullApiDeprecationService = Object.freeze(new class implements IExtHostApiDeprecationService {
|
||||
_serviceBrand: undefined;
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
public report(_apiId: string, _extension: IExtensionDescription, _warningMessage: string): void {
|
||||
// noop
|
||||
|
||||
@@ -28,11 +28,11 @@ export class ExtHostEditorInsets implements ExtHostEditorInsetsShape {
|
||||
// dispose editor inset whenever the hosting editor goes away
|
||||
this._disposables.add(_editors.onDidChangeVisibleTextEditors(() => {
|
||||
const visibleEditor = _editors.getVisibleTextEditors();
|
||||
this._insets.forEach(value => {
|
||||
for (const value of this._insets.values()) {
|
||||
if (visibleEditor.indexOf(value.editor) < 0) {
|
||||
value.inset.dispose(); // will remove from `this._insets`
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -204,12 +204,12 @@ export class ExtHostCommands implements ExtHostCommandsShape {
|
||||
|
||||
$getContributedCommandHandlerDescriptions(): Promise<{ [id: string]: string | ICommandHandlerDescription }> {
|
||||
const result: { [id: string]: string | ICommandHandlerDescription } = Object.create(null);
|
||||
this._commands.forEach((command, id) => {
|
||||
for (let [id, command] of this._commands) {
|
||||
let { description } = command;
|
||||
if (description) {
|
||||
result[id] = description;
|
||||
}
|
||||
});
|
||||
}
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ export interface IExtHostDebugService extends ExtHostDebugServiceShape {
|
||||
asDebugSourceUri(source: vscode.DebugProtocolSource, session?: vscode.DebugSession): vscode.Uri;
|
||||
}
|
||||
|
||||
export class ExtHostDebugServiceBase implements IExtHostDebugService, ExtHostDebugServiceShape {
|
||||
export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, ExtHostDebugServiceShape {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
@@ -295,7 +295,8 @@ export class ExtHostDebugServiceBase implements IExtHostDebugService, ExtHostDeb
|
||||
public startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration, options: vscode.DebugSessionOptions): Promise<boolean> {
|
||||
return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig, {
|
||||
parentSessionID: options.parentSession ? options.parentSession.id : undefined,
|
||||
repl: options.consoleMode === DebugConsoleMode.MergeWithParent ? 'mergeWithParent' : 'separate'
|
||||
repl: options.consoleMode === DebugConsoleMode.MergeWithParent ? 'mergeWithParent' : 'separate',
|
||||
noDebug: options.noDebug
|
||||
});
|
||||
}
|
||||
|
||||
@@ -372,9 +373,7 @@ export class ExtHostDebugServiceBase implements IExtHostDebugService, ExtHostDeb
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
protected createVariableResolver(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider): AbstractVariableResolverService {
|
||||
return new ExtHostVariableResolverService(folders, editorService, configurationService);
|
||||
}
|
||||
protected abstract createVariableResolver(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider): AbstractVariableResolverService;
|
||||
|
||||
public async $substituteVariables(folderUri: UriComponents | undefined, config: IConfig): Promise<IConfig> {
|
||||
if (!this._variableResolver) {
|
||||
@@ -973,7 +972,7 @@ export class ExtHostDebugConsole implements vscode.DebugConsole {
|
||||
|
||||
export class ExtHostVariableResolverService extends AbstractVariableResolverService {
|
||||
|
||||
constructor(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider, env?: IProcessEnvironment) {
|
||||
constructor(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors | undefined, configurationService: ExtHostConfigProvider, env?: IProcessEnvironment) {
|
||||
super({
|
||||
getFolderUri: (folderName: string): URI | undefined => {
|
||||
const found = folders.filter(f => f.name === folderName);
|
||||
@@ -992,27 +991,33 @@ export class ExtHostVariableResolverService extends AbstractVariableResolverServ
|
||||
return env ? env['VSCODE_EXEC_PATH'] : undefined;
|
||||
},
|
||||
getFilePath: (): string | undefined => {
|
||||
const activeEditor = editorService.activeEditor();
|
||||
if (activeEditor) {
|
||||
return path.normalize(activeEditor.document.uri.fsPath);
|
||||
if (editorService) {
|
||||
const activeEditor = editorService.activeEditor();
|
||||
if (activeEditor) {
|
||||
return path.normalize(activeEditor.document.uri.fsPath);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
getSelectedText: (): string | undefined => {
|
||||
const activeEditor = editorService.activeEditor();
|
||||
if (activeEditor && !activeEditor.selection.isEmpty) {
|
||||
return activeEditor.document.getText(activeEditor.selection);
|
||||
if (editorService) {
|
||||
const activeEditor = editorService.activeEditor();
|
||||
if (activeEditor && !activeEditor.selection.isEmpty) {
|
||||
return activeEditor.document.getText(activeEditor.selection);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
getLineNumber: (): string | undefined => {
|
||||
const activeEditor = editorService.activeEditor();
|
||||
if (activeEditor) {
|
||||
return String(activeEditor.selection.end.line + 1);
|
||||
if (editorService) {
|
||||
const activeEditor = editorService.activeEditor();
|
||||
if (activeEditor) {
|
||||
return String(activeEditor.selection.end.line + 1);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}, env);
|
||||
}, env, !editorService);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1103,4 +1108,8 @@ export class WorkerExtHostDebugService extends ExtHostDebugServiceBase {
|
||||
) {
|
||||
super(extHostRpcService, workspaceService, extensionService, editorsService, configurationService, commandService);
|
||||
}
|
||||
|
||||
protected createVariableResolver(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider): AbstractVariableResolverService {
|
||||
return new ExtHostVariableResolverService(folders, editorService, configurationService);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,9 +173,9 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
|
||||
|
||||
forEach(callback: (uri: URI, diagnostics: ReadonlyArray<vscode.Diagnostic>, collection: DiagnosticCollection) => any, thisArg?: any): void {
|
||||
this._checkDisposed();
|
||||
this._data.forEach((value, uri) => {
|
||||
for (let uri of this._data.keys()) {
|
||||
callback.apply(thisArg, [uri, this.get(uri), this]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get(uri: URI): ReadonlyArray<vscode.Diagnostic> {
|
||||
@@ -307,7 +307,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
|
||||
} else {
|
||||
const index = new Map<string, number>();
|
||||
const res: [vscode.Uri, vscode.Diagnostic[]][] = [];
|
||||
this._collections.forEach(collection => {
|
||||
for (const collection of this._collections.values()) {
|
||||
collection.forEach((uri, diagnostics) => {
|
||||
let idx = index.get(uri.toString());
|
||||
if (typeof idx === 'undefined') {
|
||||
@@ -317,18 +317,18 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
|
||||
}
|
||||
res[idx][1] = res[idx][1].concat(...diagnostics);
|
||||
});
|
||||
});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
private _getDiagnostics(resource: vscode.Uri): ReadonlyArray<vscode.Diagnostic> {
|
||||
let res: vscode.Diagnostic[] = [];
|
||||
this._collections.forEach(collection => {
|
||||
for (let collection of this._collections.values()) {
|
||||
if (collection.has(resource)) {
|
||||
res = res.concat(collection.get(resource));
|
||||
}
|
||||
});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { ExtHostTextEditor } from 'vs/workbench/api/common/extHostTextEditor';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
|
||||
export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsShape {
|
||||
|
||||
@@ -22,7 +23,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
|
||||
private _activeEditorId: string | null = null;
|
||||
|
||||
private readonly _editors = new Map<string, ExtHostTextEditor>();
|
||||
private readonly _documents = new Map<string, ExtHostDocumentData>();
|
||||
private readonly _documents = new ResourceMap<ExtHostDocumentData>();
|
||||
|
||||
private readonly _onDidAddDocuments = new Emitter<ExtHostDocumentData[]>();
|
||||
private readonly _onDidRemoveDocuments = new Emitter<ExtHostDocumentData[]>();
|
||||
@@ -48,9 +49,8 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
|
||||
if (delta.removedDocuments) {
|
||||
for (const uriComponent of delta.removedDocuments) {
|
||||
const uri = URI.revive(uriComponent);
|
||||
const id = uri.toString();
|
||||
const data = this._documents.get(id);
|
||||
this._documents.delete(id);
|
||||
const data = this._documents.get(uri);
|
||||
this._documents.delete(uri);
|
||||
if (data) {
|
||||
removedDocuments.push(data);
|
||||
}
|
||||
@@ -60,7 +60,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
|
||||
if (delta.addedDocuments) {
|
||||
for (const data of delta.addedDocuments) {
|
||||
const resource = URI.revive(data.uri);
|
||||
assert.ok(!this._documents.has(resource.toString()), `document '${resource} already exists!'`);
|
||||
assert.ok(!this._documents.has(resource), `document '${resource} already exists!'`);
|
||||
|
||||
const documentData = new ExtHostDocumentData(
|
||||
this._extHostRpc.getProxy(MainContext.MainThreadDocuments),
|
||||
@@ -71,7 +71,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
|
||||
data.versionId,
|
||||
data.isDirty
|
||||
);
|
||||
this._documents.set(resource.toString(), documentData);
|
||||
this._documents.set(resource, documentData);
|
||||
addedDocuments.push(documentData);
|
||||
}
|
||||
}
|
||||
@@ -89,10 +89,10 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
|
||||
if (delta.addedEditors) {
|
||||
for (const data of delta.addedEditors) {
|
||||
const resource = URI.revive(data.documentUri);
|
||||
assert.ok(this._documents.has(resource.toString()), `document '${resource}' does not exist`);
|
||||
assert.ok(this._documents.has(resource), `document '${resource}' does not exist`);
|
||||
assert.ok(!this._editors.has(data.id), `editor '${data.id}' already exists!`);
|
||||
|
||||
const documentData = this._documents.get(resource.toString())!;
|
||||
const documentData = this._documents.get(resource)!;
|
||||
const editor = new ExtHostTextEditor(
|
||||
data.id,
|
||||
this._extHostRpc.getProxy(MainContext.MainThreadTextEditors),
|
||||
@@ -132,13 +132,11 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
|
||||
}
|
||||
|
||||
getDocument(uri: URI): ExtHostDocumentData | undefined {
|
||||
return this._documents.get(uri.toString());
|
||||
return this._documents.get(uri);
|
||||
}
|
||||
|
||||
allDocuments(): ExtHostDocumentData[] {
|
||||
const result: ExtHostDocumentData[] = [];
|
||||
this._documents.forEach(data => result.push(data));
|
||||
return result;
|
||||
return [...this._documents.values()];
|
||||
}
|
||||
|
||||
getEditor(id: string): ExtHostTextEditor | undefined {
|
||||
@@ -154,9 +152,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
|
||||
}
|
||||
|
||||
allEditors(): ExtHostTextEditor[] {
|
||||
const result: ExtHostTextEditor[] = [];
|
||||
this._editors.forEach(data => result.push(data));
|
||||
return result;
|
||||
return [...this._editors.values()];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
import * as nls from 'vs/nls';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import { originalFSPath, joinPath } from 'vs/base/common/resources';
|
||||
import { Barrier } from 'vs/base/common/async';
|
||||
import { dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Barrier, timeout } from 'vs/base/common/async';
|
||||
import { dispose, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
@@ -16,7 +16,7 @@ import { ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/co
|
||||
import { ActivatedExtension, EmptyExtension, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { ExtHostStorage, IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { ExtensionActivationError, checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
@@ -26,7 +26,7 @@ import { Schemas } from 'vs/base/common/network';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento';
|
||||
import { RemoteAuthorityResolverError, ExtensionMode } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ResolvedAuthority, ResolvedOptions, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { ResolvedAuthority, ResolvedOptions, RemoteAuthorityResolverErrorCode, IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||
@@ -34,6 +34,7 @@ import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
|
||||
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
|
||||
interface ITestRunner {
|
||||
/** Old test runner API, as exported from `vscode/lib/testrunner` */
|
||||
@@ -48,7 +49,7 @@ interface INewTestRunner {
|
||||
export const IHostUtils = createDecorator<IHostUtils>('IHostUtils');
|
||||
|
||||
export interface IHostUtils {
|
||||
_serviceBrand: undefined;
|
||||
readonly _serviceBrand: undefined;
|
||||
exit(code?: number): void;
|
||||
exists(path: string): Promise<boolean>;
|
||||
realpath(path: string): Promise<string>;
|
||||
@@ -65,12 +66,15 @@ type TelemetryActivationEventFragment = {
|
||||
reasonId: { classification: 'PublicNonPersonalData', purpose: 'FeatureInsight' };
|
||||
};
|
||||
|
||||
export abstract class AbstractExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
export abstract class AbstractExtHostExtensionService extends Disposable implements ExtHostExtensionServiceShape {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private static readonly WORKSPACE_CONTAINS_TIMEOUT = 7000;
|
||||
|
||||
private readonly _onDidChangeRemoteConnectionData = this._register(new Emitter<void>());
|
||||
public readonly onDidChangeRemoteConnectionData = this._onDidChangeRemoteConnectionData.event;
|
||||
|
||||
protected readonly _hostUtils: IHostUtils;
|
||||
protected readonly _initData: IInitData;
|
||||
protected readonly _extHostContext: IExtHostRpcService;
|
||||
@@ -97,6 +101,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
||||
private readonly _resolvers: { [authorityPrefix: string]: vscode.RemoteAuthorityResolver; };
|
||||
|
||||
private _started: boolean;
|
||||
private _remoteConnectionData: IRemoteConnectionData | null;
|
||||
|
||||
private readonly _disposables: DisposableStore;
|
||||
|
||||
@@ -112,6 +117,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
||||
@IExtHostTunnelService extHostTunnelService: IExtHostTunnelService,
|
||||
@IExtHostTerminalService extHostTerminalService: IExtHostTerminalService
|
||||
) {
|
||||
super();
|
||||
this._hostUtils = hostUtils;
|
||||
this._extHostContext = extHostContext;
|
||||
this._initData = initData;
|
||||
@@ -164,6 +170,11 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
||||
this._extensionPathIndex = null;
|
||||
this._resolvers = Object.create(null);
|
||||
this._started = false;
|
||||
this._remoteConnectionData = this._initData.remote.connectionData;
|
||||
}
|
||||
|
||||
public getRemoteConnectionData(): IRemoteConnectionData | null {
|
||||
return this._remoteConnectionData;
|
||||
}
|
||||
|
||||
public async initialize(): Promise<void> {
|
||||
@@ -360,7 +371,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
||||
const workspaceState = new ExtensionMemento(extensionDescription.identifier.value, false, this._storage);
|
||||
const extensionMode = extensionDescription.isUnderDevelopment
|
||||
? (this._initData.environment.extensionTestsLocationURI ? ExtensionMode.Test : ExtensionMode.Development)
|
||||
: ExtensionMode.Release;
|
||||
: ExtensionMode.Production;
|
||||
|
||||
this._logService.trace(`ExtensionService#loadExtensionContext ${extensionDescription.identifier.value}`);
|
||||
|
||||
@@ -380,10 +391,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
||||
get globalStoragePath() { return that._storagePath.globalValue(extensionDescription); },
|
||||
asAbsolutePath(relativePath: string) { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); },
|
||||
get logPath() { return path.join(that._initData.logsLocation.fsPath, extensionDescription.identifier.value); },
|
||||
get extensionMode() {
|
||||
checkProposedApiEnabled(extensionDescription);
|
||||
return extensionMode;
|
||||
},
|
||||
get extensionMode() { return extensionMode; },
|
||||
get environmentVariableCollection() { return that._extHostTerminalService.getEnvironmentVariableCollection(extensionDescription); }
|
||||
});
|
||||
});
|
||||
@@ -426,15 +434,44 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
||||
|
||||
// -- eager activation
|
||||
|
||||
private _activateOneStartupFinished(desc: IExtensionDescription, activationEvent: string): void {
|
||||
this._activateById(desc.identifier, {
|
||||
startup: false,
|
||||
extensionId: desc.identifier,
|
||||
activationEvent: activationEvent
|
||||
}).then(undefined, (err) => {
|
||||
this._logService.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
private _activateAllStartupFinished(): void {
|
||||
for (const desc of this._registry.getAllExtensionDescriptions()) {
|
||||
if (desc.activationEvents) {
|
||||
for (const activationEvent of desc.activationEvents) {
|
||||
if (activationEvent === 'onStartupFinished') {
|
||||
this._activateOneStartupFinished(desc, activationEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle "eager" activation extensions
|
||||
private _handleEagerExtensions(): Promise<void> {
|
||||
this._activateByEvent('*', true).then(undefined, (err) => {
|
||||
const starActivation = this._activateByEvent('*', true).then(undefined, (err) => {
|
||||
this._logService.error(err);
|
||||
});
|
||||
|
||||
this._disposables.add(this._extHostWorkspace.onDidChangeWorkspace((e) => this._handleWorkspaceContainsEagerExtensions(e.added)));
|
||||
const folders = this._extHostWorkspace.workspace ? this._extHostWorkspace.workspace.folders : [];
|
||||
return this._handleWorkspaceContainsEagerExtensions(folders);
|
||||
const workspaceContainsActivation = this._handleWorkspaceContainsEagerExtensions(folders);
|
||||
const eagerExtensionsActivation = Promise.all([starActivation, workspaceContainsActivation]).then(() => { });
|
||||
|
||||
Promise.race([eagerExtensionsActivation, timeout(10000)]).then(() => {
|
||||
this._activateAllStartupFinished();
|
||||
});
|
||||
|
||||
return eagerExtensionsActivation;
|
||||
}
|
||||
|
||||
private _handleWorkspaceContainsEagerExtensions(folders: ReadonlyArray<vscode.WorkspaceFolder>): Promise<void> {
|
||||
@@ -764,6 +801,11 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
||||
return buff;
|
||||
}
|
||||
|
||||
public async $updateRemoteConnectionData(connectionData: IRemoteConnectionData): Promise<void> {
|
||||
this._remoteConnectionData = connectionData;
|
||||
this._onDidChangeRemoteConnectionData.fire();
|
||||
}
|
||||
|
||||
public abstract async $setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -798,7 +840,7 @@ function getTelemetryActivationEvent(extensionDescription: IExtensionDescription
|
||||
export const IExtHostExtensionService = createDecorator<IExtHostExtensionService>('IExtHostExtensionService');
|
||||
|
||||
export interface IExtHostExtensionService extends AbstractExtHostExtensionService {
|
||||
_serviceBrand: undefined;
|
||||
readonly _serviceBrand: undefined;
|
||||
initialize(): Promise<void>;
|
||||
isActivated(extensionId: ExtensionIdentifier): boolean;
|
||||
activateByIdWithErrors(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void>;
|
||||
@@ -807,4 +849,7 @@ export interface IExtHostExtensionService extends AbstractExtHostExtensionServic
|
||||
getExtensionRegistry(): Promise<ExtensionDescriptionRegistry>;
|
||||
getExtensionPathIndex(): Promise<TernarySearchTree<string, IExtensionDescription>>;
|
||||
registerRemoteAuthorityResolver(authorityPrefix: string, resolver: vscode.RemoteAuthorityResolver): vscode.Disposable;
|
||||
|
||||
onDidChangeRemoteConnectionData: Event<void>;
|
||||
getRemoteConnectionData(): IRemoteConnectionData | null;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
||||
export const IExtHostInitDataService = createDecorator<IExtHostInitDataService>('IExtHostInitDataService');
|
||||
|
||||
export interface IExtHostInitDataService extends Readonly<IInitData> {
|
||||
_serviceBrand: undefined;
|
||||
readonly _serviceBrand: undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,13 +13,19 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
|
||||
import { CellKind, ExtHostNotebookShape, IMainContext, MainContext, MainThreadNotebookShape, NotebookCellOutputsSplice, MainThreadDocumentsShape, INotebookEditorPropertiesChangeData, INotebookDocumentsAndEditorsDelta } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { CellEditType, CellUri, diff, ICellEditOperation, ICellInsertEdit, INotebookDisplayOrder, INotebookEditData, NotebookCellsChangedEvent, NotebookCellsSplice2, ICellDeleteEdit, notebookDocumentMetadataDefaults, NotebookCellsChangeType, NotebookDataDto, IOutputRenderRequest, IOutputRenderResponse, IOutputRenderResponseOutputInfo, IOutputRenderResponseCellInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellEditType, CellUri, diff, ICellEditOperation, ICellInsertEdit, INotebookDisplayOrder, INotebookEditData, NotebookCellsChangedEvent, NotebookCellsSplice2, ICellDeleteEdit, notebookDocumentMetadataDefaults, NotebookCellsChangeType, NotebookDataDto, IOutputRenderRequest, IOutputRenderResponse, IOutputRenderResponseOutputInfo, IOutputRenderResponseCellInfo, IRawOutput, CellOutputKind, IProcessedOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtHostDocumentData } from 'vs/workbench/api/common/extHostDocumentData';
|
||||
import { NotImplementedProxy } from 'vs/base/common/types';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
|
||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { Cache } from './cache';
|
||||
|
||||
interface IObservable<T> {
|
||||
proxy: T;
|
||||
@@ -48,15 +54,18 @@ interface INotebookEventEmitter {
|
||||
emitCellLanguageChange(event: vscode.NotebookCellLanguageChangeEvent): void;
|
||||
}
|
||||
|
||||
const addIdToOutput = (output: IRawOutput, id = generateUuid()): IProcessedOutput => output.outputKind === CellOutputKind.Rich
|
||||
? ({ ...output, outputId: id }) : output;
|
||||
|
||||
export class ExtHostCell extends Disposable implements vscode.NotebookCell {
|
||||
|
||||
// private originalSource: string[];
|
||||
private _outputs: any[];
|
||||
private _onDidChangeOutputs = new Emitter<ISplice<vscode.CellOutput>[]>();
|
||||
onDidChangeOutputs: Event<ISplice<vscode.CellOutput>[]> = this._onDidChangeOutputs.event;
|
||||
private _onDidChangeOutputs = new Emitter<ISplice<IProcessedOutput>[]>();
|
||||
onDidChangeOutputs: Event<ISplice<IProcessedOutput>[]> = this._onDidChangeOutputs.event;
|
||||
// private _textDocument: vscode.TextDocument | undefined;
|
||||
// private _initalVersion: number = -1;
|
||||
private _outputMapping = new Set<vscode.CellOutput>();
|
||||
private _outputMapping = new WeakMap<vscode.CellOutput, string | undefined /* output ID */>();
|
||||
private _metadata: vscode.NotebookCellMetadata;
|
||||
|
||||
private _metadataChangeListener: IDisposable;
|
||||
@@ -71,11 +80,6 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
|
||||
return this._notebook;
|
||||
}
|
||||
|
||||
get source() {
|
||||
// todo@jrieken remove this
|
||||
return this._documentData.getText();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly _notebook: ExtHostNotebookDocument,
|
||||
readonly handle: number,
|
||||
@@ -96,6 +100,10 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
|
||||
);
|
||||
|
||||
this._outputs = outputs;
|
||||
for (const output of this._outputs) {
|
||||
this._outputMapping.set(output, output.outputId);
|
||||
delete output.outputId;
|
||||
}
|
||||
|
||||
const observableMetadata = getObservable(_metadata || {});
|
||||
this._metadata = observableMetadata.proxy;
|
||||
@@ -109,22 +117,33 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
|
||||
}
|
||||
|
||||
set outputs(newOutputs: vscode.CellOutput[]) {
|
||||
let diffs = diff<vscode.CellOutput>(this._outputs || [], newOutputs || [], (a) => {
|
||||
let rawDiffs = diff<vscode.CellOutput>(this._outputs || [], newOutputs || [], (a) => {
|
||||
return this._outputMapping.has(a);
|
||||
});
|
||||
|
||||
diffs.forEach(diff => {
|
||||
const transformedDiffs: ISplice<IProcessedOutput>[] = rawDiffs.map(diff => {
|
||||
for (let i = diff.start; i < diff.start + diff.deleteCount; i++) {
|
||||
this._outputMapping.delete(this._outputs[i]);
|
||||
}
|
||||
|
||||
diff.toInsert.forEach(output => {
|
||||
this._outputMapping.add(output);
|
||||
});
|
||||
return {
|
||||
deleteCount: diff.deleteCount,
|
||||
start: diff.start,
|
||||
toInsert: diff.toInsert.map((output): IProcessedOutput => {
|
||||
if (output.outputKind === CellOutputKind.Rich) {
|
||||
const uuid = generateUuid();
|
||||
this._outputMapping.set(output, uuid);
|
||||
return { ...output, outputId: uuid };
|
||||
}
|
||||
|
||||
this._outputMapping.set(output, undefined);
|
||||
return output;
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
this._outputs = newOutputs;
|
||||
this._onDidChangeOutputs.fire(diffs);
|
||||
this._onDidChangeOutputs.fire(transformedDiffs);
|
||||
}
|
||||
|
||||
get metadata() {
|
||||
@@ -228,6 +247,47 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
|
||||
return this._versionId;
|
||||
}
|
||||
|
||||
private _backupCounter = 1;
|
||||
|
||||
private _backup?: vscode.NotebookDocumentBackup;
|
||||
|
||||
|
||||
private readonly _edits = new Cache<vscode.NotebookDocumentEditEvent>('notebook documents');
|
||||
|
||||
|
||||
addEdit(item: vscode.NotebookDocumentEditEvent): number {
|
||||
return this._edits.add([item]);
|
||||
}
|
||||
|
||||
async undo(editId: number, isDirty: boolean): Promise<void> {
|
||||
await this.getEdit(editId).undo();
|
||||
// if (!isDirty) {
|
||||
// this.disposeBackup();
|
||||
// }
|
||||
}
|
||||
|
||||
async redo(editId: number, isDirty: boolean): Promise<void> {
|
||||
await this.getEdit(editId).redo();
|
||||
// if (!isDirty) {
|
||||
// this.disposeBackup();
|
||||
// }
|
||||
}
|
||||
|
||||
private getEdit(editId: number): vscode.NotebookDocumentEditEvent {
|
||||
const edit = this._edits.get(editId, 0);
|
||||
if (!edit) {
|
||||
throw new Error('No edit found');
|
||||
}
|
||||
|
||||
return edit;
|
||||
}
|
||||
|
||||
disposeEdits(editIds: number[]): void {
|
||||
for (const id of editIds) {
|
||||
this._edits.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
private _disposed = false;
|
||||
|
||||
constructor(
|
||||
@@ -236,7 +296,8 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
|
||||
private _emitter: INotebookEventEmitter,
|
||||
public viewType: string,
|
||||
public uri: URI,
|
||||
public renderingHandler: ExtHostNotebookOutputRenderingHandler
|
||||
public renderingHandler: ExtHostNotebookOutputRenderingHandler,
|
||||
private readonly _storagePath: URI | undefined
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -251,6 +312,24 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
|
||||
this._proxy.$updateNotebookMetadata(this.viewType, this.uri, this._metadata);
|
||||
}
|
||||
|
||||
getNewBackupUri(): URI {
|
||||
if (!this._storagePath) {
|
||||
throw new Error('Backup requires a valid storage path');
|
||||
}
|
||||
const fileName = hashPath(this.uri) + (this._backupCounter++);
|
||||
return joinPath(this._storagePath, fileName);
|
||||
}
|
||||
|
||||
updateBackup(backup: vscode.NotebookDocumentBackup): void {
|
||||
this._backup?.delete();
|
||||
this._backup = backup;
|
||||
}
|
||||
|
||||
disposeBackup(): void {
|
||||
this._backup?.delete();
|
||||
this._backup = undefined;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._disposed = true;
|
||||
super.dispose();
|
||||
@@ -263,8 +342,10 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
|
||||
|
||||
accpetModelChanged(event: NotebookCellsChangedEvent): void {
|
||||
this._versionId = event.versionId;
|
||||
if (event.kind === NotebookCellsChangeType.ModelChange) {
|
||||
this.$spliceNotebookCells(event.changes);
|
||||
if (event.kind === NotebookCellsChangeType.Initialize) {
|
||||
this.$spliceNotebookCells(event.changes, true);
|
||||
} if (event.kind === NotebookCellsChangeType.ModelChange) {
|
||||
this.$spliceNotebookCells(event.changes, false);
|
||||
} else if (event.kind === NotebookCellsChangeType.Move) {
|
||||
this.$moveCell(event.index, event.newIdx);
|
||||
} else if (event.kind === NotebookCellsChangeType.CellClearOutput) {
|
||||
@@ -276,7 +357,7 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
|
||||
}
|
||||
}
|
||||
|
||||
private $spliceNotebookCells(splices: NotebookCellsSplice2[]): void {
|
||||
private $spliceNotebookCells(splices: NotebookCellsSplice2[], initialization: boolean): void {
|
||||
if (this._disposed) {
|
||||
return;
|
||||
}
|
||||
@@ -312,21 +393,24 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
|
||||
|
||||
}
|
||||
|
||||
this.cells.splice(splice[0], splice[1], ...newCells);
|
||||
const deletedItems = this.cells.splice(splice[0], splice[1], ...newCells);
|
||||
|
||||
const event: vscode.NotebookCellsChangeData = {
|
||||
start: splice[0],
|
||||
deletedCount: splice[1],
|
||||
deletedItems,
|
||||
items: newCells
|
||||
};
|
||||
|
||||
contentChangeEvents.push(event);
|
||||
});
|
||||
|
||||
this._emitter.emitModelChange({
|
||||
document: this,
|
||||
changes: contentChangeEvents
|
||||
});
|
||||
if (!initialization) {
|
||||
this._emitter.emitModelChange({
|
||||
document: this,
|
||||
changes: contentChangeEvents
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private $moveCell(index: number, newIdx: number): void {
|
||||
@@ -335,10 +419,12 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
|
||||
const changes: vscode.NotebookCellsChangeData[] = [{
|
||||
start: index,
|
||||
deletedCount: 1,
|
||||
deletedItems: cells,
|
||||
items: []
|
||||
}, {
|
||||
start: newIdx,
|
||||
deletedCount: 0,
|
||||
deletedItems: [],
|
||||
items: cells
|
||||
}];
|
||||
this._emitter.emitModelChange({
|
||||
@@ -373,7 +459,7 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
|
||||
this._emitter.emitCellLanguageChange(event);
|
||||
}
|
||||
|
||||
async eventuallyUpdateCellOutputs(cell: ExtHostCell, diffs: ISplice<vscode.CellOutput>[]) {
|
||||
async eventuallyUpdateCellOutputs(cell: ExtHostCell, diffs: ISplice<IProcessedOutput>[]) {
|
||||
let renderers = new Set<number>();
|
||||
let outputDtos: NotebookCellOutputsSplice[] = diffs.map(diff => {
|
||||
let outputs = diff.toInsert;
|
||||
@@ -445,8 +531,8 @@ export class NotebookEditorCellEditBuilder implements vscode.NotebookEditorCellE
|
||||
source: sourceArr,
|
||||
language,
|
||||
cellKind: type,
|
||||
outputs: outputs,
|
||||
metadata
|
||||
outputs: outputs.map(o => addIdToOutput(o)),
|
||||
metadata,
|
||||
};
|
||||
|
||||
this._collectedEdits.push({
|
||||
@@ -467,6 +553,30 @@ export class NotebookEditorCellEditBuilder implements vscode.NotebookEditorCellE
|
||||
}
|
||||
}
|
||||
|
||||
class ExtHostWebviewComm extends Disposable {
|
||||
|
||||
onDidReceiveMessage: vscode.Event<any> = this._onDidReceiveMessage.event;
|
||||
|
||||
constructor(
|
||||
readonly id: string,
|
||||
public uri: URI,
|
||||
private _proxy: MainThreadNotebookShape,
|
||||
private _onDidReceiveMessage: Emitter<any>,
|
||||
private _webviewInitData: WebviewInitData,
|
||||
public document: ExtHostNotebookDocument,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async postMessage(message: any): Promise<boolean> {
|
||||
return this._proxy.$postMessage(this.document.handle, message);
|
||||
}
|
||||
|
||||
asWebviewUri(localResource: vscode.Uri): vscode.Uri {
|
||||
return asWebviewUri(this._webviewInitData, this.id, localResource);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostNotebookEditor extends Disposable implements vscode.NotebookEditor {
|
||||
private _viewColumn: vscode.ViewColumn | undefined;
|
||||
|
||||
@@ -500,6 +610,7 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
|
||||
|
||||
private _onDidDispose = new Emitter<void>();
|
||||
readonly onDidDispose: Event<void> = this._onDidDispose.event;
|
||||
private _onDidReceiveMessage = new Emitter<any>();
|
||||
onDidReceiveMessage: vscode.Event<any> = this._onDidReceiveMessage.event;
|
||||
|
||||
constructor(
|
||||
@@ -507,8 +618,7 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
|
||||
readonly id: string,
|
||||
public uri: URI,
|
||||
private _proxy: MainThreadNotebookShape,
|
||||
private _onDidReceiveMessage: Emitter<any>,
|
||||
private _webviewInitData: WebviewInitData,
|
||||
private _webComm: ExtHostWebviewComm,
|
||||
public document: ExtHostNotebookDocument,
|
||||
private _documentsAndEditors: ExtHostDocumentsAndEditors
|
||||
) {
|
||||
@@ -517,7 +627,7 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
|
||||
for (const documentData of documents) {
|
||||
let data = CellUri.parse(documentData.document.uri);
|
||||
if (data) {
|
||||
if (this.document.uri.toString() === data.notebook.toString()) {
|
||||
if (this.document.uri.fsPath === data.notebook.fsPath) {
|
||||
document.attachCellTextDocument(documentData);
|
||||
}
|
||||
}
|
||||
@@ -528,12 +638,16 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
|
||||
for (const documentData of documents) {
|
||||
let data = CellUri.parse(documentData.document.uri);
|
||||
if (data) {
|
||||
if (this.document.uri.toString() === data.notebook.toString()) {
|
||||
if (this.document.uri.fsPath === data.notebook.fsPath) {
|
||||
document.detachCellTextDocument(documentData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this._webComm.onDidReceiveMessage(e => {
|
||||
this._onDidReceiveMessage.fire(e);
|
||||
}));
|
||||
}
|
||||
|
||||
edit(callback: (editBuilder: NotebookEditorCellEditBuilder) => void): Thenable<boolean> {
|
||||
@@ -593,11 +707,11 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
|
||||
}
|
||||
|
||||
async postMessage(message: any): Promise<boolean> {
|
||||
return this._proxy.$postMessage(this.document.handle, message);
|
||||
return this._webComm.postMessage(message);
|
||||
}
|
||||
|
||||
asWebviewUri(localResource: vscode.Uri): vscode.Uri {
|
||||
return asWebviewUri(this._webviewInitData, this.id, localResource);
|
||||
return this._webComm.asWebviewUri(localResource);
|
||||
}
|
||||
dispose() {
|
||||
this._onDidDispose.fire();
|
||||
@@ -618,16 +732,16 @@ export class ExtHostNotebookOutputRenderer {
|
||||
}
|
||||
|
||||
matches(mimeType: string): boolean {
|
||||
if (this.filter.subTypes) {
|
||||
if (this.filter.subTypes.indexOf(mimeType) >= 0) {
|
||||
if (this.filter.mimeTypes) {
|
||||
if (this.filter.mimeTypes.indexOf(mimeType) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
render(document: ExtHostNotebookDocument, output: vscode.CellDisplayOutput, mimeType: string): string {
|
||||
let html = this.renderer.render(document, output, mimeType);
|
||||
render(document: ExtHostNotebookDocument, output: vscode.CellDisplayOutput, outputId: string, mimeType: string): string {
|
||||
let html = this.renderer.render(document, { output, outputId, mimeType });
|
||||
|
||||
return html;
|
||||
}
|
||||
@@ -644,7 +758,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
private readonly _notebookKernels = new Map<string, { readonly kernel: vscode.NotebookKernel, readonly extension: IExtensionDescription; }>();
|
||||
private readonly _documents = new Map<string, ExtHostNotebookDocument>();
|
||||
private readonly _unInitializedDocuments = new Map<string, ExtHostNotebookDocument>();
|
||||
private readonly _editors = new Map<string, { editor: ExtHostNotebookEditor, onDidReceiveMessage: Emitter<any>; }>();
|
||||
private readonly _editors = new Map<string, { editor: ExtHostNotebookEditor }>();
|
||||
private readonly _webviewComm = new Map<string, { comm: ExtHostWebviewComm, onDidReceiveMessage: Emitter<any> }>();
|
||||
private readonly _notebookOutputRenderers = new Map<string, ExtHostNotebookOutputRenderer>();
|
||||
private readonly _onDidChangeNotebookCells = new Emitter<vscode.NotebookCellsChangeEvent>();
|
||||
readonly onDidChangeNotebookCells = this._onDidChangeNotebookCells.event;
|
||||
@@ -661,18 +776,16 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
return this._outputDisplayOrder;
|
||||
}
|
||||
|
||||
private _activeNotebookDocument: ExtHostNotebookDocument | undefined;
|
||||
|
||||
get activeNotebookDocument() {
|
||||
return this._activeNotebookDocument;
|
||||
}
|
||||
|
||||
private _activeNotebookEditor: ExtHostNotebookEditor | undefined;
|
||||
|
||||
get activeNotebookEditor() {
|
||||
return this._activeNotebookEditor;
|
||||
}
|
||||
|
||||
get notebookDocuments() {
|
||||
return [...this._documents.values()];
|
||||
}
|
||||
|
||||
private _onDidOpenNotebookDocument = new Emitter<vscode.NotebookDocument>();
|
||||
onDidOpenNotebookDocument: Event<vscode.NotebookDocument> = this._onDidOpenNotebookDocument.event;
|
||||
private _onDidCloseNotebookDocument = new Emitter<vscode.NotebookDocument>();
|
||||
@@ -681,7 +794,13 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>();
|
||||
onDidChangeVisibleNotebookEditors = this._onDidChangeVisibleNotebookEditors.event;
|
||||
|
||||
constructor(mainContext: IMainContext, commands: ExtHostCommands, private _documentsAndEditors: ExtHostDocumentsAndEditors, private readonly _webviewInitData: WebviewInitData) {
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
commands: ExtHostCommands,
|
||||
private _documentsAndEditors: ExtHostDocumentsAndEditors,
|
||||
private readonly _webviewInitData: WebviewInitData,
|
||||
private readonly _extensionStoragePaths?: IExtensionStoragePaths,
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadNotebook);
|
||||
|
||||
commands.registerArgumentProcessor({
|
||||
@@ -736,13 +855,14 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
|
||||
const renderer = this._notebookOutputRenderers.get(id)!;
|
||||
const cellsResponse: IOutputRenderResponseCellInfo<UriComponents>[] = request.items.map(cellInfo => {
|
||||
const cell = document.getCell2(cellInfo.key);
|
||||
const cell = document.getCell2(cellInfo.key)!;
|
||||
const outputResponse: IOutputRenderResponseOutputInfo[] = cellInfo.outputs.map(output => {
|
||||
return {
|
||||
index: output.index,
|
||||
outputId: output.outputId,
|
||||
mimeType: output.mimeType,
|
||||
handlerId: id,
|
||||
transformedOutput: renderer.render(document, cell!.outputs[output.index] as vscode.CellDisplayOutput, output.mimeType)
|
||||
transformedOutput: renderer.render(document, cell.outputs[output.index] as vscode.CellDisplayOutput, output.outputId, output.mimeType)
|
||||
};
|
||||
});
|
||||
|
||||
@@ -774,9 +894,10 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
const outputResponse: IOutputRenderResponseOutputInfo[] = cellInfo.outputs.map(output => {
|
||||
return {
|
||||
index: output.index,
|
||||
outputId: output.outputId,
|
||||
mimeType: output.mimeType,
|
||||
handlerId: id,
|
||||
transformedOutput: renderer.render(document, output.output! as vscode.CellDisplayOutput, output.mimeType)
|
||||
transformedOutput: renderer.render(document, output.output! as vscode.CellDisplayOutput, output.outputId, output.mimeType)
|
||||
};
|
||||
});
|
||||
|
||||
@@ -817,10 +938,26 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
this._notebookContentProviders.set(viewType, { extension, provider });
|
||||
|
||||
const listener = provider.onDidChangeNotebook
|
||||
? provider.onDidChangeNotebook(e => this._proxy.$onNotebookChange(viewType, e.document.uri))
|
||||
? provider.onDidChangeNotebook(e => {
|
||||
const document = this._documents.get(URI.revive(e.document.uri).toString());
|
||||
|
||||
if (!document) {
|
||||
throw new Error(`Notebook document ${e.document.uri.toString()} not found`);
|
||||
}
|
||||
|
||||
if (isEditEvent(e)) {
|
||||
const editId = document.addEdit(e);
|
||||
this._proxy.$onDidEdit(e.document.uri, viewType, editId, e.label);
|
||||
} else {
|
||||
this._proxy.$onContentChange(e.document.uri, viewType);
|
||||
}
|
||||
})
|
||||
: Disposable.None;
|
||||
|
||||
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation }, viewType, provider.kernel ? { id: viewType, label: provider.kernel.label, extensionLocation: extension.extensionLocation, preloads: provider.kernel.preloads } : undefined);
|
||||
const supportBackup = !!provider.backupNotebook;
|
||||
|
||||
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation }, viewType, supportBackup, provider.kernel ? { id: viewType, label: provider.kernel.label, extensionLocation: extension.extensionLocation, preloads: provider.kernel.preloads } : undefined);
|
||||
|
||||
return new extHostTypes.Disposable(() => {
|
||||
listener.dispose();
|
||||
this._notebookContentProviders.delete(viewType);
|
||||
@@ -843,11 +980,16 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
});
|
||||
}
|
||||
|
||||
async $resolveNotebookData(viewType: string, uri: UriComponents): Promise<NotebookDataDto | undefined> {
|
||||
async $resolveNotebookData(viewType: string, uri: UriComponents, backupId?: string): Promise<NotebookDataDto | undefined> {
|
||||
const provider = this._notebookContentProviders.get(viewType);
|
||||
const revivedUri = URI.revive(uri);
|
||||
|
||||
if (provider) {
|
||||
let storageRoot: URI | undefined;
|
||||
if (this._extensionStoragePaths) {
|
||||
storageRoot = URI.file(this._extensionStoragePaths.workspaceValue(provider.extension) ?? this._extensionStoragePaths.globalValue(provider.extension));
|
||||
}
|
||||
|
||||
let document = this._documents.get(URI.revive(uri).toString());
|
||||
|
||||
if (!document) {
|
||||
@@ -862,18 +1004,21 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
emitCellLanguageChange(event: vscode.NotebookCellLanguageChangeEvent): void {
|
||||
that._onDidChangeCellLanguage.fire(event);
|
||||
}
|
||||
}, viewType, revivedUri, this);
|
||||
}, viewType, revivedUri, this, storageRoot);
|
||||
this._unInitializedDocuments.set(revivedUri.toString(), document);
|
||||
}
|
||||
|
||||
const rawCells = await provider.provider.openNotebook(URI.revive(uri));
|
||||
const rawCells = await provider.provider.openNotebook(URI.revive(uri), { backupId });
|
||||
const dto = {
|
||||
metadata: {
|
||||
...notebookDocumentMetadataDefaults,
|
||||
...rawCells.metadata
|
||||
},
|
||||
languages: rawCells.languages,
|
||||
cells: rawCells.cells,
|
||||
cells: rawCells.cells.map(cell => ({
|
||||
...cell,
|
||||
outputs: cell.outputs.map(o => addIdToOutput(o))
|
||||
})),
|
||||
};
|
||||
|
||||
return dto;
|
||||
@@ -882,6 +1027,30 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
return undefined; // {{SQL CARBON EDIT}}
|
||||
}
|
||||
|
||||
async $resolveNotebookEditor(viewType: string, uri: UriComponents, editorId: string): Promise<void> {
|
||||
const provider = this._notebookContentProviders.get(viewType);
|
||||
const revivedUri = URI.revive(uri);
|
||||
const document = this._documents.get(revivedUri.toString());
|
||||
if (!document || !provider) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!provider.provider.resolveNotebook) {
|
||||
return;
|
||||
}
|
||||
|
||||
let webComm = this._webviewComm.get(editorId)?.comm;
|
||||
|
||||
if (webComm) {
|
||||
await provider.provider.resolveNotebook(document, webComm);
|
||||
} else {
|
||||
const onDidReceiveMessage = new Emitter<any>();
|
||||
webComm = new ExtHostWebviewComm(editorId, revivedUri, this._proxy, onDidReceiveMessage, this._webviewInitData, document);
|
||||
this._webviewComm.set(editorId, { comm: webComm, onDidReceiveMessage });
|
||||
await provider.provider.resolveNotebook(document, webComm);
|
||||
}
|
||||
}
|
||||
|
||||
async $executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, useAttachedKernel: boolean, token: CancellationToken): Promise<void> {
|
||||
let document = this._documents.get(URI.revive(uri).toString());
|
||||
|
||||
@@ -963,6 +1132,39 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
return false;
|
||||
}
|
||||
|
||||
async $undoNotebook(viewType: string, uri: UriComponents, editId: number, isDirty: boolean): Promise<void> {
|
||||
const document = this._documents.get(URI.revive(uri).toString());
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.undo(editId, isDirty);
|
||||
|
||||
}
|
||||
|
||||
async $redoNotebook(viewType: string, uri: UriComponents, editId: number, isDirty: boolean): Promise<void> {
|
||||
const document = this._documents.get(URI.revive(uri).toString());
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.redo(editId, isDirty);
|
||||
}
|
||||
|
||||
|
||||
async $backup(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string | undefined> {
|
||||
const document = this._documents.get(URI.revive(uri).toString());
|
||||
const provider = this._notebookContentProviders.get(viewType);
|
||||
|
||||
if (document && provider && provider.provider.backupNotebook) {
|
||||
const backup = await provider.provider.backupNotebook(document, { destination: document.getNewBackupUri() }, cancellation);
|
||||
document.updateBackup(backup);
|
||||
return backup.id;
|
||||
}
|
||||
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-checks
|
||||
}
|
||||
|
||||
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void {
|
||||
this._outputDisplayOrder = displayOrder;
|
||||
}
|
||||
@@ -970,7 +1172,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
// TODO: remove document - editor one on one mapping
|
||||
private _getEditorFromURI(uriComponents: UriComponents) {
|
||||
const uriStr = URI.revive(uriComponents).toString();
|
||||
let editor: { editor: ExtHostNotebookEditor, onDidReceiveMessage: Emitter<any>; } | undefined;
|
||||
let editor: { editor: ExtHostNotebookEditor } | undefined;
|
||||
this._editors.forEach(e => {
|
||||
if (e.editor.uri.toString() === uriStr) {
|
||||
editor = e;
|
||||
@@ -981,10 +1183,10 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
}
|
||||
|
||||
$onDidReceiveMessage(editorId: string, message: any): void {
|
||||
let editor = this._editors.get(editorId);
|
||||
let messageEmitter = this._webviewComm.get(editorId)?.onDidReceiveMessage;
|
||||
|
||||
if (editor) {
|
||||
editor.onDidReceiveMessage.fire(message);
|
||||
if (messageEmitter) {
|
||||
messageEmitter.fire(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1023,16 +1225,21 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
}
|
||||
|
||||
private _createExtHostEditor(document: ExtHostNotebookDocument, editorId: string, selections: number[]) {
|
||||
const onDidReceiveMessage = new Emitter<any>();
|
||||
const revivedUri = document.uri;
|
||||
let webComm = this._webviewComm.get(editorId)?.comm;
|
||||
|
||||
if (!webComm) {
|
||||
const onDidReceiveMessage = new Emitter<any>();
|
||||
webComm = new ExtHostWebviewComm(editorId, revivedUri, this._proxy, onDidReceiveMessage, this._webviewInitData, document);
|
||||
this._webviewComm.set(editorId, { comm: webComm!, onDidReceiveMessage });
|
||||
}
|
||||
|
||||
let editor = new ExtHostNotebookEditor(
|
||||
document.viewType,
|
||||
editorId,
|
||||
revivedUri,
|
||||
this._proxy,
|
||||
onDidReceiveMessage,
|
||||
this._webviewInitData,
|
||||
webComm,
|
||||
document,
|
||||
this._documentsAndEditors
|
||||
);
|
||||
@@ -1048,7 +1255,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
|
||||
this._editors.get(editorId)?.editor.dispose();
|
||||
|
||||
this._editors.set(editorId, { editor, onDidReceiveMessage });
|
||||
this._editors.set(editorId, { editor });
|
||||
}
|
||||
|
||||
async $acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta) {
|
||||
@@ -1069,7 +1276,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
[...this._editors.values()].forEach((e) => {
|
||||
if (e.editor.uri.toString() === revivedUriStr) {
|
||||
e.editor.dispose();
|
||||
e.onDidReceiveMessage.dispose();
|
||||
this._editors.delete(e.editor.id);
|
||||
editorChanged = true;
|
||||
}
|
||||
@@ -1082,8 +1288,15 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
const revivedUri = URI.revive(modelData.uri);
|
||||
const revivedUriStr = revivedUri.toString();
|
||||
const viewType = modelData.viewType;
|
||||
const entry = this._notebookContentProviders.get(viewType);
|
||||
let storageRoot: URI | undefined;
|
||||
if (entry && this._extensionStoragePaths) {
|
||||
storageRoot = URI.file(this._extensionStoragePaths.workspaceValue(entry.extension) ?? this._extensionStoragePaths.globalValue(entry.extension));
|
||||
}
|
||||
|
||||
if (!this._documents.has(revivedUriStr)) {
|
||||
const that = this;
|
||||
|
||||
let document = this._unInitializedDocuments.get(revivedUriStr) ?? new ExtHostNotebookDocument(this._proxy, this._documentsAndEditors, {
|
||||
emitModelChange(event: vscode.NotebookCellsChangeEvent): void {
|
||||
that._onDidChangeNotebookCells.fire(event);
|
||||
@@ -1094,7 +1307,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
emitCellLanguageChange(event: vscode.NotebookCellLanguageChangeEvent): void {
|
||||
that._onDidChangeCellLanguage.fire(event);
|
||||
}
|
||||
}, viewType, revivedUri, this);
|
||||
}, viewType, revivedUri, this, storageRoot);
|
||||
|
||||
this._unInitializedDocuments.delete(revivedUriStr);
|
||||
if (modelData.metadata) {
|
||||
@@ -1105,7 +1318,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
}
|
||||
|
||||
document.accpetModelChanged({
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
kind: NotebookCellsChangeType.Initialize,
|
||||
versionId: modelData.versionId,
|
||||
changes: [[
|
||||
0,
|
||||
@@ -1145,7 +1358,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
});
|
||||
}
|
||||
|
||||
const removedEditors: { editor: ExtHostNotebookEditor, onDidReceiveMessage: Emitter<any>; }[] = [];
|
||||
const removedEditors: { editor: ExtHostNotebookEditor }[] = [];
|
||||
|
||||
if (delta.removedEditors) {
|
||||
delta.removedEditors.forEach(editorid => {
|
||||
@@ -1157,7 +1370,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
|
||||
if (this.activeNotebookEditor?.id === editor.editor.id) {
|
||||
this._activeNotebookEditor = undefined;
|
||||
this._activeNotebookDocument = undefined;
|
||||
}
|
||||
|
||||
removedEditors.push(editor);
|
||||
@@ -1168,12 +1380,11 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
if (editorChanged) {
|
||||
removedEditors.forEach(e => {
|
||||
e.editor.dispose();
|
||||
e.onDidReceiveMessage.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
if (delta.visibleEditors) {
|
||||
this.visibleNotebookEditors = delta.visibleEditors.map(id => this._editors.get(id)?.editor).filter(editor => !!editor) as ExtHostNotebookEditor[];
|
||||
this.visibleNotebookEditors = delta.visibleEditors.map(id => this._editors.get(id)!.editor).filter(editor => !!editor) as ExtHostNotebookEditor[];
|
||||
const visibleEditorsSet = new Set<string>();
|
||||
this.visibleNotebookEditors.forEach(editor => visibleEditorsSet.add(editor.id));
|
||||
|
||||
@@ -1190,19 +1401,32 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
if (delta.newActiveEditor) {
|
||||
this._activeNotebookEditor = this._editors.get(delta.newActiveEditor)?.editor;
|
||||
this._activeNotebookEditor?._acceptActive(true);
|
||||
this._activeNotebookDocument = this._activeNotebookEditor ? this._documents.get(this._activeNotebookEditor!.uri.toString()) : undefined;
|
||||
[...this._editors.values()].forEach((e) => {
|
||||
if (e.editor !== this.activeNotebookEditor) {
|
||||
e.editor._acceptActive(false);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// clear active notebook as current active editor is non-notebook editor
|
||||
this._activeNotebookEditor = undefined;
|
||||
this._activeNotebookDocument = undefined;
|
||||
|
||||
[...this._editors.values()].forEach((e) => {
|
||||
e.editor._acceptActive(false);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
this._onDidChangeActiveNotebookEditor.fire(this._activeNotebookEditor);
|
||||
}
|
||||
|
||||
[...this._editors.values()].forEach((e) => {
|
||||
if (e.editor !== this.activeNotebookEditor) {
|
||||
e.editor._acceptActive(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function hashPath(resource: URI): string {
|
||||
const str = resource.scheme === Schemas.file || resource.scheme === Schemas.untitled ? resource.fsPath : resource.toString();
|
||||
return hash(str) + '';
|
||||
}
|
||||
|
||||
function isEditEvent(e: vscode.NotebookDocumentEditEvent | vscode.NotebookDocumentContentChangeEvent): e is vscode.NotebookDocumentEditEvent {
|
||||
return typeof (e as vscode.NotebookDocumentEditEvent).undo === 'function'
|
||||
&& typeof (e as vscode.NotebookDocumentEditEvent).redo === 'function';
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
||||
export const IExtHostRpcService = createDecorator<IExtHostRpcService>('IExtHostRpcService');
|
||||
|
||||
export interface IExtHostRpcService extends IRPCProtocol {
|
||||
_serviceBrand: undefined;
|
||||
readonly _serviceBrand: undefined;
|
||||
}
|
||||
|
||||
export class ExtHostRpcService implements IExtHostRpcService {
|
||||
|
||||
@@ -9,7 +9,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
||||
export const IExtensionStoragePaths = createDecorator<IExtensionStoragePaths>('IExtensionStoragePaths');
|
||||
|
||||
export interface IExtensionStoragePaths {
|
||||
_serviceBrand: undefined;
|
||||
readonly _serviceBrand: undefined;
|
||||
whenReady: Promise<any>;
|
||||
workspaceValue(extension: IExtensionDescription): string | undefined;
|
||||
globalValue(extension: IExtensionDescription): string;
|
||||
|
||||
@@ -512,12 +512,10 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape {
|
||||
|
||||
public async $onDidStartTaskProcess(value: tasks.TaskProcessStartedDTO): Promise<void> {
|
||||
const execution = await this.getTaskExecution(value.id);
|
||||
if (execution) {
|
||||
this._onDidTaskProcessStarted.fire({
|
||||
execution: execution,
|
||||
processId: value.processId
|
||||
});
|
||||
}
|
||||
this._onDidTaskProcessStarted.fire({
|
||||
execution: execution,
|
||||
processId: value.processId
|
||||
});
|
||||
}
|
||||
|
||||
public get onDidEndTaskProcess(): Event<vscode.TaskProcessEndEvent> {
|
||||
@@ -526,12 +524,10 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape {
|
||||
|
||||
public async $onDidEndTaskProcess(value: tasks.TaskProcessEndedDTO): Promise<void> {
|
||||
const execution = await this.getTaskExecution(value.id);
|
||||
if (execution) {
|
||||
this._onDidTaskProcessEnded.fire({
|
||||
execution: execution,
|
||||
exitCode: value.exitCode
|
||||
});
|
||||
}
|
||||
this._onDidTaskProcessEnded.fire({
|
||||
execution: execution,
|
||||
exitCode: value.exitCode
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract provideTasksInternal(validTypes: { [key: string]: boolean; }, taskIdPromises: Promise<void>[], handler: HandlerData, value: vscode.Task[] | null | undefined): { tasks: tasks.TaskDTO[], extension: IExtensionDescription };
|
||||
@@ -622,7 +618,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape {
|
||||
|
||||
protected async getTaskExecution(execution: tasks.TaskExecutionDTO | string, task?: vscode.Task): Promise<TaskExecutionImpl> {
|
||||
if (typeof execution === 'string') {
|
||||
const taskExecution = this._taskExecutions.get(execution);
|
||||
const taskExecution = this._taskExecutionPromises.get(execution);
|
||||
if (!taskExecution) {
|
||||
throw new Error('Unexpected: The specified task is missing an execution');
|
||||
}
|
||||
@@ -643,9 +639,11 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape {
|
||||
});
|
||||
|
||||
this._taskExecutionPromises.set(execution.id, createdResult);
|
||||
return createdResult.then(result => {
|
||||
this._taskExecutions.set(execution.id, result);
|
||||
return result;
|
||||
return createdResult.then(executionCreatedResult => {
|
||||
this._taskExecutions.set(execution.id, executionCreatedResult);
|
||||
return executionCreatedResult;
|
||||
}, rejected => {
|
||||
return Promise.reject(rejected);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -708,7 +706,7 @@ export class WorkerExtHostTask extends ExtHostTaskBase {
|
||||
public async executeTask(extension: IExtensionDescription, task: vscode.Task): Promise<vscode.TaskExecution> {
|
||||
const dto = TaskDTO.from(task, extension);
|
||||
if (dto === undefined) {
|
||||
return Promise.reject(new Error('Task is not valid'));
|
||||
throw new Error('Task is not valid');
|
||||
}
|
||||
|
||||
// If this task is a custom execution, then we need to save it away
|
||||
@@ -720,7 +718,10 @@ export class WorkerExtHostTask extends ExtHostTaskBase {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
return this._proxy.$executeTask(dto).then(value => this.getTaskExecution(value, task));
|
||||
// Always get the task execution first to prevent timing issues when retrieving it later
|
||||
const execution = await this.getTaskExecution(await this._proxy.$getTaskExecution(dto), task);
|
||||
this._proxy.$executeTask(dto).catch(error => { throw new Error(error); });
|
||||
return execution;
|
||||
}
|
||||
|
||||
protected provideTasksInternal(validTypes: { [key: string]: boolean; }, taskIdPromises: Promise<void>[], handler: HandlerData, value: vscode.Task[] | null | undefined): { tasks: tasks.TaskDTO[], extension: IExtensionDescription } {
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShap
|
||||
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ITerminalChildProcess, ITerminalDimensions, EXT_HOST_CREATION_DELAY } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ITerminalChildProcess, ITerminalDimensions, EXT_HOST_CREATION_DELAY, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
|
||||
@@ -17,10 +17,11 @@ import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType } from './extHostTypes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
export interface IExtHostTerminalService extends ExtHostTerminalServiceShape {
|
||||
|
||||
_serviceBrand: undefined;
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
activeTerminal: vscode.Terminal | undefined;
|
||||
terminals: vscode.Terminal[];
|
||||
@@ -243,6 +244,10 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
|
||||
|
||||
constructor(private readonly _pty: vscode.Pseudoterminal) { }
|
||||
|
||||
async start(): Promise<undefined> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
shutdown(): void {
|
||||
this._pty.close();
|
||||
}
|
||||
@@ -332,7 +337,7 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
|
||||
public abstract createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal;
|
||||
public abstract getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string;
|
||||
public abstract getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string;
|
||||
public abstract $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<void>;
|
||||
public abstract $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<ITerminalLaunchError | undefined>;
|
||||
public abstract $getAvailableShells(): Promise<IShellDefinitionDto[]>;
|
||||
public abstract $getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
|
||||
public abstract $acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
|
||||
@@ -454,20 +459,17 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
|
||||
}
|
||||
}
|
||||
|
||||
public async $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise<void> {
|
||||
public async $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise<ITerminalLaunchError | undefined> {
|
||||
// Make sure the ExtHostTerminal exists so onDidOpenTerminal has fired before we call
|
||||
// Pseudoterminal.start
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (!terminal) {
|
||||
return;
|
||||
return { message: localize('launchFail.idMissingOnExtHost', "Could not find the terminal with id {0} on the extension host", id) };
|
||||
}
|
||||
|
||||
// Wait for onDidOpenTerminal to fire
|
||||
let openPromise: Promise<void>;
|
||||
if (terminal.isOpen) {
|
||||
openPromise = Promise.resolve();
|
||||
} else {
|
||||
openPromise = new Promise<void>(r => {
|
||||
if (!terminal.isOpen) {
|
||||
await new Promise<void>(r => {
|
||||
// Ensure open is called after onDidOpenTerminal
|
||||
const listener = this.onDidOpenTerminal(async e => {
|
||||
if (e === terminal) {
|
||||
@@ -477,7 +479,6 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
|
||||
});
|
||||
});
|
||||
}
|
||||
await openPromise;
|
||||
|
||||
if (this._terminalProcesses[id]) {
|
||||
(this._terminalProcesses[id] as ExtHostPseudoterminal).startSendingEvents(initialDimensions);
|
||||
@@ -486,6 +487,7 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
|
||||
this._extensionTerminalAwaitingStart[id] = { initialDimensions };
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): IDisposable {
|
||||
@@ -721,7 +723,7 @@ export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<void> {
|
||||
public $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<ITerminalLaunchError | undefined> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
showTextDocument(document: vscode.TextDocument, column: vscode.ViewColumn, preserveFocus: boolean): Promise<vscode.TextEditor>;
|
||||
showTextDocument(document: vscode.TextDocument, options: { column: vscode.ViewColumn, preserveFocus: boolean, pinned: boolean }): Promise<vscode.TextEditor>;
|
||||
showTextDocument(document: vscode.TextDocument, columnOrOptions: vscode.ViewColumn | vscode.TextDocumentShowOptions | undefined, preserveFocus?: boolean): Promise<vscode.TextEditor>;
|
||||
showTextDocument(document: vscode.TextDocument, columnOrOptions: vscode.ViewColumn | vscode.TextDocumentShowOptions | undefined, preserveFocus?: boolean): Promise<vscode.TextEditor> {
|
||||
async showTextDocument(document: vscode.TextDocument, columnOrOptions: vscode.ViewColumn | vscode.TextDocumentShowOptions | undefined, preserveFocus?: boolean): Promise<vscode.TextEditor> {
|
||||
let options: ITextDocumentShowOptions;
|
||||
if (typeof columnOrOptions === 'number') {
|
||||
options = {
|
||||
@@ -74,14 +74,18 @@ export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
};
|
||||
}
|
||||
|
||||
return this._proxy.$tryShowTextDocument(document.uri, options).then(id => {
|
||||
const editor = id && this._extHostDocumentsAndEditors.getEditor(id);
|
||||
if (editor) {
|
||||
return editor;
|
||||
} else {
|
||||
throw new Error(`Failed to show text document ${document.uri.toString()}, should show in editor #${id}`);
|
||||
}
|
||||
});
|
||||
const editorId = await this._proxy.$tryShowTextDocument(document.uri, options);
|
||||
const editor = editorId && this._extHostDocumentsAndEditors.getEditor(editorId);
|
||||
if (editor) {
|
||||
return editor;
|
||||
}
|
||||
// we have no editor... having an id means that we had an editor
|
||||
// on the main side and that it isn't the current editor anymore...
|
||||
if (editorId) {
|
||||
throw new Error(`Could NOT open editor for "${document.uri.toString()}" because another editor opened in the meantime.`);
|
||||
} else {
|
||||
throw new Error(`Could NOT open editor for "${document.uri.toString()}".`);
|
||||
}
|
||||
}
|
||||
|
||||
createTextEditorDecorationType(options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType {
|
||||
|
||||
@@ -22,7 +22,7 @@ export interface IExtHostTimeline extends ExtHostTimelineShape {
|
||||
export const IExtHostTimeline = createDecorator<IExtHostTimeline>('IExtHostTimeline');
|
||||
|
||||
export class ExtHostTimeline implements IExtHostTimeline {
|
||||
_serviceBrand: undefined;
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private _proxy: MainThreadTimelineShape;
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ export interface IExtHostTunnelService extends ExtHostTunnelServiceShape {
|
||||
export const IExtHostTunnelService = createDecorator<IExtHostTunnelService>('IExtHostTunnelService');
|
||||
|
||||
export class ExtHostTunnelService implements IExtHostTunnelService {
|
||||
_serviceBrand: undefined;
|
||||
declare readonly _serviceBrand: undefined;
|
||||
onDidChangeTunnels: vscode.Event<void> = (new Emitter<void>()).event;
|
||||
private readonly _proxy: MainThreadTunnelServiceShape;
|
||||
|
||||
|
||||
@@ -1164,15 +1164,20 @@ export namespace FoldingRangeKind {
|
||||
}
|
||||
}
|
||||
|
||||
export namespace TextEditorOptions {
|
||||
export interface TextEditorOpenOptions extends vscode.TextDocumentShowOptions {
|
||||
background?: boolean;
|
||||
}
|
||||
|
||||
export function from(options?: vscode.TextDocumentShowOptions): ITextEditorOptions | undefined {
|
||||
export namespace TextEditorOpenOptions {
|
||||
|
||||
export function from(options?: TextEditorOpenOptions): ITextEditorOptions | undefined {
|
||||
if (options) {
|
||||
return {
|
||||
pinned: typeof options.preview === 'boolean' ? !options.preview : undefined,
|
||||
inactive: options.background,
|
||||
preserveFocus: options.preserveFocus,
|
||||
selection: typeof options.selection === 'object' ? Range.from(options.selection) : undefined
|
||||
} as ITextEditorOptions;
|
||||
selection: typeof options.selection === 'object' ? Range.from(options.selection) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
@@ -2750,7 +2750,7 @@ export enum ExtensionMode {
|
||||
* The extension is installed normally (for example, from the marketplace
|
||||
* or VSIX) in VS Code.
|
||||
*/
|
||||
Release = 1,
|
||||
Production = 1,
|
||||
|
||||
/**
|
||||
* The extension is running from an `--extensionDevelopmentPath` provided
|
||||
|
||||
@@ -8,13 +8,13 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
|
||||
export interface IURITransformerService extends IURITransformer {
|
||||
_serviceBrand: undefined;
|
||||
readonly _serviceBrand: undefined;
|
||||
}
|
||||
|
||||
export const IURITransformerService = createDecorator<IURITransformerService>('IURITransformerService');
|
||||
|
||||
export class URITransformerService implements IURITransformerService {
|
||||
_serviceBrand: undefined;
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
transformIncoming: (uri: UriComponents) => UriComponents;
|
||||
transformOutgoing: (uri: UriComponents) => UriComponents;
|
||||
|
||||
@@ -273,7 +273,7 @@ class CustomDocumentStoreEntry {
|
||||
|
||||
constructor(
|
||||
public readonly document: vscode.CustomDocument,
|
||||
private readonly _storagePath: string,
|
||||
private readonly _storagePath: URI | undefined,
|
||||
) { }
|
||||
|
||||
private readonly _edits = new Cache<vscode.CustomDocumentEditEvent>('custom documents');
|
||||
@@ -305,7 +305,11 @@ class CustomDocumentStoreEntry {
|
||||
}
|
||||
|
||||
getNewBackupUri(): URI {
|
||||
return joinPath(URI.file(this._storagePath), hashPath(this.document.uri) + (this._backupCounter++));
|
||||
if (!this._storagePath) {
|
||||
throw new Error('Backup requires a valid storage path');
|
||||
}
|
||||
const fileName = hashPath(this.document.uri) + (this._backupCounter++);
|
||||
return joinPath(this._storagePath, fileName);
|
||||
}
|
||||
|
||||
updateBackup(backup: vscode.CustomDocumentBackup): void {
|
||||
@@ -334,7 +338,7 @@ class CustomDocumentStore {
|
||||
return this._documents.get(this.key(viewType, resource));
|
||||
}
|
||||
|
||||
public add(viewType: string, document: vscode.CustomDocument, storagePath: string): CustomDocumentStoreEntry {
|
||||
public add(viewType: string, document: vscode.CustomDocument, storagePath: URI | undefined): CustomDocumentStoreEntry {
|
||||
const key = this.key(viewType, document.uri);
|
||||
if (this._documents.has(key)) {
|
||||
throw new Error(`Document already exists for viewType:${viewType} resource:${document.uri}`);
|
||||
@@ -592,8 +596,11 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
const revivedResource = URI.revive(resource);
|
||||
const document = await entry.provider.openCustomDocument(revivedResource, { backupId }, cancellation);
|
||||
|
||||
const storageRoot = this._extensionStoragePaths?.workspaceValue(entry.extension) ?? this._extensionStoragePaths?.globalValue(entry.extension);
|
||||
this._documents.add(viewType, document, storageRoot!);
|
||||
let storageRoot: URI | undefined;
|
||||
if (this.supportEditing(entry.provider) && this._extensionStoragePaths) {
|
||||
storageRoot = URI.file(this._extensionStoragePaths.workspaceValue(entry.extension) ?? this._extensionStoragePaths.globalValue(entry.extension));
|
||||
}
|
||||
this._documents.add(viewType, document, storageRoot);
|
||||
|
||||
return { editable: this.supportEditing(entry.provider) };
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ namespace schema {
|
||||
switch (menuId) {
|
||||
case MenuId.StatusBarWindowIndicatorMenu:
|
||||
case MenuId.MenubarWebNavigationMenu:
|
||||
case MenuId.NotebookCellTitle:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -88,6 +88,7 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
|
||||
|
||||
const configProvider = await this._configurationService.getConfigProvider();
|
||||
const shell = this._terminalService.getDefaultShell(true, configProvider);
|
||||
let cwdForPrepareCommand: string | undefined;
|
||||
|
||||
if (needNewTerminal || !this._integratedTerminalInstance) {
|
||||
|
||||
@@ -97,9 +98,9 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
|
||||
cwd: args.cwd,
|
||||
name: args.title || nls.localize('debug.terminal.title', "debuggee"),
|
||||
};
|
||||
// @ts-ignore
|
||||
delete args.cwd;
|
||||
this._integratedTerminalInstance = this._terminalService.createTerminalFromOptions(options);
|
||||
} else {
|
||||
cwdForPrepareCommand = args.cwd;
|
||||
}
|
||||
|
||||
const terminal = this._integratedTerminalInstance;
|
||||
@@ -107,7 +108,7 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
|
||||
terminal.show();
|
||||
|
||||
const shellProcessId = await this._integratedTerminalInstance.processId;
|
||||
const command = prepareCommand(args, shell);
|
||||
const command = prepareCommand(shell, args.args, cwdForPrepareCommand, args.env);
|
||||
terminal.sendText(command, true);
|
||||
|
||||
return shellProcessId;
|
||||
@@ -120,7 +121,6 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
|
||||
}
|
||||
|
||||
protected createVariableResolver(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider): AbstractVariableResolverService {
|
||||
return new ExtHostVariableResolverService(folders, editorService, configurationService, process.env as env.IProcessEnvironment);
|
||||
return new ExtHostVariableResolverService(folders, undefined, configurationService, process.env as env.IProcessEnvironment);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,7 +53,14 @@ export class ExtHostTask extends ExtHostTaskBase {
|
||||
const tTask = (task as types.Task);
|
||||
// We have a preserved ID. So the task didn't change.
|
||||
if (tTask._id !== undefined) {
|
||||
return this._proxy.$executeTask(TaskHandleDTO.from(tTask)).then(value => this.getTaskExecution(value, task));
|
||||
// Always get the task execution first to prevent timing issues when retrieving it later
|
||||
const executionDTO = await this._proxy.$getTaskExecution(TaskHandleDTO.from(tTask));
|
||||
if (executionDTO.task === undefined) {
|
||||
throw new Error('Task from execution DTO is undefined');
|
||||
}
|
||||
const execution = await this.getTaskExecution(executionDTO, task);
|
||||
this._proxy.$executeTask(executionDTO.task).catch(error => { throw new Error(error); });
|
||||
return execution;
|
||||
} else {
|
||||
const dto = TaskDTO.from(task, extension);
|
||||
if (dto === undefined) {
|
||||
@@ -66,8 +73,10 @@ export class ExtHostTask extends ExtHostTaskBase {
|
||||
if (CustomExecutionDTO.is(dto.execution)) {
|
||||
await this.addCustomExecution(dto, task, false);
|
||||
}
|
||||
|
||||
return this._proxy.$executeTask(dto).then(value => this.getTaskExecution(value, task));
|
||||
// Always get the task execution first to prevent timing issues when retrieving it later
|
||||
const execution = await this.getTaskExecution(await this._proxy.$getTaskExecution(dto), task);
|
||||
this._proxy.$executeTask(dto).catch(error => { throw new Error(error); });
|
||||
return execution;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/termi
|
||||
import { IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IShellLaunchConfig, ITerminalEnvironment } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IShellLaunchConfig, ITerminalEnvironment, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
|
||||
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
@@ -129,7 +129,7 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
|
||||
this._variableResolver = new ExtHostVariableResolverService(workspaceFolders || [], this._extHostDocumentsAndEditors, configProvider, process.env as platform.IProcessEnvironment);
|
||||
}
|
||||
|
||||
public async $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents | undefined, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<void> {
|
||||
public async $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents | undefined, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<ITerminalLaunchError | undefined> {
|
||||
const shellLaunchConfig: IShellLaunchConfig = {
|
||||
name: shellLaunchConfigDto.name,
|
||||
executable: shellLaunchConfigDto.executable,
|
||||
@@ -209,7 +209,15 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
|
||||
// TODO: Support conpty on remote, it doesn't seem to work for some reason?
|
||||
// TODO: When conpty is enabled, only enable it when accessibilityMode is off
|
||||
const enableConpty = false; //terminalConfig.get('windowsEnableConpty') as boolean;
|
||||
this._setupExtHostProcessListeners(id, new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, enableConpty, this._logService));
|
||||
|
||||
const terminalProcess = new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, enableConpty, this._logService);
|
||||
this._setupExtHostProcessListeners(id, terminalProcess);
|
||||
const error = await terminalProcess.start();
|
||||
if (error) {
|
||||
// TODO: Teardown?
|
||||
return error;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public $getAvailableShells(): Promise<IShellDefinitionDto[]> {
|
||||
|
||||
@@ -181,7 +181,7 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
|
||||
|
||||
connections.filter((connection => socketMap[connection.socket])).forEach(({ socket, ip, port }) => {
|
||||
const command = processMap[socketMap[socket].pid].cmd;
|
||||
if (!command.match('.*\.vscode\-server\-[a-zA-Z]+\/bin.*') && (command.indexOf('out/vs/server/main.js') === -1)) {
|
||||
if (!command.match(/.*\.vscode-server-[a-zA-Z]+\/bin.*/) && (command.indexOf('out/vs/server/main.js') === -1)) {
|
||||
ports.push({ host: ip, port, detail: processMap[socketMap[socket].pid].cmd });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ import { UriComponents } from 'vs/base/common/uri';
|
||||
|
||||
export class ExtHostLogService extends AbstractLogService implements ILogService, ExtHostLogServiceShape {
|
||||
|
||||
_serviceBrand: undefined;
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly _proxy: MainThreadLogShape;
|
||||
private readonly _logFile: UriComponents;
|
||||
|
||||
Reference in New Issue
Block a user