mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-11 18:48:33 -05:00
Merge vscode source through 1.62 release (#19981)
* Build breaks 1 * Build breaks * Build breaks * Build breaks * More build breaks * Build breaks (#2512) * Runtime breaks * Build breaks * Fix dialog location break * Update typescript * Fix ASAR break issue * Unit test breaks * Update distro * Fix breaks in ADO builds (#2513) * Bump to node 16 * Fix hygiene errors * Bump distro * Remove reference to node type * Delete vscode specific extension * Bump to node 16 in CI yaml * Skip integration tests in CI builds (while fixing) * yarn.lock update * Bump moment dependency in remote yarn * Fix drop-down chevron style * Bump to node 16 * Remove playwrite from ci.yaml * Skip building build scripts in hygine check
This commit is contained in:
@@ -17,6 +17,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
||||
import { fromNow } from 'vs/base/common/date';
|
||||
import { ActivationKind, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import type { AuthenticationGetSessionOptions } from 'vscode';
|
||||
|
||||
interface TrustedExtensionsQuickPickItem {
|
||||
label: string;
|
||||
@@ -204,91 +205,67 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||
|
||||
}
|
||||
|
||||
private async selectSession(providerId: string, extensionId: string, extensionName: string, scopes: string[], potentialSessions: readonly modes.AuthenticationSession[], clearSessionPreference: boolean, silent: boolean): Promise<modes.AuthenticationSession | undefined> {
|
||||
if (!potentialSessions.length) {
|
||||
throw new Error('No potential sessions found');
|
||||
}
|
||||
|
||||
if (clearSessionPreference) {
|
||||
this.storageService.remove(`${extensionName}-${providerId}`, StorageScope.GLOBAL);
|
||||
} else {
|
||||
const existingSessionPreference = this.storageService.get(`${extensionName}-${providerId}`, StorageScope.GLOBAL);
|
||||
if (existingSessionPreference) {
|
||||
const matchingSession = potentialSessions.find(session => session.id === existingSessionPreference);
|
||||
if (matchingSession) {
|
||||
const allowed = this.authenticationService.isAccessAllowed(providerId, matchingSession.account.label, extensionId);
|
||||
if (!allowed) {
|
||||
if (!silent) {
|
||||
const didAcceptPrompt = await this.authenticationService.showGetSessionPrompt(providerId, matchingSession.account.label, extensionId, extensionName);
|
||||
if (!didAcceptPrompt) {
|
||||
throw new Error('User did not consent to login.');
|
||||
}
|
||||
} else {
|
||||
this.authenticationService.requestSessionAccess(providerId, extensionId, extensionName, scopes, potentialSessions);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return matchingSession;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (silent) {
|
||||
this.authenticationService.requestSessionAccess(providerId, extensionId, extensionName, scopes, potentialSessions);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.authenticationService.selectSession(providerId, extensionId, extensionName, scopes, potentialSessions);
|
||||
}
|
||||
|
||||
async $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: { createIfNone: boolean, forceNewSession: boolean | { detail: string }, clearSessionPreference: boolean }): Promise<modes.AuthenticationSession | undefined> {
|
||||
private async doGetSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: AuthenticationGetSessionOptions): Promise<modes.AuthenticationSession | undefined> {
|
||||
const sessions = await this.authenticationService.getSessions(providerId, scopes, true);
|
||||
let silent = !options.createIfNone;
|
||||
|
||||
// Error cases
|
||||
if (options.forceNewSession && !sessions.length) {
|
||||
throw new Error('No existing sessions found.');
|
||||
}
|
||||
if (options.forceNewSession && options.createIfNone) {
|
||||
throw new Error('Invalid combination of options. Please remove one of the following: forceNewSession, createIfNone');
|
||||
}
|
||||
if (options.forceNewSession && options.silent) {
|
||||
throw new Error('Invalid combination of options. Please remove one of the following: forceNewSession, silent');
|
||||
}
|
||||
if (options.createIfNone && options.silent) {
|
||||
throw new Error('Invalid combination of options. Please remove one of the following: createIfNone, silent');
|
||||
}
|
||||
|
||||
let session: modes.AuthenticationSession | undefined;
|
||||
// Ignore existing sessions if we are forceRecreating
|
||||
// Check if the sessions we have are valid
|
||||
if (!options.forceNewSession && sessions.length) {
|
||||
if (!this.authenticationService.supportsMultipleAccounts(providerId)) {
|
||||
session = sessions[0];
|
||||
const allowed = this.authenticationService.isAccessAllowed(providerId, session.account.label, extensionId);
|
||||
if (!allowed) {
|
||||
if (!silent) {
|
||||
const didAcceptPrompt = await this.authenticationService.showGetSessionPrompt(providerId, session.account.label, extensionId, extensionName);
|
||||
if (!didAcceptPrompt) {
|
||||
throw new Error('User did not consent to login.');
|
||||
if (this.authenticationService.supportsMultipleAccounts(providerId)) {
|
||||
if (options.clearSessionPreference) {
|
||||
this.storageService.remove(`${extensionName}-${providerId}`, StorageScope.GLOBAL);
|
||||
} else {
|
||||
const existingSessionPreference = this.storageService.get(`${extensionName}-${providerId}`, StorageScope.GLOBAL);
|
||||
if (existingSessionPreference) {
|
||||
const matchingSession = sessions.find(session => session.id === existingSessionPreference);
|
||||
if (matchingSession && this.authenticationService.isAccessAllowed(providerId, matchingSession.account.label, extensionId)) {
|
||||
return matchingSession;
|
||||
}
|
||||
} else if (allowed !== false) {
|
||||
this.authenticationService.requestSessionAccess(providerId, extensionId, extensionName, scopes, [session]);
|
||||
return undefined;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return this.selectSession(providerId, extensionId, extensionName, scopes, sessions, !!options.clearSessionPreference, silent);
|
||||
}
|
||||
} else {
|
||||
// If we are forceRecreating, we need to show the prompt.
|
||||
if (options.forceNewSession || !silent) {
|
||||
const providerName = this.authenticationService.getLabel(providerId);
|
||||
const detail = (typeof options.forceNewSession === 'object') ? options.forceNewSession!.detail : undefined;
|
||||
const isAllowed = await this.loginPrompt(providerName, extensionName, !!options.forceNewSession, detail);
|
||||
if (!isAllowed) {
|
||||
throw new Error('User did not consent to login.');
|
||||
}
|
||||
|
||||
session = await this.authenticationService.createSession(providerId, scopes, true);
|
||||
await this.setTrustedExtensionAndAccountPreference(providerId, session.account.label, extensionId, extensionName, session.id);
|
||||
} else {
|
||||
await this.authenticationService.requestNewSession(providerId, scopes, extensionId, extensionName);
|
||||
} else if (this.authenticationService.isAccessAllowed(providerId, sessions[0].account.label, extensionId)) {
|
||||
return sessions[0];
|
||||
}
|
||||
}
|
||||
|
||||
// We may need to prompt because we don't have a valid session
|
||||
// modal flows
|
||||
if (options.createIfNone || options.forceNewSession) {
|
||||
const providerName = this.authenticationService.getLabel(providerId);
|
||||
const detail = (typeof options.forceNewSession === 'object') ? options.forceNewSession!.detail : undefined;
|
||||
const isAllowed = await this.loginPrompt(providerName, extensionName, !!options.forceNewSession, detail);
|
||||
if (!isAllowed) {
|
||||
throw new Error('User did not consent to login.');
|
||||
}
|
||||
|
||||
const session = await this.authenticationService.createSession(providerId, scopes, true);
|
||||
await this.setTrustedExtensionAndAccountPreference(providerId, session.account.label, extensionId, extensionName, session.id);
|
||||
return session;
|
||||
}
|
||||
// passive flows
|
||||
if (!options.silent) {
|
||||
await this.authenticationService.requestNewSession(providerId, scopes, extensionId, extensionName);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: AuthenticationGetSessionOptions): Promise<modes.AuthenticationSession | undefined> {
|
||||
const session = await this.doGetSession(providerId, scopes, extensionId, extensionName, options);
|
||||
|
||||
if (session) {
|
||||
type AuthProviderUsageClassification = {
|
||||
extensionId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
|
||||
@@ -9,6 +9,7 @@ import { ExtHostContext, MainThreadCommandsShape, ExtHostCommandsShape, MainCont
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadCommands)
|
||||
export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
@@ -72,7 +73,10 @@ export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
}
|
||||
}
|
||||
|
||||
async $executeCommand<T>(id: string, args: any[], retry: boolean): Promise<T | undefined> {
|
||||
async $executeCommand<T>(id: string, args: any[] | SerializableObjectWithBuffers<any[]>, retry: boolean): Promise<T | undefined> {
|
||||
if (args instanceof SerializableObjectWithBuffers) {
|
||||
args = args.value;
|
||||
}
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
args[i] = revive(args[i]);
|
||||
}
|
||||
|
||||
@@ -290,6 +290,10 @@ export class MainThreadCommentController {
|
||||
}
|
||||
}
|
||||
|
||||
updateCommentingRanges() {
|
||||
this._commentService.updateCommentingRanges(this._uniqueId);
|
||||
}
|
||||
|
||||
private getKnownThread(commentThreadHandle: number): MainThreadCommentThread {
|
||||
const thread = this._threads.get(commentThreadHandle);
|
||||
if (!thread) {
|
||||
@@ -412,12 +416,15 @@ export class MainThreadComments extends Disposable implements MainThreadComments
|
||||
|
||||
$unregisterCommentController(handle: number): void {
|
||||
const providerId = this._handlers.get(handle);
|
||||
if (typeof providerId !== 'string') {
|
||||
throw new Error('unknown handler');
|
||||
}
|
||||
this._commentService.unregisterCommentController(providerId);
|
||||
this._handlers.delete(handle);
|
||||
this._commentControllers.delete(handle);
|
||||
|
||||
if (typeof providerId !== 'string') {
|
||||
return;
|
||||
// throw new Error('unknown handler');
|
||||
} else {
|
||||
this._commentService.unregisterCommentController(providerId);
|
||||
}
|
||||
}
|
||||
|
||||
$updateCommentControllerFeatures(handle: number, features: CommentProviderFeatures): void {
|
||||
@@ -470,6 +477,16 @@ export class MainThreadComments extends Disposable implements MainThreadComments
|
||||
return provider.deleteCommentThread(commentThreadHandle);
|
||||
}
|
||||
|
||||
$updateCommentingRanges(handle: number) {
|
||||
let provider = this._commentControllers.get(handle);
|
||||
|
||||
if (!provider) {
|
||||
return;
|
||||
}
|
||||
|
||||
provider.updateCommentingRanges();
|
||||
}
|
||||
|
||||
private registerView(commentsViewAlreadyRegistered: boolean) {
|
||||
if (!commentsViewAlreadyRegistered) {
|
||||
const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewExtensions.ViewContainersRegistry).registerViewContainer({
|
||||
|
||||
@@ -7,7 +7,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { MainContext, MainThreadConsoleShape, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IRemoteConsoleLog, log } from 'vs/base/common/console';
|
||||
import { logRemoteEntry } from 'vs/workbench/services/extensions/common/remoteConsoleUtil';
|
||||
import { logRemoteEntry, logRemoteEntryIfError } from 'vs/workbench/services/extensions/common/remoteConsoleUtil';
|
||||
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
@@ -30,14 +30,13 @@ export class MainThreadConsole implements MainThreadConsoleShape {
|
||||
}
|
||||
|
||||
$logExtensionHostMessage(entry: IRemoteConsoleLog): void {
|
||||
// Send to local console unless we run tests from cli
|
||||
if (!this._isExtensionDevTestFromCli) {
|
||||
log(entry, 'Extension Host');
|
||||
}
|
||||
|
||||
// Log on main side if running tests from cli
|
||||
if (this._isExtensionDevTestFromCli) {
|
||||
// If running tests from cli, log to the log service everything
|
||||
logRemoteEntry(this._logService, entry);
|
||||
} else {
|
||||
// Log to the log service only errors and log everything to local console
|
||||
logRemoteEntryIfError(this._logService, entry, 'Extension Host');
|
||||
log(entry, 'Extension Host');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,7 +646,7 @@ class MainThreadCustomEditorModel extends ResourceWorkingCopy implements ICustom
|
||||
backupId: '',
|
||||
extension: primaryEditor.extension ? {
|
||||
id: primaryEditor.extension.id.value,
|
||||
location: primaryEditor.extension.location,
|
||||
location: primaryEditor.extension.location!,
|
||||
} : undefined,
|
||||
webview: {
|
||||
id: primaryEditor.id,
|
||||
|
||||
@@ -219,7 +219,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public $startDebugging(folder: UriComponents | undefined, nameOrConfig: string | IDebugConfiguration, options: IStartDebuggingOptions): Promise<boolean> {
|
||||
public async $startDebugging(folder: UriComponents | undefined, nameOrConfig: string | IDebugConfiguration, options: IStartDebuggingOptions): Promise<boolean> {
|
||||
const folderUri = folder ? uri.revive(folder) : undefined;
|
||||
const launch = this.debugService.getConfigurationManager().getLaunch(folderUri);
|
||||
const parentSession = this.getSession(options.parentSessionID);
|
||||
@@ -232,11 +232,12 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
debugUI: options.debugUI,
|
||||
compoundRoot: parentSession?.compoundRoot
|
||||
};
|
||||
return this.debugService.startDebugging(launch, nameOrConfig, debugOptions).then(success => {
|
||||
return success;
|
||||
}, err => {
|
||||
return Promise.reject(new Error(err && err.message ? err.message : 'cannot start debugging'));
|
||||
});
|
||||
try {
|
||||
const saveBeforeStart = typeof options.suppressSaveBeforeStart === 'boolean' ? !options.suppressSaveBeforeStart : undefined;
|
||||
return this.debugService.startDebugging(launch, nameOrConfig, debugOptions, saveBeforeStart);
|
||||
} catch (err) {
|
||||
throw new Error(err && err.message ? err.message : 'cannot start debugging');
|
||||
}
|
||||
}
|
||||
|
||||
public $setDebugSessionName(sessionId: DebugSessionUUID, name: string): void {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Emitter } from 'vs/base/common/event';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ExtHostContext, MainContext, IExtHostContext, MainThreadDecorationsShape, ExtHostDecorationsShape, DecorationData, DecorationRequest } from '../common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { IDecorationsService, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations';
|
||||
import { IDecorationsService, IDecorationData } from 'vs/workbench/services/decorations/common/decorations';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
class DecorationRequestsQueue {
|
||||
|
||||
@@ -29,8 +29,9 @@ export class BoundModelReferenceCollection {
|
||||
|
||||
constructor(
|
||||
private readonly _extUri: IExtUri,
|
||||
private readonly _maxAge: number = 1000 * 60 * 3,
|
||||
private readonly _maxLength: number = 1024 * 1024 * 80,
|
||||
private readonly _maxAge: number = 1000 * 60 * 3, // auto-dispse by age
|
||||
private readonly _maxLength: number = 1024 * 1024 * 80, // auto-dispose by total length
|
||||
private readonly _maxSize: number = 50 // auto-dispose by number of references
|
||||
) {
|
||||
//
|
||||
}
|
||||
@@ -69,9 +70,15 @@ export class BoundModelReferenceCollection {
|
||||
}
|
||||
|
||||
private _cleanup(): void {
|
||||
// clean-up wrt total length
|
||||
while (this._length > this._maxLength) {
|
||||
this._data[0].dispose();
|
||||
}
|
||||
// clean-up wrt number of documents
|
||||
const extraSize = Math.ceil(this._maxSize * 1.2);
|
||||
if (this._data.length >= extraSize) {
|
||||
dispose(this._data.slice(0, extraSize - this._maxSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +198,7 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen
|
||||
if (!this._modelIsSynced.has(model.uri)) {
|
||||
return;
|
||||
}
|
||||
this._proxy.$acceptModelModeChanged(model.uri, model.getLanguageIdentifier().language);
|
||||
this._proxy.$acceptModelModeChanged(model.uri, model.getLanguageId());
|
||||
}
|
||||
|
||||
private _onModelRemoved(modelUrl: URI): void {
|
||||
|
||||
@@ -24,7 +24,6 @@ import { IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { EditorGroupColumn, editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||
@@ -35,7 +34,8 @@ import { diffSets, diffMaps } from 'vs/base/common/collections';
|
||||
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { CELL_URI_PATH_PREFIX } from 'sql/workbench/common/constants';
|
||||
|
||||
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
|
||||
import { ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
|
||||
class TextEditorSnapshot {
|
||||
|
||||
@@ -125,7 +125,7 @@ class MainThreadDocumentAndEditorStateComputer {
|
||||
@IModelService private readonly _modelService: IModelService,
|
||||
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@IPanelService private readonly _panelService: IPanelService
|
||||
@IPaneCompositePartService private readonly _paneCompositeService: IPaneCompositePartService,
|
||||
) {
|
||||
this._modelService.onModelAdded(this._updateStateOnModelAdd, this, this._toDispose);
|
||||
this._modelService.onModelRemoved(_ => this._updateState(), this, this._toDispose);
|
||||
@@ -135,8 +135,8 @@ class MainThreadDocumentAndEditorStateComputer {
|
||||
this._codeEditorService.onCodeEditorRemove(this._onDidRemoveEditor, this, this._toDispose);
|
||||
this._codeEditorService.listCodeEditors().forEach(this._onDidAddEditor, this);
|
||||
|
||||
this._panelService.onDidPanelOpen(_ => this._activeEditorOrder = ActiveEditorOrder.Panel, undefined, this._toDispose);
|
||||
this._panelService.onDidPanelClose(_ => this._activeEditorOrder = ActiveEditorOrder.Editor, undefined, this._toDispose);
|
||||
Event.filter(this._paneCompositeService.onDidPaneCompositeOpen, event => event.viewContainerLocation === ViewContainerLocation.Panel)(_ => this._activeEditorOrder = ActiveEditorOrder.Panel, undefined, this._toDispose);
|
||||
Event.filter(this._paneCompositeService.onDidPaneCompositeClose, event => event.viewContainerLocation === ViewContainerLocation.Panel)(_ => this._activeEditorOrder = ActiveEditorOrder.Editor, undefined, this._toDispose);
|
||||
this._editorService.onDidVisibleEditorsChange(_ => this._activeEditorOrder = ActiveEditorOrder.Editor, undefined, this._toDispose);
|
||||
|
||||
this._updateState();
|
||||
@@ -255,12 +255,15 @@ class MainThreadDocumentAndEditorStateComputer {
|
||||
}
|
||||
|
||||
private _getActiveEditorFromPanel(): IEditor | undefined {
|
||||
const panel = this._panelService.getActivePanel();
|
||||
if (panel instanceof BaseTextEditor && isCodeEditor(panel.getControl())) {
|
||||
return panel.getControl();
|
||||
} else {
|
||||
return undefined;
|
||||
const panel = this._paneCompositeService.getActivePaneComposite(ViewContainerLocation.Panel);
|
||||
if (panel instanceof BaseTextEditor) {
|
||||
const control = panel.getControl();
|
||||
if (isCodeEditor(control)) {
|
||||
return control;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private _getActiveEditorFromEditorPart(): IEditor | undefined {
|
||||
@@ -300,7 +303,7 @@ export class MainThreadDocumentsAndEditors {
|
||||
@ITextModelService textModelResolverService: ITextModelService,
|
||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||
@IBulkEditService bulkEditService: IBulkEditService,
|
||||
@IPanelService panelService: IPanelService,
|
||||
@IPaneCompositePartService paneCompositeService: IPaneCompositePartService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService,
|
||||
@IUriIdentityService uriIdentityService: IUriIdentityService,
|
||||
@@ -317,7 +320,7 @@ export class MainThreadDocumentsAndEditors {
|
||||
extHostContext.set(MainContext.MainThreadTextEditors, mainThreadTextEditors);
|
||||
|
||||
// It is expected that the ctor of the state computer calls our `_onDelta`.
|
||||
this._toDispose.add(new MainThreadDocumentAndEditorStateComputer(delta => this._onDelta(delta), _modelService, codeEditorService, this._editorService, panelService));
|
||||
this._toDispose.add(new MainThreadDocumentAndEditorStateComputer(delta => this._onDelta(delta), _modelService, codeEditorService, this._editorService, paneCompositeService));
|
||||
|
||||
this._toDispose.add(this._onTextEditorAdd);
|
||||
this._toDispose.add(this._onTextEditorRemove);
|
||||
@@ -403,7 +406,7 @@ export class MainThreadDocumentsAndEditors {
|
||||
versionId: model.getVersionId(),
|
||||
lines: model.getLinesContent(),
|
||||
EOL: model.getEOL(),
|
||||
modeId: model.getLanguageIdentifier().language,
|
||||
languageId: model.getLanguageId(),
|
||||
isDirty: this._textFileService.isDirty(model.uri),
|
||||
notebookUri: notebookUri
|
||||
};
|
||||
|
||||
@@ -349,7 +349,7 @@ export class MainThreadTextEditor {
|
||||
}
|
||||
|
||||
private _setIndentConfiguration(newConfiguration: ITextEditorConfigurationUpdate): void {
|
||||
const creationOpts = this._modelService.getCreationOptions(this._model.getLanguageIdentifier().language, this._model.uri, this._model.isForSimpleWidget);
|
||||
const creationOpts = this._modelService.getCreationOptions(this._model.getLanguageId(), this._model.uri, this._model.isForSimpleWidget);
|
||||
|
||||
if (newConfiguration.tabSize === 'auto' || newConfiguration.insertSpaces === 'auto') {
|
||||
// one of the options was set to 'auto' => detect indentation
|
||||
|
||||
@@ -3,27 +3,26 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ExtHostContext, IExtHostEditorTabsShape, IExtHostContext, MainContext, IEditorTabDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { EditorResourceAccessor, Verbosity } from 'vs/workbench/common/editor';
|
||||
import { GroupChangeKind, IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { EditorResourceAccessor, IUntypedEditorInput, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
|
||||
import { columnToEditorGroup, EditorGroupColumn, editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
|
||||
import { GroupChangeKind, GroupDirection, IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorsChangeEvent, IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
export interface ITabInfo {
|
||||
name: string;
|
||||
resource: URI;
|
||||
}
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadEditorTabs)
|
||||
export class MainThreadEditorTabs {
|
||||
|
||||
private static _GroupEventFilter = new Set([GroupChangeKind.EDITOR_CLOSE, GroupChangeKind.EDITOR_OPEN]);
|
||||
|
||||
private readonly _dispoables = new DisposableStore();
|
||||
private readonly _groups = new Map<IEditorGroup, IDisposable>();
|
||||
private readonly _proxy: IExtHostEditorTabsShape;
|
||||
private readonly _tabModel: Map<number, IEditorTabDto[]> = new Map<number, IEditorTabDto[]>();
|
||||
private _currentlyActiveTab: { groupId: number, tab: IEditorTabDto } | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@@ -33,51 +32,255 @@ export class MainThreadEditorTabs {
|
||||
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostEditorTabs);
|
||||
|
||||
this._editorGroupsService.whenReady.then(() => this._editorGroupsService.groups.forEach(this._subscribeToGroup, this));
|
||||
this._dispoables.add(_editorGroupsService.onDidAddGroup(this._subscribeToGroup, this));
|
||||
this._dispoables.add(_editorGroupsService.onDidRemoveGroup(e => {
|
||||
const subscription = this._groups.get(e);
|
||||
if (subscription) {
|
||||
subscription.dispose();
|
||||
this._groups.delete(e);
|
||||
this._pushEditorTabs();
|
||||
}
|
||||
}));
|
||||
this._dispoables.add(editorService.onDidActiveEditorChange(this._pushEditorTabs, this));
|
||||
this._pushEditorTabs();
|
||||
// Queue all events that arrive on the same event loop and then send them as a batch
|
||||
this._dispoables.add(editorService.onDidEditorsChange((events) => this._updateTabsModel(events)));
|
||||
this._editorGroupsService.whenReady.then(() => this._createTabsModel());
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
dispose(this._groups.values());
|
||||
this._dispoables.dispose();
|
||||
}
|
||||
|
||||
private _subscribeToGroup(group: IEditorGroup) {
|
||||
this._groups.get(group)?.dispose();
|
||||
const listener = group.onDidGroupChange(e => {
|
||||
if (MainThreadEditorTabs._GroupEventFilter.has(e.kind)) {
|
||||
this._pushEditorTabs();
|
||||
}
|
||||
});
|
||||
this._groups.set(group, listener);
|
||||
/**
|
||||
* Creates a tab object with the correct properties
|
||||
* @param editor The editor input represented by the tab
|
||||
* @param group The group the tab is in
|
||||
* @returns A tab object
|
||||
*/
|
||||
private _buildTabObject(editor: EditorInput, group: IEditorGroup): IEditorTabDto {
|
||||
// Even though the id isn't a diff / sideBySide on the main side we need to let the ext host know what type of editor it is
|
||||
const editorId = editor instanceof DiffEditorInput ? 'diff' : editor instanceof SideBySideEditorInput ? 'sideBySide' : editor.editorId;
|
||||
const tab: IEditorTabDto = {
|
||||
viewColumn: editorGroupToColumn(this._editorGroupsService, group),
|
||||
label: editor.getName(),
|
||||
resource: editor instanceof SideBySideEditorInput ? EditorResourceAccessor.getCanonicalUri(editor, { supportSideBySide: SideBySideEditor.PRIMARY }) : EditorResourceAccessor.getCanonicalUri(editor),
|
||||
editorId,
|
||||
additionalResourcesAndViewIds: [],
|
||||
isActive: (this._editorGroupsService.activeGroup === group) && group.isActive(editor)
|
||||
};
|
||||
tab.additionalResourcesAndViewIds.push({ resource: tab.resource, viewId: tab.editorId });
|
||||
if (editor instanceof SideBySideEditorInput) {
|
||||
tab.additionalResourcesAndViewIds.push({ resource: EditorResourceAccessor.getCanonicalUri(editor, { supportSideBySide: SideBySideEditor.SECONDARY }), viewId: editor.primary.editorId ?? editor.editorId });
|
||||
}
|
||||
return tab;
|
||||
}
|
||||
|
||||
private _pushEditorTabs(): void {
|
||||
const tabs: IEditorTabDto[] = [];
|
||||
|
||||
private _tabToUntypedEditorInput(tab: IEditorTabDto): IUntypedEditorInput {
|
||||
if (tab.editorId !== 'diff' && tab.editorId !== 'sideBySide') {
|
||||
return { resource: URI.revive(tab.resource), options: { override: tab.editorId } };
|
||||
} else if (tab.editorId === 'sideBySide') {
|
||||
return {
|
||||
primary: { resource: URI.revive(tab.resource), options: { override: tab.editorId } },
|
||||
secondary: { resource: URI.revive(tab.additionalResourcesAndViewIds[1].resource), options: { override: tab.additionalResourcesAndViewIds[1].viewId } }
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
modified: { resource: URI.revive(tab.resource), options: { override: tab.editorId } },
|
||||
original: { resource: URI.revive(tab.additionalResourcesAndViewIds[1].resource), options: { override: tab.additionalResourcesAndViewIds[1].viewId } }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the model from scratch based on the current state of the editor service.
|
||||
*/
|
||||
private _createTabsModel(): void {
|
||||
this._tabModel.clear();
|
||||
let tabs: IEditorTabDto[] = [];
|
||||
for (const group of this._editorGroupsService.groups) {
|
||||
for (const editor of group.editors) {
|
||||
if (editor.isDisposed() || !editor.resource) {
|
||||
if (editor.isDisposed()) {
|
||||
continue;
|
||||
}
|
||||
tabs.push({
|
||||
group: group.id,
|
||||
name: editor.getTitle(Verbosity.SHORT) ?? '',
|
||||
resource: EditorResourceAccessor.getOriginalUri(editor) ?? editor.resource,
|
||||
isActive: (this._editorGroupsService.activeGroup === group) && group.isActive(editor)
|
||||
});
|
||||
const tab = this._buildTabObject(editor, group);
|
||||
if (tab.isActive) {
|
||||
this._currentlyActiveTab = { groupId: group.id, tab };
|
||||
}
|
||||
tabs.push(tab);
|
||||
}
|
||||
this._tabModel.set(group.id, tabs);
|
||||
}
|
||||
|
||||
this._proxy.$acceptEditorTabs(tabs);
|
||||
}
|
||||
|
||||
private _onDidTabOpen(event: IEditorsChangeEvent): void {
|
||||
if (event.kind !== GroupChangeKind.EDITOR_OPEN || !event.editor || event.editorIndex === undefined) {
|
||||
return;
|
||||
}
|
||||
if (!this._tabModel.has(event.groupId)) {
|
||||
this._tabModel.set(event.groupId, []);
|
||||
}
|
||||
const editor = event.editor;
|
||||
const tab = this._buildTabObject(editor, this._editorGroupsService.getGroup(event.groupId) ?? this._editorGroupsService.activeGroup);
|
||||
this._tabModel.get(event.groupId)?.splice(event.editorIndex, 0, tab);
|
||||
// Update the currently active tab which may or may not be the opened one
|
||||
if (tab.isActive) {
|
||||
if (this._currentlyActiveTab) {
|
||||
this._currentlyActiveTab.tab.isActive = (this._editorGroupsService.activeGroup.id === this._currentlyActiveTab.groupId) && this._editorGroupsService.activeGroup.isActive(this._tabToUntypedEditorInput(this._currentlyActiveTab.tab));
|
||||
}
|
||||
this._currentlyActiveTab = { groupId: event.groupId, tab };
|
||||
}
|
||||
}
|
||||
|
||||
private _onDidTabClose(event: IEditorsChangeEvent): void {
|
||||
if (event.kind !== GroupChangeKind.EDITOR_CLOSE || event.editorIndex === undefined) {
|
||||
return;
|
||||
}
|
||||
this._tabModel.get(event.groupId)?.splice(event.editorIndex, 1);
|
||||
this._findAndUpdateActiveTab();
|
||||
|
||||
// Remove any empty groups
|
||||
if (this._tabModel.get(event.groupId)?.length === 0) {
|
||||
this._tabModel.delete(event.groupId);
|
||||
}
|
||||
}
|
||||
|
||||
private _onDidTabMove(event: IEditorsChangeEvent): void {
|
||||
if (event.kind !== GroupChangeKind.EDITOR_MOVE || event.editorIndex === undefined || event.oldEditorIndex === undefined) {
|
||||
return;
|
||||
}
|
||||
const movedTab = this._tabModel.get(event.groupId)?.splice(event.oldEditorIndex, 1);
|
||||
if (movedTab === undefined) {
|
||||
return;
|
||||
}
|
||||
this._tabModel.get(event.groupId)?.splice(event.editorIndex, 0, movedTab[0]);
|
||||
movedTab[0].isActive = (this._editorGroupsService.activeGroup.id === event.groupId) && this._editorGroupsService.activeGroup.isActive(this._tabToUntypedEditorInput(movedTab[0]));
|
||||
// Update the currently active tab
|
||||
if (movedTab[0].isActive) {
|
||||
if (this._currentlyActiveTab) {
|
||||
this._currentlyActiveTab.tab.isActive = (this._editorGroupsService.activeGroup.id === this._currentlyActiveTab.groupId) && this._editorGroupsService.activeGroup.isActive(this._tabToUntypedEditorInput(this._currentlyActiveTab.tab));
|
||||
}
|
||||
this._currentlyActiveTab = { groupId: event.groupId, tab: movedTab[0] };
|
||||
}
|
||||
}
|
||||
|
||||
private _onDidGroupActivate(event: IEditorsChangeEvent): void {
|
||||
if (event.kind !== GroupChangeKind.GROUP_INDEX && event.kind !== GroupChangeKind.EDITOR_ACTIVE) {
|
||||
return;
|
||||
}
|
||||
this._findAndUpdateActiveTab();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the currently active tab so that `this._currentlyActiveTab` is up to date.
|
||||
*/
|
||||
private _findAndUpdateActiveTab() {
|
||||
// Go to the active group and update the active tab
|
||||
const activeGroupId = this._editorGroupsService.activeGroup.id;
|
||||
this._tabModel.get(activeGroupId)?.forEach(t => {
|
||||
if (t.resource) {
|
||||
t.isActive = this._editorGroupsService.activeGroup.isActive(this._tabToUntypedEditorInput(t));
|
||||
}
|
||||
if (t.isActive) {
|
||||
if (this._currentlyActiveTab) {
|
||||
this._currentlyActiveTab.tab.isActive = (this._editorGroupsService.activeGroup.id === this._currentlyActiveTab.groupId) && this._editorGroupsService.activeGroup.isActive(this._tabToUntypedEditorInput(this._currentlyActiveTab.tab));
|
||||
}
|
||||
this._currentlyActiveTab = { groupId: activeGroupId, tab: t };
|
||||
return;
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
// TODOD @lramos15 Remove this after done finishing the tab model code
|
||||
// private _eventArrayToString(events: IEditorsChangeEvent[]): void {
|
||||
// let eventString = '[';
|
||||
// events.forEach(event => {
|
||||
// switch (event.kind) {
|
||||
// case GroupChangeKind.GROUP_INDEX: eventString += 'GROUP_INDEX, '; break;
|
||||
// case GroupChangeKind.EDITOR_ACTIVE: eventString += 'EDITOR_ACTIVE, '; break;
|
||||
// case GroupChangeKind.EDITOR_PIN: eventString += 'EDITOR_PIN, '; break;
|
||||
// case GroupChangeKind.EDITOR_OPEN: eventString += 'EDITOR_OPEN, '; break;
|
||||
// case GroupChangeKind.EDITOR_CLOSE: eventString += 'EDITOR_CLOSE, '; break;
|
||||
// case GroupChangeKind.EDITOR_MOVE: eventString += 'EDITOR_MOVE, '; break;
|
||||
// case GroupChangeKind.EDITOR_LABEL: eventString += 'EDITOR_LABEL, '; break;
|
||||
// case GroupChangeKind.GROUP_ACTIVE: eventString += 'GROUP_ACTIVE, '; break;
|
||||
// case GroupChangeKind.GROUP_LOCKED: eventString += 'GROUP_LOCKED, '; break;
|
||||
// default: eventString += 'UNKNOWN, '; break;
|
||||
// }
|
||||
// });
|
||||
// eventString += ']';
|
||||
// console.log(eventString);
|
||||
// }
|
||||
|
||||
/**
|
||||
* The main handler for the tab events
|
||||
* @param events The list of events to process
|
||||
*/
|
||||
private _updateTabsModel(events: IEditorsChangeEvent[]): void {
|
||||
events.forEach(event => {
|
||||
// Call the correct function for the change type
|
||||
switch (event.kind) {
|
||||
case GroupChangeKind.EDITOR_OPEN:
|
||||
this._onDidTabOpen(event);
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_CLOSE:
|
||||
this._onDidTabClose(event);
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_ACTIVE:
|
||||
case GroupChangeKind.GROUP_ACTIVE:
|
||||
if (this._editorGroupsService.activeGroup.id !== event.groupId) {
|
||||
return;
|
||||
}
|
||||
this._onDidGroupActivate(event);
|
||||
break;
|
||||
case GroupChangeKind.GROUP_INDEX:
|
||||
this._createTabsModel();
|
||||
// Here we stop the loop as no need to process other events
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_MOVE:
|
||||
this._onDidTabMove(event);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
// Flatten the map into a singular array to send the ext host
|
||||
let allTabs: IEditorTabDto[] = [];
|
||||
this._tabModel.forEach((tabs) => allTabs = allTabs.concat(tabs));
|
||||
this._proxy.$acceptEditorTabs(allTabs);
|
||||
}
|
||||
//#region Messages received from Ext Host
|
||||
$moveTab(tab: IEditorTabDto, index: number, viewColumn: EditorGroupColumn): void {
|
||||
const groupId = columnToEditorGroup(this._editorGroupsService, viewColumn);
|
||||
let targetGroup: IEditorGroup | undefined;
|
||||
const sourceGroup = this._editorGroupsService.getGroup(columnToEditorGroup(this._editorGroupsService, tab.viewColumn));
|
||||
if (!sourceGroup) {
|
||||
return;
|
||||
}
|
||||
// If group index is out of bounds then we make a new one that's to the right of the last group
|
||||
if (this._tabModel.get(groupId) === undefined) {
|
||||
targetGroup = this._editorGroupsService.addGroup(this._editorGroupsService.groups[this._editorGroupsService.groups.length - 1], GroupDirection.RIGHT, undefined);
|
||||
} else {
|
||||
targetGroup = this._editorGroupsService.getGroup(groupId);
|
||||
}
|
||||
if (!targetGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Similar logic to if index is out of bounds we place it at the end
|
||||
if (index < 0 || index > targetGroup.editors.length) {
|
||||
index = targetGroup.editors.length;
|
||||
}
|
||||
// Find the correct EditorInput using the tab info
|
||||
const editorInput = sourceGroup.editors.find(editor => editor.matches(this._tabToUntypedEditorInput(tab)));
|
||||
if (!editorInput) {
|
||||
return;
|
||||
}
|
||||
// Move the editor to the target group
|
||||
sourceGroup.moveEditor(editorInput, targetGroup, { index, preserveFocus: true });
|
||||
}
|
||||
|
||||
async $closeTab(tab: IEditorTabDto): Promise<void> {
|
||||
const group = this._editorGroupsService.getGroup(columnToEditorGroup(this._editorGroupsService, tab.viewColumn));
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
const editor = group.editors.find(editor => editor.matches(this._tabToUntypedEditorInput(tab)));
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
return group.closeEditor(editor);
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat, FileOperationError, FileOperationResult, FileSystemProviderErrorCode, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileFolderCopyCapability, FilePermission } from 'vs/platform/files/common/files';
|
||||
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat, FileOperationError, FileOperationResult, FileSystemProviderErrorCode, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileFolderCopyCapability, FilePermission, toFileSystemProviderErrorCode } from 'vs/platform/files/common/files';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../common/extHost.protocol';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
@@ -65,7 +65,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
ctime: stat.ctime,
|
||||
mtime: stat.mtime,
|
||||
size: stat.size,
|
||||
permissions: MainThreadFileSystem._asFilePermission(stat),
|
||||
permissions: stat.readonly ? FilePermission.Readonly : undefined,
|
||||
type: MainThreadFileSystem._asFileType(stat)
|
||||
};
|
||||
}).catch(MainThreadFileSystem._handleError);
|
||||
@@ -96,13 +96,6 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
return res;
|
||||
}
|
||||
|
||||
private static _asFilePermission(stat: IFileStat): FilePermission | undefined {
|
||||
if (stat.readonly) {
|
||||
return FilePermission.Readonly;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
$readFile(uri: UriComponents): Promise<VSBuffer> {
|
||||
return this._fileService.readFile(URI.revive(uri)).then(file => file.value).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
@@ -147,6 +140,11 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
err.name = FileSystemProviderErrorCode.FileExists;
|
||||
break;
|
||||
}
|
||||
} else if (err instanceof Error) {
|
||||
const code = toFileSystemProviderErrorCode(err);
|
||||
if (code !== FileSystemProviderErrorCode.Unknown) {
|
||||
err.name = code;
|
||||
}
|
||||
}
|
||||
|
||||
throw err;
|
||||
|
||||
@@ -89,7 +89,7 @@ export class MainThreadFileSystemEventService {
|
||||
delay: Math.min(timeout / 2, 3000)
|
||||
}, () => {
|
||||
// race extension host event delivery against timeout AND user-cancel
|
||||
const onWillEvent = proxy.$onWillRunFileOperation(operation, files, timeout, token);
|
||||
const onWillEvent = proxy.$onWillRunFileOperation(operation, files, timeout, cts.token);
|
||||
return raceCancellation(onWillEvent, cts.token);
|
||||
}, () => {
|
||||
// user-cancel
|
||||
@@ -100,8 +100,8 @@ export class MainThreadFileSystemEventService {
|
||||
clearTimeout(timer);
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
// cancelled or no reply
|
||||
if (!data || data.edit.edits.length === 0) {
|
||||
// cancelled, no reply, or no edits
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,12 +43,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
const langWordPairs = LanguageConfigurationRegistry.getWordDefinitions();
|
||||
let wordDefinitionDtos: ILanguageWordDefinitionDto[] = [];
|
||||
for (const [languageId, wordDefinition] of langWordPairs) {
|
||||
const language = this._modeService.getLanguageIdentifier(languageId);
|
||||
if (!language) {
|
||||
continue;
|
||||
}
|
||||
wordDefinitionDtos.push({
|
||||
languageId: language.language,
|
||||
languageId: languageId,
|
||||
regexSource: wordDefinition.source,
|
||||
regexFlags: wordDefinition.flags
|
||||
});
|
||||
@@ -56,9 +52,9 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
this._proxy.$setWordDefinitions(wordDefinitionDtos);
|
||||
};
|
||||
LanguageConfigurationRegistry.onDidChange((e) => {
|
||||
const wordDefinition = LanguageConfigurationRegistry.getWordDefinition(e.languageIdentifier.id);
|
||||
const wordDefinition = LanguageConfigurationRegistry.getWordDefinition(e.languageId);
|
||||
this._proxy.$setWordDefinitions([{
|
||||
languageId: e.languageIdentifier.language,
|
||||
languageId: e.languageId,
|
||||
regexSource: wordDefinition.source,
|
||||
regexFlags: wordDefinition.flags
|
||||
}]);
|
||||
@@ -567,10 +563,10 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
this._registrations.set(handle, modes.InlayHintsProviderRegistry.register(selector, provider));
|
||||
}
|
||||
|
||||
$emitInlayHintsEvent(eventHandle: number, event?: any): void {
|
||||
$emitInlayHintsEvent(eventHandle: number): void {
|
||||
const obj = this._registrations.get(eventHandle);
|
||||
if (obj instanceof Emitter) {
|
||||
obj.fire(event);
|
||||
obj.fire(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -776,9 +772,9 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
};
|
||||
}
|
||||
|
||||
const languageIdentifier = this._modeService.getLanguageIdentifier(languageId);
|
||||
if (languageIdentifier) {
|
||||
this._registrations.set(handle, LanguageConfigurationRegistry.register(languageIdentifier, configuration, 100));
|
||||
const validLanguageId = this._modeService.validateLanguageId(languageId);
|
||||
if (validLanguageId) {
|
||||
this._registrations.set(handle, LanguageConfigurationRegistry.register(validLanguageId, configuration, 100));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,38 +6,51 @@
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { MainThreadLanguagesShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { MainThreadLanguagesShape, MainContext, IExtHostContext, ExtHostContext, ExtHostLanguagesShape } from '../common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { StandardTokenType } from 'vs/editor/common/modes';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { ILanguageStatus, ILanguageStatusService } from 'vs/workbench/services/languageStatus/common/languageStatusService';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadLanguages)
|
||||
export class MainThreadLanguages implements MainThreadLanguagesShape {
|
||||
|
||||
private readonly _disposables = new DisposableStore();
|
||||
private readonly _proxy: ExtHostLanguagesShape;
|
||||
|
||||
private readonly _status = new Map<number, IDisposable>();
|
||||
|
||||
constructor(
|
||||
_extHostContext: IExtHostContext,
|
||||
@IModeService private readonly _modeService: IModeService,
|
||||
@IModelService private readonly _modelService: IModelService,
|
||||
@ITextModelService private _resolverService: ITextModelService,
|
||||
@ILanguageStatusService private readonly _languageStatusService: ILanguageStatusService,
|
||||
) { }
|
||||
) {
|
||||
this._proxy = _extHostContext.getProxy(ExtHostContext.ExtHostLanguages);
|
||||
|
||||
dispose(): void {
|
||||
// nothing
|
||||
this._proxy.$acceptLanguageIds(_modeService.getRegisteredModes());
|
||||
this._disposables.add(_modeService.onLanguagesMaybeChanged(e => {
|
||||
this._proxy.$acceptLanguageIds(_modeService.getRegisteredModes());
|
||||
}));
|
||||
}
|
||||
|
||||
$getLanguages(): Promise<string[]> {
|
||||
return Promise.resolve(this._modeService.getRegisteredModes());
|
||||
dispose(): void {
|
||||
this._disposables.dispose();
|
||||
|
||||
for (const status of this._status.values()) {
|
||||
status.dispose();
|
||||
}
|
||||
this._status.clear();
|
||||
}
|
||||
|
||||
async $changeLanguage(resource: UriComponents, languageId: string): Promise<void> {
|
||||
|
||||
const languageIdentifier = this._modeService.getLanguageIdentifier(languageId);
|
||||
if (!languageIdentifier || languageIdentifier.language !== languageId) {
|
||||
const validLanguageId = this._modeService.validateLanguageId(languageId);
|
||||
if (!validLanguageId || validLanguageId !== languageId) {
|
||||
return Promise.reject(new Error(`Unknown language id: ${languageId}`));
|
||||
}
|
||||
|
||||
@@ -67,8 +80,6 @@ export class MainThreadLanguages implements MainThreadLanguagesShape {
|
||||
|
||||
// --- language status
|
||||
|
||||
private readonly _status = new Map<number, IDisposable>();
|
||||
|
||||
$setLanguageStatus(handle: number, status: ILanguageStatus): void {
|
||||
this._status.get(handle)?.dispose();
|
||||
this._status.set(handle, this._languageStatusService.addStatus(status));
|
||||
|
||||
@@ -12,12 +12,10 @@ import { INotebookDecorationRenderOptions } from 'vs/workbench/contrib/notebook/
|
||||
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { EditorActivation, EditorResolution } from 'vs/platform/editor/common/editor';
|
||||
import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput';
|
||||
import { EditorActivation } from 'vs/platform/editor/common/editor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
|
||||
import { columnToEditorGroup, editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
|
||||
import { equals } from 'vs/base/common/objects';
|
||||
import { NotebookDto } from 'vs/workbench/api/browser/mainThreadNotebookDto';
|
||||
|
||||
@@ -45,7 +43,6 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
notebooksAndEditors: MainThreadNotebooksAndEditors,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
@INotebookEditorService private readonly _notebookEditorService: INotebookEditorService,
|
||||
@@ -131,11 +128,10 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
|
||||
// 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,
|
||||
override: EditorResolution.DISABLED
|
||||
override: viewType
|
||||
};
|
||||
|
||||
const input = NotebookEditorInput.create(this._instantiationService, URI.revive(resource), viewType);
|
||||
const editorPane = await this._editorService.openEditor(input, editorOptions, options.position);
|
||||
const editorPane = await this._editorService.openEditor({ resource: URI.revive(resource), options: editorOptions }, columnToEditorGroup(this._editorGroupService, options.position));
|
||||
const notebookEditor = getNotebookEditorFromEditorPane(editorPane);
|
||||
|
||||
if (notebookEditor) {
|
||||
@@ -154,12 +150,13 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
|
||||
if (!notebookEditor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
const viewModel = notebookEditor.viewModel;
|
||||
const cell = viewModel.cellAt(range.start);
|
||||
if (!cell) {
|
||||
|
||||
if (range.start >= notebookEditor.getLength()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cell = notebookEditor.cellAt(range.start);
|
||||
|
||||
switch (revealType) {
|
||||
case NotebookEditorRevealType.Default:
|
||||
return notebookEditor.revealCellRangeInView(range);
|
||||
|
||||
@@ -33,6 +33,7 @@ abstract class MainThreadKernel implements INotebookKernel {
|
||||
label: string;
|
||||
description?: string;
|
||||
detail?: string;
|
||||
kind?: string;
|
||||
supportedLanguages: string[];
|
||||
implementsExecutionOrder: boolean;
|
||||
localResourceRoot: URI;
|
||||
@@ -54,6 +55,7 @@ abstract class MainThreadKernel implements INotebookKernel {
|
||||
this.label = data.label;
|
||||
this.description = data.description;
|
||||
this.detail = data.detail;
|
||||
this.kind = data.kind;
|
||||
this.supportedLanguages = isNonEmptyArray(data.supportedLanguages) ? data.supportedLanguages : _modeService.getRegisteredModes();
|
||||
this.implementsExecutionOrder = data.supportsExecutionOrder ?? false;
|
||||
this.localResourceRoot = URI.revive(data.extensionLocation);
|
||||
@@ -76,6 +78,10 @@ abstract class MainThreadKernel implements INotebookKernel {
|
||||
this.detail = data.detail;
|
||||
event.detail = true;
|
||||
}
|
||||
if (data.kind !== undefined) {
|
||||
this.kind = data.kind;
|
||||
event.kind = true;
|
||||
}
|
||||
if (data.supportedLanguages !== undefined) {
|
||||
this.supportedLanguages = isNonEmptyArray(data.supportedLanguages) ? data.supportedLanguages : this._modeService.getRegisteredModes();
|
||||
event.supportedLanguages = true;
|
||||
|
||||
@@ -40,7 +40,7 @@ export class MainThreadProgress implements MainThreadProgressShape {
|
||||
this._progress.clear();
|
||||
}
|
||||
|
||||
$startProgress(handle: number, options: IProgressOptions, extension?: IExtensionDescription): void {
|
||||
async $startProgress(handle: number, options: IProgressOptions, extension?: IExtensionDescription): Promise<void> {
|
||||
const task = this._createTask(handle);
|
||||
|
||||
if (options.location === ProgressLocation.Notification && extension && !extension.isUnderDevelopment) {
|
||||
|
||||
@@ -120,6 +120,7 @@ class MainThreadSCMProvider implements ISCMProvider {
|
||||
|
||||
get commitTemplate(): string { return this.features.commitTemplate || ''; }
|
||||
get acceptInputCommand(): Command | undefined { return this.features.acceptInputCommand; }
|
||||
get actionButton(): Command | undefined { return this.features.actionButton ?? undefined; }
|
||||
get statusBarCommands(): Command[] | undefined { return this.features.statusBarCommands; }
|
||||
get count(): number | undefined { return this.features.count; }
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { IFileMatch, IFileQuery, IRawFileMatch2, ISearchComplete, ISearchCompleteStats, ISearchProgressItem, ISearchResultProvider, ISearchService, ITextQuery, QueryType, SearchProviderType } from 'vs/workbench/services/search/common/search';
|
||||
import { IFileMatch, IFileQuery, IRawFileMatch2, ISearchComplete, ISearchCompleteStats, ISearchConfiguration, ISearchProgressItem, ISearchResultProvider, ISearchService, ITextQuery, QueryType, SearchProviderType } from 'vs/workbench/services/search/common/search';
|
||||
import { ExtHostContext, ExtHostSearchShape, IExtHostContext, MainContext, MainThreadSearchShape } from '../common/extHost.protocol';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadSearch)
|
||||
@@ -26,8 +26,8 @@ export class MainThreadSearch implements MainThreadSearchShape {
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostSearch);
|
||||
|
||||
const forceEHSearch = _configurationService.getValue('search.experimental.forceExtensionHostSearch');
|
||||
if (forceEHSearch) {
|
||||
const searchConfig = _configurationService.getValue<ISearchConfiguration>().search;
|
||||
if (!searchConfig.forceSearchProcess) {
|
||||
this._proxy.$enableExtensionHostSearch();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar';
|
||||
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor, IStatusbarEntry, StatusbarAlignment } from 'vs/workbench/services/statusbar/browser/statusbar';
|
||||
import { MainThreadStatusBarShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
@@ -28,7 +28,7 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
|
||||
this.entries.clear();
|
||||
}
|
||||
|
||||
$setEntry(entryId: number, id: string, name: string, text: string, tooltip: IMarkdownString | string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void {
|
||||
$setEntry(entryId: number, id: string, name: string, text: string, tooltip: IMarkdownString | string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignLeft: boolean, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void {
|
||||
// if there are icons in the text use the tooltip for the aria label
|
||||
let ariaLabel: string;
|
||||
let role: string | undefined = undefined;
|
||||
@@ -48,6 +48,8 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
|
||||
priority = 0;
|
||||
}
|
||||
|
||||
const alignment = alignLeft ? StatusbarAlignment.LEFT : StatusbarAlignment.RIGHT;
|
||||
|
||||
// Reset existing entry if alignment or priority changed
|
||||
let existingEntry = this.entries.get(entryId);
|
||||
if (existingEntry && (existingEntry.alignment !== alignment || existingEntry.priority !== priority)) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { MainThreadStorageShape, MainContext, IExtHostContext, ExtHostStorageSha
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionIdWithVersion, IExtensionsStorageSyncService } from 'vs/platform/userDataSync/common/extensionsStorageSync';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadStorage)
|
||||
export class MainThreadStorage implements MainThreadStorageShape {
|
||||
@@ -22,6 +23,7 @@ export class MainThreadStorage implements MainThreadStorageShape {
|
||||
extHostContext: IExtHostContext,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IExtensionsStorageSyncService extensionsStorageSyncService: IExtensionsStorageSyncService,
|
||||
@ILogService private readonly _logService: ILogService
|
||||
) {
|
||||
this._storageService = storageService;
|
||||
this._extensionsStorageSyncService = extensionsStorageSyncService;
|
||||
@@ -30,11 +32,7 @@ export class MainThreadStorage implements MainThreadStorageShape {
|
||||
this._storageListener = this._storageService.onDidChangeValue(e => {
|
||||
const shared = e.scope === StorageScope.GLOBAL;
|
||||
if (shared && this._sharedStorageKeysToWatch.has(e.key)) {
|
||||
try {
|
||||
this._proxy.$acceptValue(shared, e.key, this._getValue(shared, e.key));
|
||||
} catch (error) {
|
||||
// ignore parsing errors that can happen
|
||||
}
|
||||
this._proxy.$acceptValue(shared, e.key, this._getValue(shared, e.key));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -43,35 +41,30 @@ export class MainThreadStorage implements MainThreadStorageShape {
|
||||
this._storageListener.dispose();
|
||||
}
|
||||
|
||||
$getValue<T>(shared: boolean, key: string): Promise<T | undefined> {
|
||||
async $getValue<T>(shared: boolean, key: string): Promise<T | undefined> {
|
||||
if (shared) {
|
||||
this._sharedStorageKeysToWatch.set(key, true);
|
||||
}
|
||||
try {
|
||||
return Promise.resolve(this._getValue<T>(shared, key));
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
return this._getValue<T>(shared, key);
|
||||
}
|
||||
|
||||
private _getValue<T>(shared: boolean, key: string): T | undefined {
|
||||
const jsonValue = this._storageService.get(key, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE);
|
||||
if (!jsonValue) {
|
||||
return undefined;
|
||||
if (jsonValue) {
|
||||
try {
|
||||
return JSON.parse(jsonValue);
|
||||
} catch (error) {
|
||||
// Do not fail this call but log it for diagnostics
|
||||
// https://github.com/microsoft/vscode/issues/132777
|
||||
this._logService.error(`[mainThreadStorage] unexpected error parsing storage contents (key: ${key}, shared: ${shared}): ${error}`);
|
||||
}
|
||||
}
|
||||
return JSON.parse(jsonValue);
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
$setValue(shared: boolean, key: string, value: object): Promise<void> {
|
||||
let jsonValue: string;
|
||||
try {
|
||||
jsonValue = JSON.stringify(value);
|
||||
// Extension state is synced separately through extensions
|
||||
this._storageService.store(key, jsonValue, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE, StorageTarget.MACHINE);
|
||||
} catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
async $setValue(shared: boolean, key: string, value: object): Promise<void> {
|
||||
this._storageService.store(key, JSON.stringify(value), shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE, StorageTarget.MACHINE /* Extension state is synced separately through extensions */);
|
||||
}
|
||||
|
||||
$registerExtensionStorageKeysToSync(extension: IExtensionIdWithVersion, keys: string[]): void {
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ITelemetryService, TelemetryLevel, TELEMETRY_OLD_SETTING_ID, TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { MainThreadTelemetryShape, MainContext, IExtHostContext, ExtHostTelemetryShape, ExtHostContext } from '../common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { getTelemetryLevel, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadTelemetry)
|
||||
export class MainThreadTelemetry extends Disposable implements MainThreadTelemetryShape {
|
||||
@@ -17,20 +19,29 @@ export class MainThreadTelemetry extends Disposable implements MainThreadTelemet
|
||||
|
||||
private static readonly _name = 'pluginHostTelemetry';
|
||||
|
||||
private _oldTelemetryEnabledValue: boolean | undefined;
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IEnvironmentService private readonly _environmenService: IEnvironmentService,
|
||||
@IProductService private readonly _productService: IProductService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTelemetry);
|
||||
|
||||
if (!this._environmenService.disableTelemetry) {
|
||||
if (supportsTelemetry(this._productService, this._environmenService)) {
|
||||
this._register(this._configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectedKeys.includes('telemetry.enableTelemetry')) {
|
||||
this._proxy.$onDidChangeTelemetryEnabled(this.telemetryEnabled);
|
||||
if (e.affectsConfiguration(TELEMETRY_SETTING_ID) || e.affectsConfiguration(TELEMETRY_OLD_SETTING_ID)) {
|
||||
const telemetryEnabled = this.telemetryEnabled;
|
||||
// Since changing telemetryLevel from "off" => "error" doesn't change the isEnabled state
|
||||
// We shouldn't fire a change event
|
||||
if (telemetryEnabled !== this._oldTelemetryEnabledValue) {
|
||||
this._oldTelemetryEnabledValue = telemetryEnabled;
|
||||
this._proxy.$onDidChangeTelemetryEnabled(this.telemetryEnabled);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -39,11 +50,11 @@ export class MainThreadTelemetry extends Disposable implements MainThreadTelemet
|
||||
}
|
||||
|
||||
private get telemetryEnabled(): boolean {
|
||||
if (this._environmenService.disableTelemetry) {
|
||||
if (!supportsTelemetry(this._productService, this._environmenService)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !!this._configurationService.getValue('telemetry.enableTelemetry');
|
||||
return getTelemetryLevel(this._configurationService) === TelemetryLevel.USAGE;
|
||||
}
|
||||
|
||||
$publicLog(eventName: string, data: any = Object.create(null)): void {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, TerminalLocation, TitleEventSource } from 'vs/platform/terminal/common/terminal';
|
||||
import { IProcessProperty, IShellLaunchConfig, IShellLaunchConfigDto, ProcessPropertyType, TerminalLocation, TitleEventSource } from 'vs/platform/terminal/common/terminal';
|
||||
import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';
|
||||
import { ITerminalEditorService, ITerminalExternalLinkProvider, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalLink, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { TerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy';
|
||||
@@ -21,6 +21,7 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { OperatingSystem, OS } from 'vs/base/common/platform';
|
||||
import { TerminalEditorLocationOptions } from 'vscode';
|
||||
import { Promises } from 'vs/base/common/async';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
|
||||
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
|
||||
@@ -140,16 +141,20 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
isExtensionOwnedTerminal: launchConfig.isExtensionOwnedTerminal,
|
||||
useShellEnvironment: launchConfig.useShellEnvironment,
|
||||
};
|
||||
this._extHostTerminals.set(extHostTerminalId, new Promise(async r => {
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
|
||||
const terminal = Promises.withAsyncBody<ITerminalInstance>(async r => {
|
||||
const terminal = await this._terminalService.createTerminal({
|
||||
config: shellLaunchConfig,
|
||||
location: await this._deserializeParentTerminal(launchConfig.location)
|
||||
});
|
||||
r(terminal);
|
||||
}));
|
||||
});
|
||||
this._extHostTerminals.set(extHostTerminalId, terminal);
|
||||
await terminal;
|
||||
}
|
||||
|
||||
private async _deserializeParentTerminal(location?: TerminalLocation | TerminalEditorLocationOptions | { parentTerminal: ExtHostTerminalIdentifier } | { splitActiveTerminal: boolean }): Promise<TerminalLocation | TerminalEditorLocationOptions | { parentTerminal: ITerminalInstance } | { splitActiveTerminal: boolean } | undefined> {
|
||||
private async _deserializeParentTerminal(location?: TerminalLocation | TerminalEditorLocationOptions | { parentTerminal: ExtHostTerminalIdentifier } | { splitActiveTerminal: boolean, location?: TerminalLocation }): Promise<TerminalLocation | TerminalEditorLocationOptions | { parentTerminal: ITerminalInstance } | { splitActiveTerminal: boolean } | undefined> {
|
||||
if (typeof location === 'object' && 'parentTerminal' in location) {
|
||||
const parentTerminal = await this._extHostTerminals.get(location.parentTerminal.toString());
|
||||
return parentTerminal ? { parentTerminal } : undefined;
|
||||
@@ -186,6 +191,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
await instance?.sendText(text, addNewLine);
|
||||
}
|
||||
|
||||
public $sendProcessExit(terminalId: number, exitCode: number | undefined): void {
|
||||
this._terminalProcessProxies.get(terminalId)?.emitExit(exitCode);
|
||||
}
|
||||
|
||||
public $startSendingDataEvents(): void {
|
||||
if (!this._dataEventTracker) {
|
||||
this._dataEventTracker = this._instantiationService.createInstance(TerminalDataEventTracker, (id, data) => {
|
||||
@@ -298,18 +307,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
proxy.onRequestLatency(() => this._onRequestLatency(proxy.instanceId));
|
||||
}
|
||||
|
||||
public $sendProcessTitle(terminalId: number, title: string): void {
|
||||
// Since title events can only come from vscode.Pseudoterminals right now, these are routed
|
||||
// directly to the instance as API source events such that they will replace the initial
|
||||
// `name` property provided for the Pseudoterminal. If we support showing both Api and
|
||||
// Process titles at the same time we may want to pass this through as a Process source
|
||||
// event.
|
||||
const instance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (instance) {
|
||||
instance.setTitle(title, TitleEventSource.Api);
|
||||
}
|
||||
}
|
||||
|
||||
public $sendProcessData(terminalId: number, data: string): void {
|
||||
this._terminalProcessProxies.get(terminalId)?.emitData(data);
|
||||
}
|
||||
@@ -318,24 +315,14 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
this._terminalProcessProxies.get(terminalId)?.emitReady(pid, cwd);
|
||||
}
|
||||
|
||||
public $sendProcessExit(terminalId: number, exitCode: number | undefined): void {
|
||||
this._terminalProcessProxies.get(terminalId)?.emitExit(exitCode);
|
||||
}
|
||||
|
||||
public $sendOverrideDimensions(terminalId: number, dimensions: ITerminalDimensions | undefined): void {
|
||||
this._terminalProcessProxies.get(terminalId)?.emitOverrideDimensions(dimensions);
|
||||
}
|
||||
|
||||
public $sendProcessInitialCwd(terminalId: number, initialCwd: string): void {
|
||||
this._terminalProcessProxies.get(terminalId)?.emitInitialCwd(initialCwd);
|
||||
}
|
||||
|
||||
public $sendProcessCwd(terminalId: number, cwd: string): void {
|
||||
this._terminalProcessProxies.get(terminalId)?.emitCwd(cwd);
|
||||
}
|
||||
|
||||
public $sendResolvedLaunchConfig(terminalId: number, shellLaunchConfig: IShellLaunchConfig): void {
|
||||
this._getTerminalProcess(terminalId)?.emitResolvedShellLaunchConfig(shellLaunchConfig);
|
||||
public $sendProcessProperty(terminalId: number, property: IProcessProperty<any>): void {
|
||||
if (property.type === ProcessPropertyType.Title) {
|
||||
const instance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (instance) {
|
||||
instance.refreshTabLabels(property.value, TitleEventSource.Api);
|
||||
}
|
||||
}
|
||||
this._terminalProcessProxies.get(terminalId)?.emitProcessProperty(property);
|
||||
}
|
||||
|
||||
private async _onRequestLatency(terminalId: number): Promise<void> {
|
||||
|
||||
@@ -11,7 +11,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { MutableObservableValue } from 'vs/workbench/contrib/testing/common/observableValue';
|
||||
import { ExtensionRunTestsRequest, ITestItem, ITestMessage, ITestRunProfile, ITestRunTask, ResolvedTestRunRequest, TestDiffOpType, TestResultState, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { ExtensionRunTestsRequest, ITestItem, ITestMessage, ITestRunProfile, ITestRunTask, ResolvedTestRunRequest, SerializedTestMessage, TestDiffOpType, TestResultState, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { ITestProfileService } from 'vs/workbench/contrib/testing/common/testProfileService';
|
||||
import { TestCoverage } from 'vs/workbench/contrib/testing/common/testCoverage';
|
||||
import { LiveTestResult } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
@@ -176,7 +176,7 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $appendTestMessagesInRun(runId: string, taskId: string, testId: string, messages: ITestMessage[]): void {
|
||||
public $appendTestMessagesInRun(runId: string, taskId: string, testId: string, messages: SerializedTestMessage[]): void {
|
||||
const r = this.resultService.getResult(runId);
|
||||
if (r && r instanceof LiveTestResult) {
|
||||
for (const message of messages) {
|
||||
@@ -185,7 +185,7 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh
|
||||
message.location.range = Range.lift(message.location.range);
|
||||
}
|
||||
|
||||
r.appendMessage(testId, taskId, message);
|
||||
r.appendMessage(testId, taskId, message as ITestMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,6 +177,7 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
|
||||
localAddress: typeof tunnel.localAddress === 'string' ? tunnel.localAddress : makeAddress(tunnel.localAddress.host, tunnel.localAddress.port),
|
||||
tunnelLocalPort: typeof tunnel.localAddress !== 'string' ? tunnel.localAddress.port : undefined,
|
||||
public: tunnel.public,
|
||||
privacy: tunnel.privacy,
|
||||
protocol: tunnel.protocol ?? TunnelProtocol.Http,
|
||||
dispose: async (silent?: boolean) => {
|
||||
this.logService.trace(`ForwardedPorts: (MainThreadTunnelService) Closing tunnel from tunnel provider: ${tunnel?.remoteAddress.host}:${tunnel?.remoteAddress.port}`);
|
||||
|
||||
@@ -9,7 +9,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { MainThreadWebviews, reviveWebviewContentOptions, reviveWebviewExtension } from 'vs/workbench/api/browser/mainThreadWebviews';
|
||||
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { EditorGroupColumn, columnToEditorGroup, editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
@@ -263,14 +263,14 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc
|
||||
this._revivers.delete(viewType);
|
||||
}
|
||||
|
||||
private updateWebviewViewStates(activeEditorInput: IEditorInput | undefined) {
|
||||
private updateWebviewViewStates(activeEditorInput: EditorInput | undefined) {
|
||||
if (!this._webviewInputs.size) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewStates: extHostProtocol.WebviewPanelViewStateData = {};
|
||||
|
||||
const updateViewStatesForInput = (group: IEditorGroup, topLevelInput: IEditorInput, editorInput: IEditorInput) => {
|
||||
const updateViewStatesForInput = (group: IEditorGroup, topLevelInput: EditorInput, editorInput: EditorInput) => {
|
||||
if (!(editorInput instanceof WebviewInput)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@ export function reviveWebviewExtension(extensionData: extHostProtocol.WebviewExt
|
||||
export function reviveWebviewContentOptions(webviewOptions: extHostProtocol.IWebviewOptions): WebviewContentOptions {
|
||||
return {
|
||||
allowScripts: webviewOptions.enableScripts,
|
||||
allowForms: webviewOptions.enableForms,
|
||||
enableCommandUris: webviewOptions.enableCommandUris,
|
||||
localResourceRoots: Array.isArray(webviewOptions.localResourceRoots) ? webviewOptions.localResourceRoots.map(r => URI.revive(r)) : undefined,
|
||||
portMapping: webviewOptions.portMapping,
|
||||
|
||||
@@ -54,7 +54,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
const workspace = this._contextService.getWorkspace();
|
||||
// The workspace file is provided be a unknown file system provider. It might come
|
||||
// from the extension host. So initialize now knowing that `rootPath` is undefined.
|
||||
if (workspace.configuration && !isNative && !fileService.canHandleResource(workspace.configuration)) {
|
||||
if (workspace.configuration && !isNative && !fileService.hasProvider(workspace.configuration)) {
|
||||
this._proxy.$initializeWorkspace(this.getWorkspaceData(workspace), this.isWorkspaceTrusted());
|
||||
} else {
|
||||
this._contextService.getCompleteWorkspace().then(workspace => this._proxy.$initializeWorkspace(this.getWorkspaceData(workspace), this.isWorkspaceTrusted()));
|
||||
@@ -129,7 +129,8 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
isUntitled: workspace.configuration ? isUntitledWorkspace(workspace.configuration, this._environmentService) : false,
|
||||
folders: workspace.folders,
|
||||
id: workspace.id,
|
||||
name: this._labelService.getWorkspaceLabel(workspace)
|
||||
name: this._labelService.getWorkspaceLabel(workspace),
|
||||
transient: workspace.transient
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,11 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { Extensions as ViewletExtensions, PaneCompositeRegistry } from 'vs/workbench/browser/panecomposite';
|
||||
import { CustomTreeView, TreeViewPane } from 'vs/workbench/browser/parts/views/treeView';
|
||||
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
import { Extensions as ViewletExtensions, ViewletRegistry } from 'vs/workbench/browser/viewlet';
|
||||
import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { Extensions as ViewContainerExtensions, ITreeViewDescriptor, IViewContainersRegistry, IViewDescriptor, IViewsRegistry, ViewContainer, ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { Extensions as ViewContainerExtensions, ICustomTreeViewDescriptor, ICustomViewDescriptor, IViewContainersRegistry, IViewDescriptor, IViewsRegistry, ViewContainer, ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { VIEWLET_ID as DEBUG } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { VIEWLET_ID as EXPLORER } from 'vs/workbench/contrib/files/common/files';
|
||||
import { VIEWLET_ID as REMOTE } from 'vs/workbench/contrib/remote/browser/remoteExplorer';
|
||||
@@ -234,18 +234,6 @@ const viewsContribution: IJSONSchema = {
|
||||
}
|
||||
};
|
||||
|
||||
export interface ICustomTreeViewDescriptor extends ITreeViewDescriptor {
|
||||
readonly extensionId: ExtensionIdentifier;
|
||||
readonly originalContainerId: string;
|
||||
}
|
||||
|
||||
export interface ICustomWebviewViewDescriptor extends IViewDescriptor {
|
||||
readonly extensionId: ExtensionIdentifier;
|
||||
readonly originalContainerId: string;
|
||||
}
|
||||
|
||||
export type ICustomViewDescriptor = ICustomTreeViewDescriptor | ICustomWebviewViewDescriptor;
|
||||
|
||||
type ViewContainerExtensionPointType = { [loc: string]: IUserFriendlyViewsContainerDescriptor[] };
|
||||
const viewsContainersExtensionPoint: IExtensionPoint<ViewContainerExtensionPointType> = ExtensionsRegistry.registerExtensionPoint<ViewContainerExtensionPointType>({
|
||||
extensionPoint: 'viewsContainers',
|
||||
@@ -398,7 +386,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
|
||||
private deregisterCustomViewContainer(viewContainer: ViewContainer): void {
|
||||
this.viewContainersRegistry.deregisterViewContainer(viewContainer);
|
||||
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).deregisterViewlet(viewContainer.id);
|
||||
Registry.as<PaneCompositeRegistry>(ViewletExtensions.Viewlets).deregisterPaneComposite(viewContainer.id);
|
||||
}
|
||||
|
||||
private handleAndRegisterCustomViews() {
|
||||
|
||||
Reference in New Issue
Block a user