mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-09 01:32:34 -05:00
Merge from vscode fc10e26ea50f82cdd84e9141491357922e6f5fba (#4639)
This commit is contained in:
@@ -6,10 +6,10 @@
|
||||
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, parse } from 'vs/base/node/console';
|
||||
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/electron-browser/extensionHost';
|
||||
import { IRemoteConsoleLog, log, parse } from 'vs/base/common/console';
|
||||
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
|
||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { IBroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService';
|
||||
import { IBroadcastService } from 'vs/workbench/services/broadcast/common/broadcast';
|
||||
import { EXTENSION_LOG_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadConsole)
|
||||
@@ -41,14 +41,14 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon
|
||||
|
||||
$registerTextContentProvider(handle: number, scheme: string): void {
|
||||
const registration = this._textModelResolverService.registerTextModelContentProvider(scheme, {
|
||||
provideTextContent: (uri: URI): Promise<ITextModel | undefined> => {
|
||||
provideTextContent: (uri: URI): Promise<ITextModel | null> => {
|
||||
return this._proxy.$provideTextDocumentContent(handle, uri).then(value => {
|
||||
if (typeof value === 'string') {
|
||||
const firstLineText = value.substr(0, 1 + value.search(/\r?\n/));
|
||||
const languageSelection = this._modeService.createByFilepathOrFirstLine(uri.fsPath, firstLineText);
|
||||
return this._modelService.createModel(value, languageSelection, uri);
|
||||
}
|
||||
return undefined;
|
||||
return null;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IModelService, shouldSynchronizeModel } from 'vs/editor/common/services/modelService';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors';
|
||||
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors';
|
||||
import { ExtHostContext, ExtHostDocumentsShape, IExtHostContext, MainThreadDocumentsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ITextEditorModel } from 'vs/workbench/common/editor';
|
||||
import { ITextFileService, TextFileModelChangeEvent } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
@@ -17,9 +17,9 @@ import { IModelService, shouldSynchronizeModel } from 'vs/editor/common/services
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { MainThreadDocuments } from 'vs/workbench/api/electron-browser/mainThreadDocuments';
|
||||
import { MainThreadTextEditor } from 'vs/workbench/api/electron-browser/mainThreadEditor';
|
||||
import { MainThreadTextEditors } from 'vs/workbench/api/electron-browser/mainThreadEditors';
|
||||
import { MainThreadDocuments } from 'vs/workbench/api/browser/mainThreadDocuments';
|
||||
import { MainThreadTextEditor } from 'vs/workbench/api/browser/mainThreadEditor';
|
||||
import { MainThreadTextEditors } from 'vs/workbench/api/browser/mainThreadEditors';
|
||||
import { ExtHostContext, ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, IExtHostContext, IModelAddedData, ITextEditorAddData, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { EditorViewColumn, editorGroupToViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
|
||||
@@ -18,14 +18,12 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors';
|
||||
import { MainThreadTextEditor } from 'vs/workbench/api/electron-browser/mainThreadEditor';
|
||||
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors';
|
||||
import { MainThreadTextEditor } from 'vs/workbench/api/browser/mainThreadEditor';
|
||||
import { ExtHostContext, ExtHostEditorsShape, IApplyEditsOptions, IExtHostContext, ITextDocumentShowOptions, ITextEditorConfigurationUpdate, ITextEditorPositionData, IUndoStopOptions, MainThreadTextEditorsShape, TextEditorRevealType, WorkspaceEditDto, reviveWorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { EditorViewColumn, editorGroupToViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
|
||||
export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
|
||||
@@ -270,7 +268,6 @@ CommandsRegistry.registerCommand('_workbench.open', function (accessor: Services
|
||||
const editorService = accessor.get(IEditorService);
|
||||
const editorGroupService = accessor.get(IEditorGroupsService);
|
||||
const openerService = accessor.get(IOpenerService);
|
||||
const urlService = accessor.get(IURLService);
|
||||
|
||||
const [resource, options, position, label] = args;
|
||||
|
||||
@@ -282,12 +279,8 @@ CommandsRegistry.registerCommand('_workbench.open', function (accessor: Services
|
||||
if (resource && resource.scheme === 'command') {
|
||||
// do not allow to execute commands from here
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
if (resource && (resource.scheme === product.urlProtocol || /^vscode/.test(resource.scheme))) {
|
||||
return urlService.open(resource).then(_ => undefined);
|
||||
}
|
||||
|
||||
// finally, delegate to opener service
|
||||
return openerService.open(resource).then(_ => undefined);
|
||||
});
|
||||
@@ -8,7 +8,6 @@ import Severity from 'vs/base/common/severity';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { IExtHostContext, MainContext, MainThreadExtensionServiceShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IExtensionService, ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionService } from 'vs/workbench/services/extensions/electron-browser/extensionService';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -17,11 +16,12 @@ import { EnablementState } from 'vs/platform/extensionManagement/common/extensio
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { IExtensionsWorkbenchService, IExtension } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadExtensionService)
|
||||
export class MainThreadExtensionService implements MainThreadExtensionServiceShape {
|
||||
|
||||
private readonly _extensionService: ExtensionService;
|
||||
private readonly _extensionService: IExtensionService;
|
||||
private readonly _notificationService: INotificationService;
|
||||
private readonly _extensionsWorkbenchService: IExtensionsWorkbenchService;
|
||||
private readonly _windowService: IWindowService;
|
||||
@@ -33,9 +33,7 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha
|
||||
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IWindowService windowService: IWindowService
|
||||
) {
|
||||
if (extensionService instanceof ExtensionService) {
|
||||
this._extensionService = extensionService;
|
||||
}
|
||||
this._extensionService = extensionService;
|
||||
this._notificationService = notificationService;
|
||||
this._extensionsWorkbenchService = extensionsWorkbenchService;
|
||||
this._windowService = windowService;
|
||||
@@ -108,7 +106,7 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha
|
||||
|
||||
private async _handleMissingNotInstalledDependency(extension: IExtensionDescription, missingDependency: string): Promise<void> {
|
||||
const extName = extension.displayName || extension.name;
|
||||
const dependencyExtension = (await this._extensionsWorkbenchService.queryGallery({ names: [missingDependency] })).firstPage[0];
|
||||
const dependencyExtension = (await this._extensionsWorkbenchService.queryGallery({ names: [missingDependency] }, CancellationToken.None)).firstPage[0];
|
||||
if (dependencyExtension) {
|
||||
this._notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
@@ -124,4 +122,7 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha
|
||||
}
|
||||
}
|
||||
|
||||
$onExtensionHostExit(code: number): void {
|
||||
this._extensionService._onExtensionHostExit(code);
|
||||
}
|
||||
}
|
||||
25
src/vs/workbench/api/browser/mainThreadHeapService.ts
Normal file
25
src/vs/workbench/api/browser/mainThreadHeapService.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtHostContext, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { IHeapService } from 'vs/workbench/services/heap/common/heap';
|
||||
|
||||
@extHostCustomer
|
||||
export class MainThreadHeapService extends Disposable {
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IHeapService heapService: IHeapService,
|
||||
) {
|
||||
super();
|
||||
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostHeapService);
|
||||
this._register(heapService.onGarbageCollection((ids) => {
|
||||
// send to ext host
|
||||
proxy.$onGarbageCollection(ids);
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -14,15 +14,14 @@ import { Range as EditorRange } from 'vs/editor/common/core/range';
|
||||
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, WorkspaceSymbolDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter, DefinitionLinkDto, ISerializedSignatureHelpProviderMetadata, CodeInsetDto, LinkDto, CallHierarchyDto } from '../common/extHost.protocol';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { IHeapService } from './mainThreadHeapService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { IHeapService } from 'vs/workbench/services/heap/common/heap';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
|
||||
export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape {
|
||||
@@ -127,7 +126,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
// --- outline
|
||||
|
||||
$registerDocumentSymbolProvider(handle: number, selector: ISerializedDocumentFilter[], displayName: string): void {
|
||||
this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentSymbolProvider>{
|
||||
this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(selector, <modes.DocumentSymbolProvider>{
|
||||
displayName,
|
||||
provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Promise<modes.DocumentSymbol[] | undefined> => {
|
||||
return this._proxy.$provideDocumentSymbols(handle, model.uri, token);
|
||||
@@ -168,7 +167,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
provider.onDidChange = emitter.event;
|
||||
}
|
||||
|
||||
this._registrations[handle] = modes.CodeLensProviderRegistry.register(typeConverters.LanguageSelector.from(selector), provider);
|
||||
this._registrations[handle] = modes.CodeLensProviderRegistry.register(selector, provider);
|
||||
}
|
||||
|
||||
$emitCodeLensEvent(eventHandle: number, event?: any): void {
|
||||
@@ -203,14 +202,14 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
provider.onDidChange = emitter.event;
|
||||
}
|
||||
|
||||
const langSelector = typeConverters.LanguageSelector.from(selector);
|
||||
const langSelector = selector;
|
||||
this._registrations[handle] = codeInset.CodeInsetProviderRegistry.register(langSelector, provider);
|
||||
}
|
||||
|
||||
// --- declaration
|
||||
|
||||
$registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.DefinitionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DefinitionProvider>{
|
||||
this._registrations[handle] = modes.DefinitionProviderRegistry.register(selector, <modes.DefinitionProvider>{
|
||||
provideDefinition: (model, position, token): Promise<modes.LocationLink[]> => {
|
||||
return this._proxy.$provideDefinition(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);
|
||||
}
|
||||
@@ -218,7 +217,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}
|
||||
|
||||
$registerDeclarationSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.DeclarationProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DeclarationProvider>{
|
||||
this._registrations[handle] = modes.DeclarationProviderRegistry.register(selector, <modes.DeclarationProvider>{
|
||||
provideDeclaration: (model, position, token) => {
|
||||
return this._proxy.$provideDeclaration(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);
|
||||
}
|
||||
@@ -226,7 +225,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}
|
||||
|
||||
$registerImplementationSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.ImplementationProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.ImplementationProvider>{
|
||||
this._registrations[handle] = modes.ImplementationProviderRegistry.register(selector, <modes.ImplementationProvider>{
|
||||
provideImplementation: (model, position, token): Promise<modes.LocationLink[]> => {
|
||||
return this._proxy.$provideImplementation(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);
|
||||
}
|
||||
@@ -234,7 +233,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}
|
||||
|
||||
$registerTypeDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.TypeDefinitionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.TypeDefinitionProvider>{
|
||||
this._registrations[handle] = modes.TypeDefinitionProviderRegistry.register(selector, <modes.TypeDefinitionProvider>{
|
||||
provideTypeDefinition: (model, position, token): Promise<modes.LocationLink[]> => {
|
||||
return this._proxy.$provideTypeDefinition(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);
|
||||
}
|
||||
@@ -244,7 +243,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
// --- extra info
|
||||
|
||||
$registerHoverProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.HoverProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.HoverProvider>{
|
||||
this._registrations[handle] = modes.HoverProviderRegistry.register(selector, <modes.HoverProvider>{
|
||||
provideHover: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.Hover | undefined> => {
|
||||
return this._proxy.$provideHover(handle, model.uri, position, token);
|
||||
}
|
||||
@@ -254,7 +253,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
// --- occurrences
|
||||
|
||||
$registerDocumentHighlightProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.DocumentHighlightProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentHighlightProvider>{
|
||||
this._registrations[handle] = modes.DocumentHighlightProviderRegistry.register(selector, <modes.DocumentHighlightProvider>{
|
||||
provideDocumentHighlights: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.DocumentHighlight[] | undefined> => {
|
||||
return this._proxy.$provideDocumentHighlights(handle, model.uri, position, token);
|
||||
}
|
||||
@@ -264,7 +263,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
// --- references
|
||||
|
||||
$registerReferenceSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.ReferenceProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.ReferenceProvider>{
|
||||
this._registrations[handle] = modes.ReferenceProviderRegistry.register(selector, <modes.ReferenceProvider>{
|
||||
provideReferences: (model: ITextModel, position: EditorPosition, context: modes.ReferenceContext, token: CancellationToken): Promise<modes.Location[]> => {
|
||||
return this._proxy.$provideReferences(handle, model.uri, position, context, token).then(MainThreadLanguageFeatures._reviveLocationDto);
|
||||
}
|
||||
@@ -274,7 +273,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
// --- quick fix
|
||||
|
||||
$registerQuickFixSupport(handle: number, selector: ISerializedDocumentFilter[], providedCodeActionKinds?: string[]): void {
|
||||
this._registrations[handle] = modes.CodeActionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.CodeActionProvider>{
|
||||
this._registrations[handle] = modes.CodeActionProviderRegistry.register(selector, <modes.CodeActionProvider>{
|
||||
provideCodeActions: (model: ITextModel, rangeOrSelection: EditorRange | Selection, context: modes.CodeActionContext, token: CancellationToken): Promise<modes.CodeAction[]> => {
|
||||
return this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context, token).then(dto => {
|
||||
if (dto) {
|
||||
@@ -290,7 +289,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
// --- formatting
|
||||
|
||||
$registerDocumentFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], extensionId: ExtensionIdentifier): void {
|
||||
this._registrations[handle] = modes.DocumentFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentFormattingEditProvider>{
|
||||
this._registrations[handle] = modes.DocumentFormattingEditProviderRegistry.register(selector, <modes.DocumentFormattingEditProvider>{
|
||||
extensionId,
|
||||
provideDocumentFormattingEdits: (model: ITextModel, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined> => {
|
||||
return this._proxy.$provideDocumentFormattingEdits(handle, model.uri, options, token);
|
||||
@@ -299,7 +298,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}
|
||||
|
||||
$registerRangeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], extensionId: ExtensionIdentifier): void {
|
||||
this._registrations[handle] = modes.DocumentRangeFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentRangeFormattingEditProvider>{
|
||||
this._registrations[handle] = modes.DocumentRangeFormattingEditProviderRegistry.register(selector, <modes.DocumentRangeFormattingEditProvider>{
|
||||
extensionId,
|
||||
provideDocumentRangeFormattingEdits: (model: ITextModel, range: EditorRange, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined> => {
|
||||
return this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options, token);
|
||||
@@ -308,7 +307,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}
|
||||
|
||||
$registerOnTypeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void {
|
||||
this._registrations[handle] = modes.OnTypeFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.OnTypeFormattingEditProvider>{
|
||||
this._registrations[handle] = modes.OnTypeFormattingEditProviderRegistry.register(selector, <modes.OnTypeFormattingEditProvider>{
|
||||
extensionId,
|
||||
autoFormatTriggerCharacters,
|
||||
provideOnTypeFormattingEdits: (model: ITextModel, position: EditorPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined> => {
|
||||
@@ -346,7 +345,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
|
||||
$registerRenameSupport(handle: number, selector: ISerializedDocumentFilter[], supportResolveLocation: boolean): void {
|
||||
|
||||
this._registrations[handle] = modes.RenameProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.RenameProvider>{
|
||||
this._registrations[handle] = modes.RenameProviderRegistry.register(selector, <modes.RenameProvider>{
|
||||
provideRenameEdits: (model: ITextModel, position: EditorPosition, newName: string, token: CancellationToken): Promise<modes.WorkspaceEdit> => {
|
||||
return this._proxy.$provideRenameEdits(handle, model.uri, position, newName, token).then(reviveWorkspaceEditDto);
|
||||
},
|
||||
@@ -359,7 +358,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
// --- suggest
|
||||
|
||||
$registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean): void {
|
||||
this._registrations[handle] = modes.CompletionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.CompletionItemProvider>{
|
||||
this._registrations[handle] = modes.CompletionProviderRegistry.register(selector, <modes.CompletionItemProvider>{
|
||||
triggerCharacters,
|
||||
provideCompletionItems: (model: ITextModel, position: EditorPosition, context: modes.CompletionContext, token: CancellationToken): Promise<modes.CompletionList | undefined> => {
|
||||
return this._proxy.$provideCompletionItems(handle, model.uri, position, context, token).then(result => {
|
||||
@@ -386,7 +385,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
// --- parameter hints
|
||||
|
||||
$registerSignatureHelpProvider(handle: number, selector: ISerializedDocumentFilter[], metadata: ISerializedSignatureHelpProviderMetadata): void {
|
||||
this._registrations[handle] = modes.SignatureHelpProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.SignatureHelpProvider>{
|
||||
this._registrations[handle] = modes.SignatureHelpProviderRegistry.register(selector, <modes.SignatureHelpProvider>{
|
||||
|
||||
signatureHelpTriggerCharacters: metadata.triggerCharacters,
|
||||
signatureHelpRetriggerCharacters: metadata.retriggerCharacters,
|
||||
@@ -400,7 +399,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
// --- links
|
||||
|
||||
$registerDocumentLinkProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.LinkProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.LinkProvider>{
|
||||
this._registrations[handle] = modes.LinkProviderRegistry.register(selector, <modes.LinkProvider>{
|
||||
provideLinks: (model, token) => {
|
||||
return this._proxy.$provideDocumentLinks(handle, model.uri, token).then(dto => {
|
||||
if (dto) {
|
||||
@@ -428,7 +427,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
|
||||
$registerDocumentColorProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
const proxy = this._proxy;
|
||||
this._registrations[handle] = modes.ColorProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentColorProvider>{
|
||||
this._registrations[handle] = modes.ColorProviderRegistry.register(selector, <modes.DocumentColorProvider>{
|
||||
provideDocumentColors: (model, token) => {
|
||||
return proxy.$provideDocumentColors(handle, model.uri, token)
|
||||
.then(documentColors => {
|
||||
@@ -462,7 +461,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
|
||||
$registerFoldingRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
const proxy = this._proxy;
|
||||
this._registrations[handle] = modes.FoldingRangeProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.FoldingRangeProvider>{
|
||||
this._registrations[handle] = modes.FoldingRangeProviderRegistry.register(selector, <modes.FoldingRangeProvider>{
|
||||
provideFoldingRanges: (model, context, token) => {
|
||||
return proxy.$provideFoldingRanges(handle, model.uri, context, token);
|
||||
}
|
||||
@@ -472,7 +471,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
// -- smart select
|
||||
|
||||
$registerSelectionRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.SelectionRangeRegistry.register(typeConverters.LanguageSelector.from(selector), {
|
||||
this._registrations[handle] = modes.SelectionRangeRegistry.register(selector, {
|
||||
provideSelectionRanges: (model, positions, token) => {
|
||||
return this._proxy.$provideSelectionRanges(handle, model.uri, positions, token);
|
||||
}
|
||||
@@ -482,7 +481,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
// --- call hierarchy
|
||||
|
||||
$registerCallHierarchyProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = callh.CallHierarchyProviderRegistry.register(typeConverters.LanguageSelector.from(selector), {
|
||||
this._registrations[handle] = callh.CallHierarchyProviderRegistry.register(selector, {
|
||||
provideCallHierarchyItem: (document, position, token) => {
|
||||
return this._proxy.$provideCallHierarchyItem(handle, document.uri, position, token).then(MainThreadLanguageFeatures._reviveCallHierarchyItemDto);
|
||||
},
|
||||
@@ -263,7 +263,7 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
|
||||
|
||||
const timeout = this._configurationService.getValue<number>('editor.formatOnSaveTimeout', { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() });
|
||||
|
||||
return new Promise<TextEdit[] | null | undefined>((resolve, reject) => {
|
||||
return new Promise<TextEdit[] | null>((resolve, reject) => {
|
||||
const source = new CancellationTokenSource();
|
||||
const request = getDocumentFormattingEdits(this._telemetryService, this._editorWorkerService, model, model.getFormattingOptions(), FormatMode.Auto, source.token);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { extHostNamedCustomer } from '../common/extHostCustomers';
|
||||
import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler';
|
||||
import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
class ExtensionUrlHandler implements IURLHandler {
|
||||
@@ -44,6 +44,8 @@ import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityReso
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset';
|
||||
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { IRelativePattern } from 'vs/base/common/glob';
|
||||
import { IRemoteConsoleLog } from 'vs/base/common/console';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views';
|
||||
@@ -310,7 +312,7 @@ export interface ISerializedDocumentFilter {
|
||||
$serialized: true;
|
||||
language?: string;
|
||||
scheme?: string;
|
||||
pattern?: GlobPattern;
|
||||
pattern?: string | IRelativePattern;
|
||||
exclusive?: boolean;
|
||||
}
|
||||
|
||||
@@ -610,6 +612,7 @@ export interface MainThreadExtensionServiceShape extends IDisposable {
|
||||
$onDidActivateExtension(extensionId: ExtensionIdentifier, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string | null): void;
|
||||
$onExtensionActivationError(extensionId: ExtensionIdentifier, error: ExtensionActivationError): Promise<void>;
|
||||
$onExtensionRuntimeError(extensionId: ExtensionIdentifier, error: SerializedError): void;
|
||||
$onExtensionHostExit(code: number): void;
|
||||
}
|
||||
|
||||
export interface SCMProviderFeatures {
|
||||
|
||||
@@ -35,11 +35,13 @@ namespace schema {
|
||||
case 'editor/title/context': return MenuId.EditorTitleContext;
|
||||
case 'debug/callstack/context': return MenuId.DebugCallStackContext;
|
||||
case 'debug/toolbar': return MenuId.DebugToolbar;
|
||||
case 'menuBar/file': return MenuId.MenubarFileMenu;
|
||||
case 'scm/title': return MenuId.SCMTitle;
|
||||
case 'scm/sourceControl': return MenuId.SCMSourceControl;
|
||||
case 'scm/resourceGroup/context': return MenuId.SCMResourceGroupContext;
|
||||
case 'scm/resourceState/context': return MenuId.SCMResourceContext;
|
||||
case 'scm/change/title': return MenuId.SCMChangeContext;
|
||||
case 'statusBar/windowIndicator': return MenuId.StatusBarWindowIndicatorMenu;
|
||||
case 'view/title': return MenuId.ViewTitle;
|
||||
case 'view/item/context': return MenuId.ViewItemContext;
|
||||
// {{SQL CARBON EDIT}}
|
||||
|
||||
@@ -14,19 +14,28 @@ import { ColorExtensionPoint } from 'vs/workbench/services/themes/common/colorEx
|
||||
import { LanguageConfigurationFileHandler } from 'vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint';
|
||||
|
||||
// --- mainThread participants
|
||||
import 'vs/workbench/api/node/apiCommands';
|
||||
import '../browser/mainThreadClipboard';
|
||||
import '../browser/mainThreadCommands';
|
||||
import '../browser/mainThreadConfiguration';
|
||||
import '../browser/mainThreadConsole';
|
||||
// {{SQL CARBON EDIT}}
|
||||
// import '../browser/mainThreadDebugService';
|
||||
import '../browser/mainThreadDecorations';
|
||||
import '../browser/mainThreadDiagnostics';
|
||||
import '../browser/mainThreadDialogs';
|
||||
import '../browser/mainThreadDocumentContentProviders';
|
||||
import '../browser/mainThreadDocuments';
|
||||
import '../browser/mainThreadDocumentsAndEditors';
|
||||
import '../browser/mainThreadEditor';
|
||||
import '../browser/mainThreadEditors';
|
||||
import '../browser/mainThreadErrors';
|
||||
import '../browser/mainThreadExtensionService';
|
||||
import '../browser/mainThreadFileSystem';
|
||||
import '../browser/mainThreadFileSystemEventService';
|
||||
import '../browser/mainThreadHeapService';
|
||||
import '../browser/mainThreadLanguageFeatures';
|
||||
import '../browser/mainThreadLanguages';
|
||||
import '../browser/mainThreadLogService';
|
||||
import '../browser/mainThreadMessageService';
|
||||
import '../browser/mainThreadOutputService';
|
||||
import '../browser/mainThreadProgress';
|
||||
@@ -36,25 +45,16 @@ import '../browser/mainThreadSCM';
|
||||
import '../browser/mainThreadSearch';
|
||||
import '../browser/mainThreadStatusBar';
|
||||
import '../browser/mainThreadStorage';
|
||||
import './mainThreadComments';
|
||||
import './mainThreadConsole';
|
||||
import './mainThreadDocuments';
|
||||
import './mainThreadDocumentsAndEditors';
|
||||
import './mainThreadEditor';
|
||||
import './mainThreadEditors';
|
||||
import './mainThreadExtensionService';
|
||||
import './mainThreadHeapService';
|
||||
import './mainThreadLanguageFeatures';
|
||||
import '../browser/mainThreadLanguages';
|
||||
import '../browser/mainThreadLogService';
|
||||
import './mainThreadTask';
|
||||
import '../browser/mainThreadTelemetry';
|
||||
import '../browser/mainThreadTerminalService';
|
||||
import '../browser/mainThreadTreeViews';
|
||||
import './mainThreadUrls';
|
||||
import './mainThreadWebview';
|
||||
import '../browser/mainThreadUrls';
|
||||
import '../browser/mainThreadWindow';
|
||||
import '../browser/mainThreadWorkspace';
|
||||
import './mainThreadComments';
|
||||
import './mainThreadTask';
|
||||
import './mainThreadWebview';
|
||||
import 'vs/workbench/api/node/apiCommands';
|
||||
|
||||
export class ExtensionPoints implements IWorkbenchContribution {
|
||||
|
||||
|
||||
@@ -68,6 +68,25 @@ CommandsRegistry.registerCommand({
|
||||
}
|
||||
});
|
||||
|
||||
interface INewWindowAPICommandOptions {
|
||||
}
|
||||
|
||||
export class NewWindowAPICommand {
|
||||
public static ID = 'vscode.newWindow';
|
||||
public static execute(executor: ICommandsExecutor, options?: INewWindowAPICommandOptions): Promise<any> {
|
||||
return executor.executeCommand('_files.newWindow', [options]);
|
||||
}
|
||||
}
|
||||
CommandsRegistry.registerCommand({
|
||||
id: NewWindowAPICommand.ID,
|
||||
handler: adjustHandler(NewWindowAPICommand.execute),
|
||||
description: {
|
||||
description: 'Opens an new window',
|
||||
args: [
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
export class DiffAPICommand {
|
||||
public static ID = 'vscode.diff';
|
||||
public static execute(executor: ICommandsExecutor, left: URI, right: URI, label: string, options?: vscode.TextDocumentShowOptions): Promise<any> {
|
||||
|
||||
@@ -67,6 +67,7 @@ import * as vscode from 'vscode';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { originalFSPath } from 'vs/base/common/resources';
|
||||
import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
|
||||
export interface IExtensionApiFactory {
|
||||
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
|
||||
@@ -537,7 +538,7 @@ export function createApiFactory(
|
||||
return extHostWorkspace.getRelativePath(pathOrUri, includeWorkspace);
|
||||
},
|
||||
findFiles: (include, exclude, maxResults?, token?) => {
|
||||
return extHostWorkspace.findFiles(typeConverters.GlobPattern.from(include), typeConverters.GlobPattern.from(exclude), maxResults, extension.identifier, token);
|
||||
return extHostWorkspace.findFiles(typeConverters.GlobPattern.from(include), typeConverters.GlobPattern.from(withNullAsUndefined(exclude)), maxResults, extension.identifier, token);
|
||||
},
|
||||
findTextInFiles: (query: vscode.TextSearchQuery, optionsOrCallback, callbackOrToken?, token?: vscode.CancellationToken) => {
|
||||
let options: vscode.FindTextInFilesOptions;
|
||||
|
||||
@@ -642,7 +642,14 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
private _gracefulExit(code: number): void {
|
||||
// to give the PH process a chance to flush any outstanding console
|
||||
// messages to the main process, we delay the exit() by some time
|
||||
setTimeout(() => this._nativeExit(code), 500);
|
||||
setTimeout(() => {
|
||||
if (!!this._initData.environment.extensionTestsLocationURI) {
|
||||
// If extension tests are running, give the exit code to the renderer
|
||||
this._mainThreadExtensionsProxy.$onExtensionHostExit(code);
|
||||
return;
|
||||
}
|
||||
this._nativeExit(code);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
private _startExtensionHost(): Promise<void> {
|
||||
|
||||
@@ -1082,7 +1082,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
$serialized: true,
|
||||
language: selector.language,
|
||||
scheme: this._transformScheme(selector.scheme),
|
||||
pattern: selector.pattern,
|
||||
pattern: typeof selector.pattern === 'undefined' ? undefined : typeConvert.GlobPattern.from(selector.pattern),
|
||||
exclusive: selector.exclusive
|
||||
};
|
||||
}
|
||||
|
||||
@@ -986,9 +986,9 @@ export namespace TextEditorOptions {
|
||||
export namespace GlobPattern {
|
||||
|
||||
export function from(pattern: vscode.GlobPattern): string | types.RelativePattern;
|
||||
export function from(pattern: undefined | null): undefined | null;
|
||||
export function from(pattern: vscode.GlobPattern | undefined | null): string | types.RelativePattern | undefined | null;
|
||||
export function from(pattern: vscode.GlobPattern | undefined | null): string | types.RelativePattern | undefined | null {
|
||||
export function from(pattern: undefined): undefined;
|
||||
export function from(pattern: vscode.GlobPattern | undefined): string | types.RelativePattern | undefined;
|
||||
export function from(pattern: vscode.GlobPattern | undefined): string | types.RelativePattern | undefined {
|
||||
if (pattern instanceof types.RelativePattern) {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
@@ -388,7 +388,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
|
||||
|
||||
// --- search ---
|
||||
|
||||
findFiles(include: string | RelativePattern | undefined | null, exclude: vscode.GlobPattern | undefined | null, maxResults: number | undefined, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.Uri[]> {
|
||||
findFiles(include: string | RelativePattern | undefined, exclude: vscode.GlobPattern | undefined, maxResults: number | undefined, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.Uri[]> {
|
||||
this._logService.trace(`extHostWorkspace#findFiles: fileSearch, extension: ${extensionId.value}, entryPoint: findFiles`);
|
||||
|
||||
let includePattern: string | undefined;
|
||||
|
||||
@@ -288,7 +288,9 @@ export class SimpleExtensionGalleryService implements IExtensionGalleryService {
|
||||
return false;
|
||||
}
|
||||
|
||||
query(options?: IQueryOptions): Promise<IPager<IGalleryExtension>> {
|
||||
query(token: CancellationToken): Promise<IPager<IGalleryExtension>>;
|
||||
query(options: IQueryOptions, token: CancellationToken): Promise<IPager<IGalleryExtension>>;
|
||||
query(arg1: any, arg2?: any): Promise<IPager<IGalleryExtension>> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ export class BinaryResourceDiffEditor extends SideBySideEditor {
|
||||
super(telemetryService, instantiationService, themeService, storageService);
|
||||
}
|
||||
|
||||
getMetadata(): string | null {
|
||||
getMetadata(): string | undefined {
|
||||
const master = this.masterEditor;
|
||||
const details = this.detailsEditor;
|
||||
|
||||
@@ -36,6 +36,6 @@ export class BinaryResourceDiffEditor extends SideBySideEditor {
|
||||
return nls.localize('metadataDiff', "{0} ↔ {1}", details.getMetadata(), master.getMetadata());
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
|
||||
get onDidOpenInPlace(): Event<void> { return this._onDidOpenInPlace.event; }
|
||||
|
||||
private callbacks: IOpenCallbacks;
|
||||
private metadata: string | null;
|
||||
private metadata: string | undefined;
|
||||
private binaryContainer: HTMLElement;
|
||||
private scrollbar: DomScrollableElement;
|
||||
private resourceViewerContext: ResourceViewerContext;
|
||||
@@ -110,20 +110,20 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
|
||||
});
|
||||
}
|
||||
|
||||
private handleMetadataChanged(meta: string | null): void {
|
||||
private handleMetadataChanged(meta: string | undefined): void {
|
||||
this.metadata = meta;
|
||||
|
||||
this._onMetadataChanged.fire();
|
||||
}
|
||||
|
||||
getMetadata() {
|
||||
getMetadata(): string | undefined {
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
clearInput(): void {
|
||||
|
||||
// Clear Meta
|
||||
this.handleMetadataChanged(null);
|
||||
this.handleMetadataChanged(undefined);
|
||||
|
||||
// Clear Resource Viewer
|
||||
clearNode(this.binaryContainer);
|
||||
|
||||
@@ -143,43 +143,35 @@ interface StateDelta {
|
||||
indentation?: string;
|
||||
tabFocusMode?: boolean;
|
||||
screenReaderMode?: boolean;
|
||||
metadata?: string | null;
|
||||
metadata?: string | undefined;
|
||||
}
|
||||
|
||||
class State {
|
||||
private _selectionStatus: string | null | undefined;
|
||||
get selectionStatus(): string | null | undefined { return this._selectionStatus; }
|
||||
private _selectionStatus: string | undefined;
|
||||
get selectionStatus(): string | undefined { return this._selectionStatus; }
|
||||
|
||||
private _mode: string | null | undefined;
|
||||
get mode(): string | null | undefined { return this._mode; }
|
||||
private _mode: string | undefined;
|
||||
get mode(): string | undefined { return this._mode; }
|
||||
|
||||
private _encoding: string | null | undefined;
|
||||
get encoding(): string | null | undefined { return this._encoding; }
|
||||
private _encoding: string | undefined;
|
||||
get encoding(): string | undefined { return this._encoding; }
|
||||
|
||||
private _EOL: string | null | undefined;
|
||||
get EOL(): string | null | undefined { return this._EOL; }
|
||||
private _EOL: string | undefined;
|
||||
get EOL(): string | undefined { return this._EOL; }
|
||||
|
||||
private _indentation: string | null | undefined;
|
||||
get indentation(): string | null | undefined { return this._indentation; }
|
||||
private _indentation: string | undefined;
|
||||
get indentation(): string | undefined { return this._indentation; }
|
||||
|
||||
private _tabFocusMode: boolean | null | undefined;
|
||||
get tabFocusMode(): boolean | null | undefined { return this._tabFocusMode; }
|
||||
private _tabFocusMode: boolean | undefined;
|
||||
get tabFocusMode(): boolean | undefined { return this._tabFocusMode; }
|
||||
|
||||
private _screenReaderMode: boolean | null | undefined;
|
||||
get screenReaderMode(): boolean | null | undefined { return this._screenReaderMode; }
|
||||
private _screenReaderMode: boolean | undefined;
|
||||
get screenReaderMode(): boolean | undefined { return this._screenReaderMode; }
|
||||
|
||||
private _metadata: string | null | undefined;
|
||||
get metadata(): string | null | undefined { return this._metadata; }
|
||||
private _metadata: string | undefined;
|
||||
get metadata(): string | undefined { return this._metadata; }
|
||||
|
||||
constructor() {
|
||||
this._selectionStatus = null;
|
||||
this._mode = null;
|
||||
this._encoding = null;
|
||||
this._EOL = null;
|
||||
this._tabFocusMode = false;
|
||||
this._screenReaderMode = false;
|
||||
this._metadata = null;
|
||||
}
|
||||
constructor() { }
|
||||
|
||||
update(update: StateDelta): StateChange {
|
||||
const change = new StateChange();
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import 'vs/css!./media/statusbarpart';
|
||||
import * as nls from 'vs/nls';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { dispose, IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { dispose, IDisposable, toDisposable, combinedDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
@@ -49,6 +49,8 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
private statusMsgDispose: IDisposable;
|
||||
private styleElement: HTMLStyleElement;
|
||||
|
||||
private pendingEntries: { entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number, disposable: IDisposable }[] = [];
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@@ -67,6 +69,18 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
|
||||
addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number = 0): IDisposable {
|
||||
|
||||
// As long as we have not been created into a container yet, record all entries
|
||||
// that are pending so that they can get created at a later point
|
||||
if (!this.element) {
|
||||
const pendingEntry = { entry, alignment, priority, disposable: Disposable.None };
|
||||
this.pendingEntries.push(pendingEntry);
|
||||
|
||||
return toDisposable(() => {
|
||||
this.pendingEntries = this.pendingEntries.filter(e => e !== pendingEntry);
|
||||
pendingEntry.disposable.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
// Render entry in status bar
|
||||
const el = this.doCreateStatusItem(alignment, priority, entry.showBeak ? 'has-beak' : undefined);
|
||||
const item = this.instantiationService.createInstance(StatusBarEntryItem, entry);
|
||||
@@ -146,6 +160,14 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
this.element.appendChild(el);
|
||||
}
|
||||
|
||||
// Fill in pending entries if any
|
||||
while (this.pendingEntries.length) {
|
||||
const entry = this.pendingEntries.shift();
|
||||
if (entry) {
|
||||
entry.disposable = this.addEntry(entry.entry, entry.alignment, entry.priority);
|
||||
}
|
||||
}
|
||||
|
||||
return this.element;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,9 @@ export class MenubarControl extends Disposable {
|
||||
|
||||
this.menuUpdater = this._register(new RunOnceScheduler(() => this.doUpdateMenubar(false), 200));
|
||||
|
||||
this._onVisibilityChange = this._register(new Emitter<boolean>());
|
||||
this._onFocusStateChange = this._register(new Emitter<boolean>());
|
||||
|
||||
if (isMacintosh || this.currentTitlebarStyleSetting !== 'custom') {
|
||||
for (const topLevelMenuName of Object.keys(this.topLevelMenus)) {
|
||||
const menu = this.topLevelMenus[topLevelMenuName];
|
||||
@@ -130,15 +133,14 @@ export class MenubarControl extends Disposable {
|
||||
this._register(menu.onDidChange(() => this.updateMenubar()));
|
||||
}
|
||||
}
|
||||
|
||||
this.doUpdateMenubar(true);
|
||||
}
|
||||
|
||||
this._onVisibilityChange = this._register(new Emitter<boolean>());
|
||||
this._onFocusStateChange = this._register(new Emitter<boolean>());
|
||||
|
||||
this.windowService.getRecentlyOpened().then((recentlyOpened) => {
|
||||
this.recentlyOpened = recentlyOpened;
|
||||
|
||||
if (isMacintosh || this.currentTitlebarStyleSetting !== 'custom') {
|
||||
this.doUpdateMenubar(true);
|
||||
}
|
||||
});
|
||||
|
||||
this.notifyExistingLinuxUser();
|
||||
|
||||
@@ -179,7 +179,7 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
}
|
||||
|
||||
private updateRepresentedFilename(): void {
|
||||
const file = toResource(this.editorService.activeEditor || null, { supportSideBySide: true, filter: 'file' });
|
||||
const file = toResource(this.editorService.activeEditor, { supportSideBySide: true, filter: 'file' });
|
||||
const path = file ? file.fsPath : '';
|
||||
|
||||
// Apply to window
|
||||
@@ -282,7 +282,7 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
// Compute folder resource
|
||||
// Single Root Workspace: always the root single workspace in this case
|
||||
// Otherwise: root folder of the currently active file if any
|
||||
const folder = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? workspace.folders[0] : this.contextService.getWorkspaceFolder(toResource(editor || null, { supportSideBySide: true })!);
|
||||
const folder = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? workspace.folders[0] : this.contextService.getWorkspaceFolder(toResource(editor, { supportSideBySide: true })!);
|
||||
|
||||
// Variables
|
||||
const activeEditorShort = editor ? editor.getTitle(Verbosity.SHORT) : '';
|
||||
|
||||
@@ -17,7 +17,7 @@ import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
|
||||
import { PeekContext } from 'vs/editor/contrib/referenceSearch/peekViewWidget';
|
||||
|
||||
const _ctxHasCompletionItemProvider = new RawContextKey<boolean>('editorHasCallHierarchyProvider', false);
|
||||
const _ctxCallHierarchyVisible = new RawContextKey<boolean>('callHierarchyVisible', false);
|
||||
@@ -101,7 +101,6 @@ class CallHierarchyController extends Disposable implements IEditorContribution
|
||||
widget.showMessage(localize('no.item', "No results"));
|
||||
return;
|
||||
}
|
||||
|
||||
widget.showItem(item);
|
||||
});
|
||||
}
|
||||
@@ -131,7 +130,10 @@ registerEditorAction(class extends EditorAction {
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.Shift + KeyMod.Alt + KeyCode.KEY_H
|
||||
},
|
||||
precondition: _ctxHasCompletionItemProvider
|
||||
precondition: ContextKeyExpr.and(
|
||||
_ctxHasCompletionItemProvider,
|
||||
PeekContext.notInPeekEditor
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -150,7 +152,10 @@ registerEditorCommand(new class extends EditorCommand {
|
||||
weight: KeybindingWeight.WorkbenchContrib + 10,
|
||||
primary: KeyCode.Escape
|
||||
},
|
||||
precondition: ContextKeyExpr.and(_ctxCallHierarchyVisible, ContextKeyExpr.not('config.editor.stablePeek'))
|
||||
precondition: ContextKeyExpr.and(
|
||||
_ctxCallHierarchyVisible,
|
||||
ContextKeyExpr.not('config.editor.stablePeek')
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import 'vs/css!./media/callHierarchy';
|
||||
import { PeekViewWidget } from 'vs/editor/contrib/referenceSearch/peekViewWidget';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { CallHierarchyItem, CallHierarchyProvider, CallHierarchyDirection } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { CallHierarchyProvider, CallHierarchyDirection, CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
|
||||
import { FuzzyScore } from 'vs/base/common/filters';
|
||||
import * as callHTree from 'vs/workbench/contrib/callHierarchy/browser/callHierarchyTree';
|
||||
@@ -262,6 +262,22 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
localDispose.push({ dispose: () => this._editor.deltaDecorations(ids, []) });
|
||||
localDispose.push(value);
|
||||
});
|
||||
|
||||
let node: callHTree.Call | CallHierarchyItem = element;
|
||||
let names = [element.item.name];
|
||||
while (true) {
|
||||
let parent = this._tree.getParentElement(node);
|
||||
if (!(parent instanceof callHTree.Call)) {
|
||||
break;
|
||||
}
|
||||
if (this._direction === CallHierarchyDirection.CallsTo) {
|
||||
names.push(parent.item.name);
|
||||
} else {
|
||||
names.unshift(parent.item.name);
|
||||
}
|
||||
node = parent;
|
||||
}
|
||||
this.setMetaTitle(localize('meta', " – {0}", names.join(' → ')));
|
||||
}
|
||||
}, undefined, this._disposables);
|
||||
|
||||
@@ -295,14 +311,14 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
this._tree.onDidChangeSelection(e => {
|
||||
const [element] = e.elements;
|
||||
// don't close on click
|
||||
if (element && !(e.browserEvent instanceof MouseEvent)) {
|
||||
if (element && isNonEmptyArray(element.locations) && !(e.browserEvent instanceof MouseEvent)) {
|
||||
this.dispose();
|
||||
this._editorService.openEditor({
|
||||
resource: element.item.uri,
|
||||
options: { selection: element.locations[0].range }
|
||||
});
|
||||
}
|
||||
});
|
||||
}, undefined, this._disposables);
|
||||
}
|
||||
|
||||
showLoading(): void {
|
||||
@@ -319,30 +335,29 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
this._show();
|
||||
}
|
||||
|
||||
showItem(item: CallHierarchyItem) {
|
||||
this._parent.dataset['state'] = State.Data;
|
||||
async showItem(item: CallHierarchyItem): Promise<void> {
|
||||
|
||||
this._show();
|
||||
this._tree.setInput(item).then(() => {
|
||||
await this._tree.setInput(item);
|
||||
|
||||
if (!this._tree.getFirstElementChild(item)) {
|
||||
//
|
||||
this.showMessage(this._direction === CallHierarchyDirection.CallsFrom
|
||||
? localize('empt.callsFrom', "No calls from '{0}'", item.name)
|
||||
: localize('empt.callsTo', "No calls to '{0}'", item.name));
|
||||
const [root] = this._tree.getNode(item).children;
|
||||
await this._tree.expand(root.element as callHTree.Call);
|
||||
const firstChild = this._tree.getFirstElementChild(root.element);
|
||||
if (!(firstChild instanceof callHTree.Call)) {
|
||||
//
|
||||
this.showMessage(this._direction === CallHierarchyDirection.CallsFrom
|
||||
? localize('empt.callsFrom', "No calls from '{0}'", item.name)
|
||||
: localize('empt.callsTo', "No calls to '{0}'", item.name));
|
||||
|
||||
} else {
|
||||
this._tree.domFocus();
|
||||
this._tree.focusFirst();
|
||||
this.setTitle(
|
||||
item.name,
|
||||
item.detail || this._labelService.getUriLabel(item.uri, { relative: true }),
|
||||
);
|
||||
this.setMetaTitle(this._direction === CallHierarchyDirection.CallsFrom
|
||||
? localize('title.from', " – calls from '{0}'", item.name)
|
||||
: localize('title.to', " – calls to '{0}'", item.name));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this._parent.dataset['state'] = State.Data;
|
||||
this._tree.domFocus();
|
||||
this._tree.setFocus([firstChild]);
|
||||
this.setTitle(
|
||||
item.name,
|
||||
item.detail || this._labelService.getUriLabel(item.uri, { relative: true }),
|
||||
);
|
||||
}
|
||||
|
||||
if (!this._toggleDirection) {
|
||||
this._toggleDirection = new ToggleHierarchyDirectionAction(
|
||||
|
||||
@@ -11,10 +11,10 @@ import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
||||
import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
import { symbolKindToCssClass, Location } from 'vs/editor/common/modes';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
|
||||
export class Call {
|
||||
constructor(
|
||||
readonly direction: CallHierarchyDirection,
|
||||
readonly item: CallHierarchyItem,
|
||||
readonly locations: Location[]
|
||||
) { }
|
||||
@@ -24,22 +24,29 @@ export class SingleDirectionDataSource implements IAsyncDataSource<CallHierarchy
|
||||
|
||||
constructor(
|
||||
public provider: CallHierarchyProvider,
|
||||
public direction: () => CallHierarchyDirection
|
||||
public getDirection: () => CallHierarchyDirection
|
||||
) { }
|
||||
|
||||
hasChildren(_element: CallHierarchyItem): boolean {
|
||||
hasChildren(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
async getChildren(element: CallHierarchyItem | Call): Promise<Call[]> {
|
||||
if (element instanceof Call) {
|
||||
element = element.item;
|
||||
try {
|
||||
const direction = this.getDirection();
|
||||
const calls = await this.provider.resolveCallHierarchyItem(element.item, direction, CancellationToken.None);
|
||||
if (!calls) {
|
||||
return [];
|
||||
}
|
||||
return calls.map(([item, locations]) => new Call(item, locations));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
} else {
|
||||
// 'root'
|
||||
return [new Call(element, [{ uri: element.uri, range: Range.lift(element.range).collapseToStart() }])];
|
||||
}
|
||||
const direction = this.direction();
|
||||
const calls = await this.provider.resolveCallHierarchyItem(element, direction, CancellationToken.None);
|
||||
return calls
|
||||
? calls.map(([item, locations]) => new Call(direction, item, locations))
|
||||
: [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +57,7 @@ export class IdentityProvider implements IIdentityProvider<Call> {
|
||||
}
|
||||
|
||||
class CallRenderingTemplate {
|
||||
iconLabel: IconLabel;
|
||||
readonly iconLabel: IconLabel;
|
||||
}
|
||||
|
||||
export class CallRenderer implements ITreeRenderer<Call, FuzzyScore, CallRenderingTemplate> {
|
||||
@@ -59,7 +66,9 @@ export class CallRenderer implements ITreeRenderer<Call, FuzzyScore, CallRenderi
|
||||
|
||||
templateId: string = CallRenderer.id;
|
||||
|
||||
constructor(@ILabelService private readonly _labelService: ILabelService) { }
|
||||
constructor(
|
||||
@ILabelService private readonly _labelService: ILabelService,
|
||||
) { }
|
||||
|
||||
renderTemplate(container: HTMLElement): CallRenderingTemplate {
|
||||
const iconLabel = new IconLabel(container, { supportHighlights: true });
|
||||
|
||||
@@ -104,7 +104,8 @@ export class SuggestEnabledInput extends Widget implements IThemable {
|
||||
readonly onInputDidChange: Event<string | undefined> = this._onInputDidChange.event;
|
||||
|
||||
private disposables: IDisposable[] = [];
|
||||
private inputWidget: CodeEditorWidget;
|
||||
private readonly inputWidget: CodeEditorWidget;
|
||||
private readonly inputModel: ITextModel;
|
||||
private stylingContainer: HTMLDivElement;
|
||||
private placeholderText: HTMLDivElement;
|
||||
|
||||
@@ -136,7 +137,8 @@ export class SuggestEnabledInput extends Widget implements IThemable {
|
||||
this.disposables.push(this.inputWidget);
|
||||
|
||||
let scopeHandle = uri.parse(resourceHandle);
|
||||
this.inputWidget.setModel(modelService.createModel('', null, scopeHandle, true));
|
||||
this.inputModel = modelService.createModel('', null, scopeHandle, true);
|
||||
this.inputWidget.setModel(this.inputModel);
|
||||
|
||||
this.disposables.push(this.inputWidget.onDidPaste(() => this.setValue(this.getValue()))); // setter cleanses
|
||||
|
||||
@@ -203,7 +205,7 @@ export class SuggestEnabledInput extends Widget implements IThemable {
|
||||
|
||||
public setValue(val: string) {
|
||||
val = val.replace(/\s/g, ' ');
|
||||
const fullRange = new Range(1, 1, 1, this.getValue().length + 1);
|
||||
const fullRange = this.inputModel.getFullModelRange();
|
||||
this.inputWidget.executeEdits('suggestEnabledInput.setValue', [EditOperation.replace(fullRange, val)]);
|
||||
this.inputWidget.setScrollTop(0);
|
||||
this.inputWidget.setPosition(new Position(1, val.length + 1));
|
||||
|
||||
@@ -97,7 +97,7 @@ export class CallStackView extends ViewletPanel {
|
||||
dom.addClass(container, 'debug-call-stack');
|
||||
const treeContainer = renderViewTree(container);
|
||||
|
||||
this.dataSource = new CallStackDataSource();
|
||||
this.dataSource = new CallStackDataSource(this.debugService);
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, treeContainer, new CallStackDelegate(), [
|
||||
new SessionsRenderer(),
|
||||
new ThreadsRenderer(),
|
||||
@@ -562,6 +562,8 @@ function isDeemphasized(frame: IStackFrame): boolean {
|
||||
class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem> {
|
||||
deemphasizedStackFramesToShow: IStackFrame[];
|
||||
|
||||
constructor(private debugService: IDebugService) { }
|
||||
|
||||
hasChildren(element: IDebugModel | CallStackItem): boolean {
|
||||
return isDebugModel(element) || isDebugSession(element) || (element instanceof Thread && element.stopped);
|
||||
}
|
||||
@@ -573,13 +575,18 @@ class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
if (sessions.length > 1) {
|
||||
return Promise.resolve(sessions);
|
||||
return Promise.resolve(sessions.filter(s => !s.parentSession));
|
||||
}
|
||||
|
||||
const threads = sessions[0].getAllThreads();
|
||||
// Only show the threads in the call stack if there is more than 1 thread.
|
||||
return threads.length === 1 ? this.getThreadChildren(<Thread>threads[0]) : Promise.resolve(threads);
|
||||
} else if (isDebugSession(element)) {
|
||||
const childSessions = this.debugService.getModel().getSessions().filter(s => s.parentSession === element);
|
||||
if (childSessions.length) {
|
||||
return Promise.resolve(childSessions);
|
||||
}
|
||||
|
||||
return Promise.resolve(element.getAllThreads());
|
||||
} else {
|
||||
return this.getThreadChildren(<Thread>element);
|
||||
|
||||
@@ -217,7 +217,15 @@ export class FocusSessionActionItem extends SelectActionItem {
|
||||
private update() {
|
||||
const session = this.debugService.getViewModel().focusedSession;
|
||||
const sessions = this.getSessions();
|
||||
const names = sessions.map(s => s.getLabel());
|
||||
const names = sessions.map(s => {
|
||||
const label = s.getLabel();
|
||||
if (s.parentSession) {
|
||||
// Indent child sessions so they look like children
|
||||
return `\u00A0\u00A0${label}`;
|
||||
}
|
||||
|
||||
return label;
|
||||
});
|
||||
this.setOptions(names.map(data => <ISelectOptionItem>{ text: data }), session ? sessions.indexOf(session) : undefined);
|
||||
}
|
||||
|
||||
|
||||
@@ -516,6 +516,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
|
||||
this.exceptionWidget = this.instantiationService.createInstance(ExceptionWidget, this.editor, exceptionInfo);
|
||||
this.exceptionWidget.show({ lineNumber, column }, 0);
|
||||
this.editor.revealLine(lineNumber);
|
||||
}
|
||||
|
||||
private closeExceptionWidget(): void {
|
||||
|
||||
@@ -37,7 +37,6 @@ export class ExceptionWidget extends ZoneWidget {
|
||||
this._applyTheme(themeService.getTheme());
|
||||
this._disposables.push(themeService.onThemeChange(this._applyTheme.bind(this)));
|
||||
|
||||
|
||||
this.create();
|
||||
const onDidLayoutChangeScheduler = new RunOnceScheduler(() => this._doLayout(undefined, undefined), 50);
|
||||
this._disposables.push(this.editor.onDidLayoutChange(() => onDidLayoutChangeScheduler.schedule()));
|
||||
|
||||
@@ -39,11 +39,6 @@
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-action.start,
|
||||
.hc-black .monaco-workbench .debug-action.start {
|
||||
background: url('continue-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-action.configure,
|
||||
.hc-black .monaco-workbench .debug-action.configure {
|
||||
background: url('configure-inverse.svg') center center no-repeat;
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.exception-widget .stack-trace {
|
||||
margin-top: 0.5em;
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.exception-widget a {
|
||||
|
||||
@@ -149,6 +149,7 @@ export interface IDebugSession extends ITreeElement {
|
||||
readonly unresolvedConfiguration: IConfig | undefined;
|
||||
readonly state: State;
|
||||
readonly root: IWorkspaceFolder;
|
||||
readonly parentSession: IDebugSession | undefined;
|
||||
|
||||
getLabel(): string;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import { isObject, isString, isUndefinedOrNull } from 'vs/base/common/types';
|
||||
import { distinct } from 'vs/base/common/arrays';
|
||||
import { distinct, lastIndex } from 'vs/base/common/arrays';
|
||||
import { Range, IRange } from 'vs/editor/common/core/range';
|
||||
import {
|
||||
ITreeElement, IExpression, IExpressionContainer, IDebugSession, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IDebugModel, IReplElementSource,
|
||||
@@ -797,7 +797,17 @@ export class DebugModel implements IDebugModel {
|
||||
|
||||
return true;
|
||||
});
|
||||
this.sessions.push(session);
|
||||
|
||||
let index = -1;
|
||||
if (session.parentSession) {
|
||||
// Make sure that child sessions are placed after the parent session
|
||||
index = lastIndex(this.sessions, s => s.parentSession === session.parentSession || s === session.parentSession);
|
||||
}
|
||||
if (index >= 0) {
|
||||
this.sessions.splice(index + 1, 0, session);
|
||||
} else {
|
||||
this.sessions.push(session);
|
||||
}
|
||||
this._onDidChangeCallStack.fire(undefined);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export class ReplModel {
|
||||
|
||||
addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise<void> {
|
||||
const expression = new Expression(name);
|
||||
this.addReplElements([expression]);
|
||||
this.addReplElement(expression);
|
||||
return expression.evaluate(this.session, stackFrame, 'repl');
|
||||
}
|
||||
|
||||
@@ -39,26 +39,18 @@ export class ReplModel {
|
||||
}
|
||||
|
||||
if (typeof data === 'string') {
|
||||
const previousElement = this.replElements.length && (this.replElements[this.replElements.length - 1] as SimpleReplElement);
|
||||
|
||||
const toAdd = data.split('\n').map((line, index) => new SimpleReplElement(`topReplElement:${topReplElementCounter++}`, line, sev, index === 0 ? source : undefined));
|
||||
if (previousElement && previousElement.value === '') {
|
||||
// remove potential empty lines between different repl types
|
||||
this.replElements.pop();
|
||||
} else if (previousElement instanceof SimpleReplElement && sev === previousElement.severity && toAdd.length && toAdd[0].sourceData === previousElement.sourceData) {
|
||||
previousElement.value += toAdd.shift()!.value;
|
||||
}
|
||||
this.addReplElements(toAdd);
|
||||
const element = new SimpleReplElement(`topReplElement:${topReplElementCounter++}`, data.trimRight(), sev, source);
|
||||
this.addReplElement(element);
|
||||
} else {
|
||||
// TODO@Isidor hack, we should introduce a new type which is an output that can fetch children like an expression
|
||||
(<any>data).severity = sev;
|
||||
(<any>data).sourceData = source;
|
||||
this.addReplElements([data]);
|
||||
this.addReplElement(data);
|
||||
}
|
||||
}
|
||||
|
||||
private addReplElements(newElements: IReplElement[]): void {
|
||||
this.replElements.push(...newElements);
|
||||
private addReplElement(newElement: IReplElement): void {
|
||||
this.replElements.push(newElement);
|
||||
if (this.replElements.length > MAX_REPL_LENGTH) {
|
||||
this.replElements.splice(0, this.replElements.length - MAX_REPL_LENGTH);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL, EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost';
|
||||
import { IBroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService';
|
||||
import { IRemoteConsoleLog, parse, getFirstFrame } from 'vs/base/node/console';
|
||||
import { IBroadcastService } from 'vs/workbench/services/broadcast/common/broadcast';
|
||||
import { IRemoteConsoleLog, parse, getFirstFrame } from 'vs/base/common/console';
|
||||
import { TaskEvent, TaskEventKind, TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
@@ -315,7 +315,7 @@ export class DebugService implements IDebugService {
|
||||
}
|
||||
}
|
||||
|
||||
return this.createSession(launchForName, launchForName!.getConfiguration(name), noDebug);
|
||||
return this.createSession(launchForName, launchForName!.getConfiguration(name), noDebug, parentSession);
|
||||
})).then(values => values.every(success => !!success)); // Compound launch is a success only if each configuration launched successfully
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ export class DebugService implements IDebugService {
|
||||
return Promise.reject(new Error(message));
|
||||
}
|
||||
|
||||
return this.createSession(launch, config, noDebug);
|
||||
return this.createSession(launch, config, noDebug, parentSession);
|
||||
});
|
||||
}));
|
||||
}).then(success => {
|
||||
@@ -341,7 +341,7 @@ export class DebugService implements IDebugService {
|
||||
/**
|
||||
* gets the debugger for the type, resolves configurations by providers, substitutes variables and runs prelaunch tasks
|
||||
*/
|
||||
private createSession(launch: ILaunch | undefined, config: IConfig | undefined, noDebug: boolean): Promise<boolean> {
|
||||
private createSession(launch: ILaunch | undefined, config: IConfig | undefined, noDebug: boolean, parentSession?: IDebugSession): Promise<boolean> {
|
||||
// We keep the debug type in a separate variable 'type' so that a no-folder config has no attributes.
|
||||
// Storing the type in the config would break extensions that assume that the no-folder case is indicated by an empty config.
|
||||
let type: string | undefined;
|
||||
@@ -386,7 +386,7 @@ export class DebugService implements IDebugService {
|
||||
const workspace = launch ? launch.workspace : undefined;
|
||||
return this.runTaskAndCheckErrors(workspace, resolvedConfig.preLaunchTask).then(result => {
|
||||
if (result === TaskRunResult.Success) {
|
||||
return this.doCreateSession(workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig });
|
||||
return this.doCreateSession(workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, parentSession);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
@@ -415,9 +415,9 @@ export class DebugService implements IDebugService {
|
||||
/**
|
||||
* instantiates the new session, initializes the session, registers session listeners and reports telemetry
|
||||
*/
|
||||
private doCreateSession(root: IWorkspaceFolder | undefined, configuration: { resolved: IConfig, unresolved: IConfig | undefined }): Promise<boolean> {
|
||||
private doCreateSession(root: IWorkspaceFolder | undefined, configuration: { resolved: IConfig, unresolved: IConfig | undefined }, parentSession?: IDebugSession): Promise<boolean> {
|
||||
|
||||
const session = this.instantiationService.createInstance(DebugSession, configuration, root, this.model);
|
||||
const session = this.instantiationService.createInstance(DebugSession, configuration, root, this.model, parentSession);
|
||||
this.model.addSession(session);
|
||||
// register listeners as the very first thing!
|
||||
this.registerSessionListeners(session);
|
||||
|
||||
@@ -57,6 +57,7 @@ export class DebugSession implements IDebugSession {
|
||||
private _configuration: { resolved: IConfig, unresolved: IConfig | undefined },
|
||||
public root: IWorkspaceFolder,
|
||||
private model: DebugModel,
|
||||
private _parentSession: IDebugSession | undefined,
|
||||
@IDebugService private readonly debugService: IDebugService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@IOutputService private readonly outputService: IOutputService,
|
||||
@@ -83,6 +84,10 @@ export class DebugSession implements IDebugSession {
|
||||
return this._configuration.unresolved;
|
||||
}
|
||||
|
||||
get parentSession(): IDebugSession | undefined {
|
||||
return this._parentSession;
|
||||
}
|
||||
|
||||
setConfiguration(configuration: { resolved: IConfig, unresolved: IConfig | undefined }) {
|
||||
this._configuration = configuration;
|
||||
}
|
||||
@@ -178,6 +183,10 @@ export class DebugSession implements IDebugSession {
|
||||
});
|
||||
});
|
||||
});
|
||||
}).then(undefined, err => {
|
||||
this.initialized = true;
|
||||
this._onDidChangeState.fire();
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,11 @@ export class MockDebugService implements IDebugService {
|
||||
}
|
||||
|
||||
export class MockSession implements IDebugSession {
|
||||
|
||||
get parentSession(): IDebugSession | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getReplElements(): IReplElement[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { DebugSession } from 'vs/workbench/contrib/debug/electron-browser/debugSession';
|
||||
import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel';
|
||||
|
||||
function createMockSession(model: DebugModel, name = 'mockSession', parentSession?: DebugSession | undefined): DebugSession {
|
||||
return new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, parentSession, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
}
|
||||
|
||||
suite('Debug - Model', () => {
|
||||
let model: DebugModel;
|
||||
let rawSession: MockRawSession;
|
||||
@@ -109,7 +113,7 @@ suite('Debug - Model', () => {
|
||||
test('threads simple', () => {
|
||||
const threadId = 1;
|
||||
const threadName = 'firstThread';
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const session = createMockSession(model);
|
||||
model.addSession(session);
|
||||
|
||||
assert.equal(model.getSessions(true).length, 1);
|
||||
@@ -136,7 +140,7 @@ suite('Debug - Model', () => {
|
||||
const stoppedReason = 'breakpoint';
|
||||
|
||||
// Add the threads
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const session = createMockSession(model);
|
||||
model.addSession(session);
|
||||
|
||||
session['raw'] = <any>rawSession;
|
||||
@@ -224,7 +228,7 @@ suite('Debug - Model', () => {
|
||||
const runningThreadId = 2;
|
||||
const runningThreadName = 'runningThread';
|
||||
const stoppedReason = 'breakpoint';
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const session = createMockSession(model);
|
||||
model.addSession(session);
|
||||
|
||||
session['raw'] = <any>rawSession;
|
||||
@@ -338,7 +342,7 @@ suite('Debug - Model', () => {
|
||||
});
|
||||
|
||||
test('repl expressions', () => {
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const session = createMockSession(model);
|
||||
assert.equal(session.getReplElements().length, 0);
|
||||
model.addSession(session);
|
||||
|
||||
@@ -362,7 +366,7 @@ suite('Debug - Model', () => {
|
||||
});
|
||||
|
||||
test('stack frame get specific source name', () => {
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const session = createMockSession(model);
|
||||
model.addSession(session);
|
||||
|
||||
let firstStackFrame: StackFrame;
|
||||
@@ -390,10 +394,33 @@ suite('Debug - Model', () => {
|
||||
assert.equal(secondStackFrame.getSpecificSourceName(), '.../x/c/d/internalModule.js');
|
||||
});
|
||||
|
||||
test('debug child sessions are added in correct order', () => {
|
||||
const session = createMockSession(model);
|
||||
model.addSession(session);
|
||||
const secondSession = createMockSession(model, 'mockSession2');
|
||||
model.addSession(secondSession);
|
||||
const firstChild = createMockSession(model, 'firstChild', session);
|
||||
model.addSession(firstChild);
|
||||
const secondChild = createMockSession(model, 'secondChild', session);
|
||||
model.addSession(secondChild);
|
||||
const thirdSession = createMockSession(model, 'mockSession3');
|
||||
model.addSession(thirdSession);
|
||||
const anotherChild = createMockSession(model, 'secondChild', secondSession);
|
||||
model.addSession(anotherChild);
|
||||
|
||||
const sessions = model.getSessions();
|
||||
assert.equal(sessions[0].getId(), session.getId());
|
||||
assert.equal(sessions[1].getId(), firstChild.getId());
|
||||
assert.equal(sessions[2].getId(), secondChild.getId());
|
||||
assert.equal(sessions[3].getId(), secondSession.getId());
|
||||
assert.equal(sessions[4].getId(), anotherChild.getId());
|
||||
assert.equal(sessions[5].getId(), thirdSession.getId());
|
||||
});
|
||||
|
||||
// Repl output
|
||||
|
||||
test('repl output', () => {
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const repl = new ReplModel(session);
|
||||
repl.appendToRepl('first line\n', severity.Error);
|
||||
repl.appendToRepl('second line', severity.Error);
|
||||
|
||||
@@ -24,7 +24,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { lastSessionDateStorageKey } from 'vs/platform/telemetry/node/workbenchCommonProperties';
|
||||
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
@@ -86,11 +86,11 @@ suite('Experiment Service', () => {
|
||||
testConfigurationService = new TestConfigurationService();
|
||||
instantiationService.stub(IConfigurationService, testConfigurationService);
|
||||
instantiationService.stub(ILifecycleService, new TestLifecycleService());
|
||||
instantiationService.stub(IStorageService, { get: (a, b, c) => c, getBoolean: (a, b, c) => c, store: () => { }, remove: () => { } });
|
||||
instantiationService.stub(IStorageService, <Partial<IStorageService>>{ get: (a: string, b: StorageScope, c?: string) => c, getBoolean: (a: string, b: StorageScope, c?: boolean) => c, store: () => { }, remove: () => { } });
|
||||
|
||||
setup(() => {
|
||||
instantiationService.stub(IEnvironmentService, {});
|
||||
instantiationService.stub(IStorageService, { get: (a, b, c) => c, getBoolean: (a, b, c) => c, store: () => { }, remove: () => { } });
|
||||
instantiationService.stub(IStorageService, <Partial<IStorageService>>{ get: (a: string, b: StorageScope, c?: string) => c, getBoolean: (a: string, b: StorageScope, c?: boolean) => c, store: () => { }, remove: () => { } });
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
@@ -196,11 +196,11 @@ suite('Experiment Service', () => {
|
||||
]
|
||||
};
|
||||
|
||||
instantiationService.stub(IStorageService, {
|
||||
get: (a, b, c) => {
|
||||
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
|
||||
get: (a: string, b: StorageScope, c?: string) => {
|
||||
return a === lastSessionDateStorageKey ? 'some-date' : undefined;
|
||||
},
|
||||
getBoolean: (a, b, c) => c, store: () => { }, remove: () => { }
|
||||
getBoolean: (a: string, b: StorageScope, c?: boolean) => c, store: () => { }, remove: () => { }
|
||||
});
|
||||
testObject = instantiationService.createInstance(TestExperimentService);
|
||||
return testObject.getExperimentById('experiment1').then(result => {
|
||||
@@ -240,11 +240,11 @@ suite('Experiment Service', () => {
|
||||
]
|
||||
};
|
||||
|
||||
instantiationService.stub(IStorageService, {
|
||||
get: (a, b, c) => {
|
||||
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
|
||||
get: (a: string, b: StorageScope, c: string | undefined) => {
|
||||
return a === lastSessionDateStorageKey ? 'some-date' : undefined;
|
||||
},
|
||||
getBoolean: (a, b, c) => c, store: () => { }, remove: () => { }
|
||||
getBoolean: (a: string, b: StorageScope, c?: boolean) => c, store: () => { }, remove: () => { }
|
||||
});
|
||||
testObject = instantiationService.createInstance(TestExperimentService);
|
||||
return testObject.getExperimentById('experiment1').then(result => {
|
||||
@@ -372,9 +372,9 @@ suite('Experiment Service', () => {
|
||||
]
|
||||
};
|
||||
|
||||
instantiationService.stub(IStorageService, {
|
||||
get: (a, b, c) => a === 'experiments.experiment1' ? JSON.stringify({ state: ExperimentState.Complete }) : c,
|
||||
store: (a, b, c) => { }
|
||||
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
|
||||
get: (a: string, b: StorageScope, c?: string) => a === 'experiments.experiment1' ? JSON.stringify({ state: ExperimentState.Complete }) : c,
|
||||
store: () => { }
|
||||
});
|
||||
|
||||
testObject = instantiationService.createInstance(TestExperimentService);
|
||||
@@ -400,9 +400,9 @@ suite('Experiment Service', () => {
|
||||
]
|
||||
};
|
||||
|
||||
instantiationService.stub(IStorageService, {
|
||||
get: (a, b, c) => a === 'experiments.experiment1' ? JSON.stringify({ enabled: true, state: ExperimentState.Run }) : c,
|
||||
store: (a, b, c) => { }
|
||||
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
|
||||
get: (a: string, b: StorageScope, c?: string) => a === 'experiments.experiment1' ? JSON.stringify({ enabled: true, state: ExperimentState.Run }) : c,
|
||||
store: () => { }
|
||||
});
|
||||
testObject = instantiationService.createInstance(TestExperimentService);
|
||||
return testObject.getExperimentById('experiment1').then(result => {
|
||||
@@ -508,8 +508,8 @@ suite('Experiment Service', () => {
|
||||
let storageDataExperiment1: ExperimentSettings | null = { enabled: false };
|
||||
let storageDataExperiment2: ExperimentSettings | null = { enabled: false };
|
||||
let storageDataAllExperiments: string[] | null = ['experiment1', 'experiment2', 'experiment3'];
|
||||
instantiationService.stub(IStorageService, {
|
||||
get: (a, b, c) => {
|
||||
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
|
||||
get: (a: string, b: StorageScope, c?: string) => {
|
||||
switch (a) {
|
||||
case 'experiments.experiment1':
|
||||
return JSON.stringify(storageDataExperiment1);
|
||||
@@ -522,7 +522,7 @@ suite('Experiment Service', () => {
|
||||
}
|
||||
return c;
|
||||
},
|
||||
store: (a, b, c) => {
|
||||
store: (a: string, b: any, c: StorageScope) => {
|
||||
switch (a) {
|
||||
case 'experiments.experiment1':
|
||||
storageDataExperiment1 = JSON.parse(b);
|
||||
@@ -537,7 +537,7 @@ suite('Experiment Service', () => {
|
||||
break;
|
||||
}
|
||||
},
|
||||
remove: a => {
|
||||
remove: (a: string) => {
|
||||
switch (a) {
|
||||
case 'experiments.experiment1':
|
||||
storageDataExperiment1 = null;
|
||||
@@ -580,8 +580,8 @@ suite('Experiment Service', () => {
|
||||
let storageDataExperiment3: ExperimentSettings | null = { enabled: true, state: ExperimentState.Evaluating };
|
||||
let storageDataExperiment4: ExperimentSettings | null = { enabled: true, state: ExperimentState.Complete };
|
||||
let storageDataAllExperiments: string[] | null = ['experiment1', 'experiment2', 'experiment3', 'experiment4'];
|
||||
instantiationService.stub(IStorageService, {
|
||||
get: (a, b, c) => {
|
||||
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
|
||||
get: (a: string, b: StorageScope, c?: string) => {
|
||||
switch (a) {
|
||||
case 'experiments.experiment1':
|
||||
return JSON.stringify(storageDataExperiment1);
|
||||
@@ -601,19 +601,19 @@ suite('Experiment Service', () => {
|
||||
store: (a, b, c) => {
|
||||
switch (a) {
|
||||
case 'experiments.experiment1':
|
||||
storageDataExperiment1 = JSON.parse(b);
|
||||
storageDataExperiment1 = JSON.parse(b + '');
|
||||
break;
|
||||
case 'experiments.experiment2':
|
||||
storageDataExperiment2 = JSON.parse(b);
|
||||
storageDataExperiment2 = JSON.parse(b + '');
|
||||
break;
|
||||
case 'experiments.experiment3':
|
||||
storageDataExperiment3 = JSON.parse(b);
|
||||
storageDataExperiment3 = JSON.parse(b + '');
|
||||
break;
|
||||
case 'experiments.experiment4':
|
||||
storageDataExperiment4 = JSON.parse(b);
|
||||
storageDataExperiment4 = JSON.parse(b + '');
|
||||
break;
|
||||
case 'allExperiments':
|
||||
storageDataAllExperiments = JSON.parse(b);
|
||||
storageDataAllExperiments = JSON.parse(b + '');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -768,8 +768,8 @@ suite('Experiment Service', () => {
|
||||
|
||||
let storageDataExperiment3 = { enabled: true, state: ExperimentState.Evaluating };
|
||||
let storageDataExperiment4 = { enabled: true, state: ExperimentState.Evaluating };
|
||||
instantiationService.stub(IStorageService, {
|
||||
get: (a, b, c) => {
|
||||
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
|
||||
get: (a: string, b: StorageScope, c?: string) => {
|
||||
switch (a) {
|
||||
case 'currentOrPreviouslyRunExperiments':
|
||||
return JSON.stringify(['experiment1', 'experiment2']);
|
||||
@@ -781,10 +781,10 @@ suite('Experiment Service', () => {
|
||||
store: (a, b, c) => {
|
||||
switch (a) {
|
||||
case 'experiments.experiment3':
|
||||
storageDataExperiment3 = JSON.parse(b);
|
||||
storageDataExperiment3 = JSON.parse(b + '');
|
||||
break;
|
||||
case 'experiments.experiment4':
|
||||
storageDataExperiment4 = JSON.parse(b);
|
||||
storageDataExperiment4 = JSON.parse(b + '');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -95,6 +95,7 @@ suite('Experimental Prompts', () => {
|
||||
assert.equal(b, promptText);
|
||||
assert.equal(c.length, 2);
|
||||
c[0].run();
|
||||
return undefined!;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -119,6 +120,7 @@ suite('Experimental Prompts', () => {
|
||||
assert.equal(b, promptText);
|
||||
assert.equal(c.length, 2);
|
||||
c[1].run();
|
||||
return undefined!;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -143,6 +145,7 @@ suite('Experimental Prompts', () => {
|
||||
assert.equal(b, promptText);
|
||||
assert.equal(c.length, 2);
|
||||
options.onCancel();
|
||||
return undefined!;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ export class GalleryExtensionsHandler extends QuickOpenHandler {
|
||||
|
||||
getResults(text: string, token: CancellationToken): Promise<IModel<any>> {
|
||||
if (/\./.test(text)) {
|
||||
return this.galleryService.query({ names: [text], pageSize: 1 })
|
||||
return this.galleryService.query({ names: [text], pageSize: 1 }, token)
|
||||
.then(galleryResult => {
|
||||
const entries: SimpleEntry[] = [];
|
||||
const galleryExtension = galleryResult.firstPage[0];
|
||||
|
||||
@@ -85,7 +85,8 @@ export interface IExtensionsWorkbenchService {
|
||||
onChange: Event<IExtension | undefined>;
|
||||
local: IExtension[];
|
||||
queryLocal(): Promise<IExtension[]>;
|
||||
queryGallery(options?: IQueryOptions): Promise<IPager<IExtension>>;
|
||||
queryGallery(token: CancellationToken): Promise<IPager<IExtension>>;
|
||||
queryGallery(options: IQueryOptions, token: CancellationToken): Promise<IPager<IExtension>>;
|
||||
canInstall(extension: IExtension): boolean;
|
||||
install(vsix: string): Promise<IExtension>;
|
||||
install(extension: IExtension, promptToInstallDependencies?: boolean): Promise<IExtension>;
|
||||
|
||||
@@ -739,7 +739,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
getChildren(): Promise<IExtensionData[] | null> {
|
||||
if (this.hasChildren) {
|
||||
const names = arrays.distinct(this.extension.extensionPack, e => e.toLowerCase());
|
||||
return extensionsWorkbenchService.queryGallery({ names, pageSize: names.length })
|
||||
return extensionsWorkbenchService.queryGallery({ names, pageSize: names.length }, CancellationToken.None)
|
||||
.then(result => result.firstPage.map(extension => new ExtensionData(extension, this)));
|
||||
}
|
||||
return Promise.resolve(null);
|
||||
|
||||
@@ -387,7 +387,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
||||
|
||||
if (filteredWanted.length) {
|
||||
try {
|
||||
let validRecommendations = (await this._galleryService.query({ names: filteredWanted, pageSize: filteredWanted.length })).firstPage
|
||||
let validRecommendations = (await this._galleryService.query({ names: filteredWanted, pageSize: filteredWanted.length }, CancellationToken.None)).firstPage
|
||||
.map(extension => extension.identifier.id.toLowerCase());
|
||||
|
||||
if (validRecommendations.length !== filteredWanted.length) {
|
||||
@@ -776,7 +776,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
||||
|
||||
const lookup = product.extensionKeywords || {};
|
||||
const keywords = lookup[fileExtension] || [];
|
||||
this._galleryService.query({ text: `tag:"__ext_${fileExtension}" ${keywords.map(tag => `tag:"${tag}"`)}` }).then(pager => {
|
||||
this._galleryService.query({ text: `tag:"__ext_${fileExtension}" ${keywords.map(tag => `tag:"${tag}"`)}` }, CancellationToken.None).then(pager => {
|
||||
if (!pager || !pager.firstPage || !pager.firstPage.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ import { ExtensionActivationProgress } from 'vs/workbench/contrib/extensions/ele
|
||||
import { ExtensionsAutoProfiler } from 'vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { ExtensionDependencyChecker } from 'vs/workbench/contrib/extensions/electron-browser/extensionsDependencyChecker';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
// Singletons
|
||||
registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService);
|
||||
@@ -268,7 +269,7 @@ CommandsRegistry.registerCommand('_extensions.manage', (accessor: ServicesAccess
|
||||
CommandsRegistry.registerCommand('extension.open', (accessor: ServicesAccessor, extensionId: string) => {
|
||||
const extensionService = accessor.get(IExtensionsWorkbenchService);
|
||||
|
||||
return extensionService.queryGallery({ names: [extensionId], pageSize: 1 }).then(pager => {
|
||||
return extensionService.queryGallery({ names: [extensionId], pageSize: 1 }, CancellationToken.None).then(pager => {
|
||||
if (pager.total !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1538,7 +1538,7 @@ export class InstallWorkspaceRecommendedExtensionsAction extends Action {
|
||||
viewlet.search('@recommended ');
|
||||
viewlet.focus();
|
||||
const names = this.recommendations.map(({ extensionId }) => extensionId);
|
||||
return this.extensionWorkbenchService.queryGallery({ names, source: 'install-all-workspace-recommendations' }).then(pager => {
|
||||
return this.extensionWorkbenchService.queryGallery({ names, source: 'install-all-workspace-recommendations' }, CancellationToken.None).then(pager => {
|
||||
let installPromises: Promise<any>[] = [];
|
||||
let model = new PagedModel(pager);
|
||||
for (let i = 0; i < pager.total; i++) {
|
||||
@@ -1580,7 +1580,7 @@ export class InstallRecommendedExtensionAction extends Action {
|
||||
.then(viewlet => {
|
||||
viewlet.search('@recommended ');
|
||||
viewlet.focus();
|
||||
return this.extensionWorkbenchService.queryGallery({ names: [this.extensionId], source: 'install-recommendation', pageSize: 1 })
|
||||
return this.extensionWorkbenchService.queryGallery({ names: [this.extensionId], source: 'install-recommendation', pageSize: 1 }, CancellationToken.None)
|
||||
.then(pager => {
|
||||
if (pager && pager.firstPage && pager.firstPage.length) {
|
||||
const extension = pager.firstPage[0];
|
||||
|
||||
@@ -15,6 +15,7 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
export class ExtensionDependencyChecker extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
@@ -60,7 +61,7 @@ export class ExtensionDependencyChecker extends Disposable implements IWorkbench
|
||||
private async installMissingDependencies(): Promise<void> {
|
||||
const missingDependencies = await this.getUninstalledMissingDependencies();
|
||||
if (missingDependencies.length) {
|
||||
const extensions = (await this.extensionsWorkbenchService.queryGallery({ names: missingDependencies, pageSize: missingDependencies.length })).firstPage;
|
||||
const extensions = (await this.extensionsWorkbenchService.queryGallery({ names: missingDependencies, pageSize: missingDependencies.length }, CancellationToken.None)).firstPage;
|
||||
if (extensions.length) {
|
||||
await Promise.all(extensions.map(extension => this.extensionsWorkbenchService.install(extension)));
|
||||
this.notificationService.notify({
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import 'vs/css!./media/extensionsViewlet';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ThrottledDelayer, timeout } from 'vs/base/common/async';
|
||||
import { timeout, Delayer } from 'vs/base/common/async';
|
||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
@@ -271,7 +271,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
||||
private recommendedExtensionsContextKey: IContextKey<boolean>;
|
||||
private defaultRecommendedExtensionsContextKey: IContextKey<boolean>;
|
||||
|
||||
private searchDelayer: ThrottledDelayer<any>;
|
||||
private searchDelayer: Delayer<void>;
|
||||
private root: HTMLElement;
|
||||
|
||||
private searchBox: SuggestEnabledInput;
|
||||
@@ -300,7 +300,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
||||
) {
|
||||
super(VIEWLET_ID, `${VIEWLET_ID}.state`, true, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
|
||||
|
||||
this.searchDelayer = new ThrottledDelayer(500);
|
||||
this.searchDelayer = new Delayer(500);
|
||||
this.nonEmptyWorkspaceContextKey = NonEmptyWorkspaceContext.bindTo(contextKeyService);
|
||||
this.searchExtensionsContextKey = SearchExtensionsContext.bindTo(contextKeyService);
|
||||
this.hasInstalledExtensionsContextKey = HasInstalledExtensionsContext.bindTo(contextKeyService);
|
||||
|
||||
@@ -44,6 +44,7 @@ import { IAction } from 'vs/base/common/actions';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
||||
|
||||
class ExtensionsViewState extends Disposable implements IExtensionsViewState {
|
||||
|
||||
@@ -69,6 +70,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
private badge: CountBadge;
|
||||
protected badgeContainer: HTMLElement;
|
||||
private list: WorkbenchPagedList<IExtension> | null;
|
||||
private queryRequest: { query: string, request: CancelablePromise<IPagedModel<IExtension>> } | null;
|
||||
|
||||
constructor(
|
||||
private options: IViewletViewOptions,
|
||||
@@ -139,6 +141,14 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
}
|
||||
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
if (this.queryRequest) {
|
||||
if (this.queryRequest.query === query) {
|
||||
return this.queryRequest.request;
|
||||
}
|
||||
this.queryRequest.request.cancel();
|
||||
this.queryRequest = null;
|
||||
}
|
||||
|
||||
const parsedQuery = Query.parse(query);
|
||||
|
||||
let options: IQueryOptions = {
|
||||
@@ -152,21 +162,24 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
}
|
||||
|
||||
const successCallback = model => {
|
||||
this.queryRequest = null;
|
||||
this.setModel(model);
|
||||
return model;
|
||||
};
|
||||
const errorCallback = e => {
|
||||
console.warn('Error querying extensions gallery', e);
|
||||
const model = new PagedModel([]);
|
||||
this.setModel(model, true);
|
||||
return model;
|
||||
if (!isPromiseCanceledError(e)) {
|
||||
this.queryRequest = null;
|
||||
console.warn('Error querying extensions gallery', e);
|
||||
this.setModel(model, true);
|
||||
}
|
||||
return this.list ? this.list.model : model;
|
||||
};
|
||||
|
||||
if (ExtensionsListView.isInstalledExtensionsQuery(query) || /@builtin/.test(query)) {
|
||||
return await this.queryLocal(parsedQuery, options).then(successCallback).catch(errorCallback);
|
||||
}
|
||||
|
||||
return await this.queryGallery(parsedQuery, options).then(successCallback).catch(errorCallback);
|
||||
const isLocalQuery = ExtensionsListView.isInstalledExtensionsQuery(query) || /@builtin/.test(query);
|
||||
const request = createCancelablePromise(token => (isLocalQuery ? this.queryLocal(parsedQuery, options) : this.queryGallery(parsedQuery, options, token)).then(successCallback).catch(errorCallback));
|
||||
this.queryRequest = { query, request };
|
||||
return request.then(successCallback).catch(errorCallback);
|
||||
}
|
||||
|
||||
count(): number {
|
||||
@@ -326,7 +339,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
return new PagedModel([]);
|
||||
}
|
||||
|
||||
private async queryGallery(query: Query, options: IQueryOptions): Promise<IPagedModel<IExtension>> {
|
||||
private async queryGallery(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
|
||||
const hasUserDefinedSortOrder = options.sortBy !== undefined;
|
||||
if (!hasUserDefinedSortOrder && !query.value.trim()) {
|
||||
options.sortBy = SortBy.InstallCount;
|
||||
@@ -343,25 +356,25 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
}
|
||||
|
||||
if (names.length) {
|
||||
return this.extensionsWorkbenchService.queryGallery({ names, source: 'queryById' })
|
||||
return this.extensionsWorkbenchService.queryGallery({ names, source: 'queryById' }, token)
|
||||
.then(pager => this.getPagedModel(pager));
|
||||
}
|
||||
|
||||
if (ExtensionsListView.isWorkspaceRecommendedExtensionsQuery(query.value)) {
|
||||
return this.getWorkspaceRecommendationsModel(query, options);
|
||||
return this.getWorkspaceRecommendationsModel(query, options, token);
|
||||
} else if (ExtensionsListView.isKeymapsRecommendedExtensionsQuery(query.value)) {
|
||||
return this.getKeymapRecommendationsModel(query, options);
|
||||
return this.getKeymapRecommendationsModel(query, options, token);
|
||||
} else if (/@recommended:all/i.test(query.value) || ExtensionsListView.isSearchRecommendedExtensionsQuery(query.value)) {
|
||||
return this.getAllRecommendationsModel(query, options);
|
||||
return this.getAllRecommendationsModel(query, options, token);
|
||||
} else if (ExtensionsListView.isRecommendedExtensionsQuery(query.value)) {
|
||||
return this.getRecommendationsModel(query, options);
|
||||
return this.getRecommendationsModel(query, options, token);
|
||||
// {{SQL CARBON EDIT}}
|
||||
} else if (ExtensionsListView.isAllMarketplaceExtensionsQuery(query.value)) {
|
||||
return this.getAllMarketplaceModel(query, options);
|
||||
return this.getAllMarketplaceModel(query, options, token);
|
||||
}
|
||||
|
||||
if (/\bcurated:([^\s]+)\b/.test(query.value)) {
|
||||
return this.getCuratedModel(query, options);
|
||||
return this.getCuratedModel(query, options, token);
|
||||
}
|
||||
|
||||
let text = query.value;
|
||||
@@ -385,7 +398,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
|
||||
if (text !== query.value) {
|
||||
options = assign(options, { text: text.substr(0, 350), source: 'file-extension-tags' });
|
||||
return this.extensionsWorkbenchService.queryGallery(options).then(pager => this.getPagedModel(pager));
|
||||
return this.extensionsWorkbenchService.queryGallery(options, token).then(pager => this.getPagedModel(pager));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,7 +419,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
options.source = 'viewlet';
|
||||
}
|
||||
|
||||
const pager = await this.extensionsWorkbenchService.queryGallery(options);
|
||||
const pager = await this.extensionsWorkbenchService.queryGallery(options, token);
|
||||
|
||||
let positionToUpdate = 0;
|
||||
for (const preferredResult of preferredResults) {
|
||||
@@ -453,7 +466,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
}
|
||||
|
||||
// Get All types of recommendations, trimmed to show a max of 8 at any given time
|
||||
private getAllRecommendationsModel(query: Query, options: IQueryOptions): Promise<IPagedModel<IExtension>> {
|
||||
private getAllRecommendationsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
|
||||
const value = query.value.replace(/@recommended:all/g, '').replace(/@recommended/g, '').trim().toLowerCase();
|
||||
|
||||
return this.extensionsWorkbenchService.queryLocal()
|
||||
@@ -486,7 +499,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
return Promise.resolve(new PagedModel([]));
|
||||
}
|
||||
options.source = 'recommendations-all';
|
||||
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }))
|
||||
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }), token)
|
||||
.then(pager => {
|
||||
this.sortFirstPage(pager, names);
|
||||
return this.getPagedModel(pager || []);
|
||||
@@ -495,12 +508,12 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
});
|
||||
}
|
||||
|
||||
private async getCuratedModel(query: Query, options: IQueryOptions): Promise<IPagedModel<IExtension>> {
|
||||
private async getCuratedModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
|
||||
const value = query.value.replace(/curated:/g, '').trim();
|
||||
const names = await this.experimentService.getCuratedExtensionsList(value);
|
||||
if (Array.isArray(names) && names.length) {
|
||||
options.source = `curated:${value}`;
|
||||
const pager = await this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }));
|
||||
const pager = await this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }), token);
|
||||
this.sortFirstPage(pager, names);
|
||||
return this.getPagedModel(pager || []);
|
||||
}
|
||||
@@ -508,7 +521,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
}
|
||||
|
||||
// Get All types of recommendations other than Workspace recommendations, trimmed to show a max of 8 at any given time
|
||||
private getRecommendationsModel(query: Query, options: IQueryOptions): Promise<IPagedModel<IExtension>> {
|
||||
private getRecommendationsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
|
||||
const value = query.value.replace(/@recommended/g, '').trim().toLowerCase();
|
||||
|
||||
return this.extensionsWorkbenchService.queryLocal()
|
||||
@@ -546,7 +559,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
return Promise.resolve(new PagedModel([]));
|
||||
}
|
||||
options.source = 'recommendations';
|
||||
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }))
|
||||
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }), token)
|
||||
.then(pager => {
|
||||
this.sortFirstPage(pager, names);
|
||||
return this.getPagedModel(pager || []);
|
||||
@@ -556,7 +569,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
private getAllMarketplaceModel(query: Query, options: IQueryOptions): Promise<IPagedModel<IExtension>> {
|
||||
private getAllMarketplaceModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
|
||||
const value = query.value.trim().toLowerCase();
|
||||
return this.extensionsWorkbenchService.queryLocal()
|
||||
.then(result => result.filter(e => e.type === ExtensionType.User))
|
||||
@@ -564,7 +577,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
return this.tipsService.getOtherRecommendations().then((recommmended) => {
|
||||
const installedExtensions = local.map(x => `${x.publisher}.${x.name}`);
|
||||
options = assign(options, { text: value, source: 'searchText' });
|
||||
return this.extensionsWorkbenchService.queryGallery(options).then((pager) => {
|
||||
return this.extensionsWorkbenchService.queryGallery(options, token).then((pager) => {
|
||||
// filter out installed extensions
|
||||
pager.firstPage = pager.firstPage.filter((p) => {
|
||||
return installedExtensions.indexOf(`${p.publisher}.${p.name}`) === -1;
|
||||
@@ -624,7 +637,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
return installed.some(i => areSameExtensions(i.identifier, { id: recommendation.extensionId }));
|
||||
}
|
||||
|
||||
private getWorkspaceRecommendationsModel(query: Query, options: IQueryOptions): Promise<IPagedModel<IExtension>> {
|
||||
private getWorkspaceRecommendationsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
|
||||
const value = query.value.replace(/@recommended:workspace/g, '').trim().toLowerCase();
|
||||
return this.tipsService.getWorkspaceRecommendations()
|
||||
.then(recommendations => {
|
||||
@@ -640,12 +653,12 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
return Promise.resolve(new PagedModel([]));
|
||||
}
|
||||
options.source = 'recommendations-workspace';
|
||||
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }))
|
||||
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }), token)
|
||||
.then(pager => this.getPagedModel(pager || []));
|
||||
});
|
||||
}
|
||||
|
||||
private getKeymapRecommendationsModel(query: Query, options: IQueryOptions): Promise<IPagedModel<IExtension>> {
|
||||
private getKeymapRecommendationsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
|
||||
const value = query.value.replace(/@recommended:keymaps/g, '').trim().toLowerCase();
|
||||
const names: string[] = this.tipsService.getKeymapRecommendations().map(({ extensionId }) => extensionId)
|
||||
.filter(extensionId => extensionId.toLowerCase().indexOf(value) > -1);
|
||||
@@ -654,7 +667,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
return Promise.resolve(new PagedModel([]));
|
||||
}
|
||||
options.source = 'recommendations-keymaps';
|
||||
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }))
|
||||
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }), token)
|
||||
.then(result => this.getPagedModel(result));
|
||||
}
|
||||
|
||||
@@ -735,6 +748,10 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
if (this.queryRequest) {
|
||||
this.queryRequest.request.cancel();
|
||||
this.queryRequest = null;
|
||||
}
|
||||
this.disposables = dispose(this.disposables);
|
||||
this.list = null;
|
||||
}
|
||||
|
||||
@@ -463,12 +463,16 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
||||
});
|
||||
}
|
||||
|
||||
queryGallery(options: IQueryOptions = {}): Promise<IPager<IExtension>> {
|
||||
queryGallery(token: CancellationToken): Promise<IPager<IExtension>>;
|
||||
queryGallery(options: IQueryOptions, token: CancellationToken): Promise<IPager<IExtension>>;
|
||||
queryGallery(arg1: any, arg2?: any): Promise<IPager<IExtension>> {
|
||||
const options: IQueryOptions = CancellationToken.isCancellationToken(arg1) ? {} : arg1;
|
||||
const token: CancellationToken = CancellationToken.isCancellationToken(arg1) ? arg1 : arg2;
|
||||
return this.extensionService.getExtensionsReport()
|
||||
.then(report => {
|
||||
const maliciousSet = getMaliciousExtensionsSet(report);
|
||||
|
||||
return this.galleryService.query(options)
|
||||
return this.galleryService.query(options, token)
|
||||
.then(result => mapPager(result, gallery => this.fromGallery(gallery, maliciousSet)))
|
||||
.then(undefined, err => {
|
||||
if (/No extension gallery service configured/.test(err.message)) {
|
||||
@@ -610,10 +614,10 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
||||
|
||||
const promises: Promise<IPager<IExtension>>[] = [];
|
||||
if (ids.length) {
|
||||
promises.push(this.queryGallery({ ids, pageSize: ids.length }));
|
||||
promises.push(this.queryGallery({ ids, pageSize: ids.length }, CancellationToken.None));
|
||||
}
|
||||
if (names.length) {
|
||||
promises.push(this.queryGallery({ names, pageSize: names.length }));
|
||||
promises.push(this.queryGallery({ names, pageSize: names.length }, CancellationToken.None));
|
||||
}
|
||||
|
||||
return Promise.all(promises).then(() => undefined);
|
||||
@@ -1056,7 +1060,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
||||
.then(() => this.open(extension));
|
||||
}
|
||||
|
||||
return this.queryGallery({ names: [extensionId], source: 'uri' }).then(result => {
|
||||
return this.queryGallery({ names: [extensionId], source: 'uri' }, CancellationToken.None).then(result => {
|
||||
if (result.total < 1) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA
|
||||
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
|
||||
import { ExtensionIdentifier, IExtensionContributions, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
suite('ExtensionsActions Test', () => {
|
||||
|
||||
@@ -110,7 +111,7 @@ suite('ExtensionsActions Test', () => {
|
||||
return workbenchService.queryLocal()
|
||||
.then(() => {
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier })));
|
||||
return workbenchService.queryGallery()
|
||||
return workbenchService.queryGallery(CancellationToken.None)
|
||||
.then((paged) => {
|
||||
testObject.extension = paged.firstPage[0];
|
||||
assert.ok(!testObject.enabled);
|
||||
@@ -126,7 +127,7 @@ suite('ExtensionsActions Test', () => {
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
return workbenchService.queryGallery()
|
||||
return workbenchService.queryGallery(CancellationToken.None)
|
||||
.then((paged) => {
|
||||
testObject.extension = paged.firstPage[0];
|
||||
installEvent.fire({ identifier: gallery.identifier, gallery });
|
||||
@@ -143,7 +144,7 @@ suite('ExtensionsActions Test', () => {
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
return workbenchService.queryGallery()
|
||||
return workbenchService.queryGallery(CancellationToken.None)
|
||||
.then((paged) => {
|
||||
testObject.extension = paged.firstPage[0];
|
||||
assert.ok(testObject.enabled);
|
||||
@@ -257,7 +258,7 @@ suite('ExtensionsActions Test', () => {
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery()
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
.then(paged => {
|
||||
testObject.extension = paged.firstPage[0];
|
||||
|
||||
@@ -299,7 +300,7 @@ suite('ExtensionsActions Test', () => {
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
return workbenchService.queryGallery()
|
||||
return workbenchService.queryGallery(CancellationToken.None)
|
||||
.then((paged) => {
|
||||
testObject.extension = paged.firstPage[0];
|
||||
assert.ok(testObject.enabled);
|
||||
@@ -329,7 +330,7 @@ suite('ExtensionsActions Test', () => {
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
return workbenchService.queryGallery()
|
||||
return workbenchService.queryGallery(CancellationToken.None)
|
||||
.then((paged) => {
|
||||
testObject.extension = paged.firstPage[0];
|
||||
installEvent.fire({ identifier: gallery.identifier, gallery });
|
||||
@@ -387,7 +388,7 @@ suite('ExtensionsActions Test', () => {
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
const gallery = aGalleryExtension('a', { version: '1.0.0' });
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery()
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
.then((paged) => {
|
||||
testObject.extension = paged.firstPage[0];
|
||||
assert.ok(!testObject.enabled);
|
||||
@@ -404,7 +405,7 @@ suite('ExtensionsActions Test', () => {
|
||||
.then(extensions => {
|
||||
testObject.extension = extensions[0];
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier, version: local.manifest.version })));
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery()
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
.then(extensions => assert.ok(!testObject.enabled));
|
||||
});
|
||||
});
|
||||
@@ -419,7 +420,7 @@ suite('ExtensionsActions Test', () => {
|
||||
.then(extensions => {
|
||||
testObject.extension = extensions[0];
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier, version: '1.0.1' })));
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery()
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
.then(extensions => assert.ok(!testObject.enabled));
|
||||
});
|
||||
});
|
||||
@@ -442,7 +443,7 @@ suite('ExtensionsActions Test', () => {
|
||||
c();
|
||||
}
|
||||
});
|
||||
instantiationService.get(IExtensionsWorkbenchService).queryGallery();
|
||||
instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -458,7 +459,7 @@ suite('ExtensionsActions Test', () => {
|
||||
testObject.extension = extensions[0];
|
||||
const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.1' });
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery()
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
.then(extensions => {
|
||||
installEvent.fire({ identifier: local.identifier, gallery });
|
||||
assert.ok(!testObject.enabled);
|
||||
@@ -494,7 +495,7 @@ suite('ExtensionsActions Test', () => {
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery()
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
.then(page => {
|
||||
testObject.extension = page.firstPage[0];
|
||||
assert.ok(!testObject.enabled);
|
||||
@@ -509,7 +510,7 @@ suite('ExtensionsActions Test', () => {
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery()
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
.then(page => {
|
||||
testObject.extension = page.firstPage[0];
|
||||
|
||||
@@ -526,7 +527,7 @@ suite('ExtensionsActions Test', () => {
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery()
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
.then(page => {
|
||||
testObject.extension = page.firstPage[0];
|
||||
installEvent.fire({ identifier: gallery.identifier, gallery });
|
||||
@@ -750,7 +751,7 @@ suite('ExtensionsActions Test', () => {
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery()
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
.then(page => {
|
||||
const testObject: ExtensionsActions.EnableDropDownAction = instantiationService.createInstance(ExtensionsActions.EnableDropDownAction);
|
||||
testObject.extension = page.firstPage[0];
|
||||
@@ -762,7 +763,7 @@ suite('ExtensionsActions Test', () => {
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery()
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
.then(page => {
|
||||
const testObject: ExtensionsActions.EnableDropDownAction = instantiationService.createInstance(ExtensionsActions.EnableDropDownAction);
|
||||
testObject.extension = page.firstPage[0];
|
||||
@@ -934,7 +935,7 @@ suite('ExtensionsActions Test', () => {
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery()
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
.then(page => {
|
||||
const testObject: ExtensionsActions.DisableDropDownAction = instantiationService.createInstance(ExtensionsActions.DisableDropDownAction, [{ identifier: new ExtensionIdentifier('pub.a'), extensionLocation: URI.file('pub.a') }]);
|
||||
testObject.extension = page.firstPage[0];
|
||||
@@ -946,7 +947,7 @@ suite('ExtensionsActions Test', () => {
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery()
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
.then(page => {
|
||||
const testObject: ExtensionsActions.DisableDropDownAction = instantiationService.createInstance(ExtensionsActions.DisableDropDownAction, [{ identifier: new ExtensionIdentifier('pub.a'), extensionLocation: URI.file('pub.a') }]);
|
||||
testObject.extension = page.firstPage[0];
|
||||
@@ -998,7 +999,7 @@ suite('ExtensionsActions Test', () => {
|
||||
c();
|
||||
}
|
||||
});
|
||||
workbenchService.queryGallery();
|
||||
workbenchService.queryGallery(CancellationToken.None);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1020,7 +1021,7 @@ suite('ExtensionsActions Test', () => {
|
||||
c();
|
||||
}
|
||||
});
|
||||
workbenchService.queryGallery();
|
||||
workbenchService.queryGallery(CancellationToken.None);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1034,7 +1035,7 @@ suite('ExtensionsActions Test', () => {
|
||||
return workbenchService.queryLocal()
|
||||
.then(() => {
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(...gallery));
|
||||
return workbenchService.queryGallery()
|
||||
return workbenchService.queryGallery(CancellationToken.None)
|
||||
.then(() => {
|
||||
installEvent.fire({ identifier: local[0].identifier, gallery: gallery[0] });
|
||||
installEvent.fire({ identifier: local[1].identifier, gallery: gallery[1] });
|
||||
@@ -1056,7 +1057,7 @@ suite('ExtensionsActions Test', () => {
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
return workbenchService.queryGallery()
|
||||
return workbenchService.queryGallery(CancellationToken.None)
|
||||
.then((paged) => {
|
||||
testObject.extension = paged.firstPage[0];
|
||||
installEvent.fire({ identifier: gallery.identifier, gallery });
|
||||
@@ -1086,7 +1087,7 @@ suite('ExtensionsActions Test', () => {
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
const paged = await instantiationService.get(IExtensionsWorkbenchService).queryGallery();
|
||||
const paged = await instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None);
|
||||
testObject.extension = paged.firstPage[0];
|
||||
assert.ok(!testObject.enabled);
|
||||
|
||||
@@ -1108,7 +1109,7 @@ suite('ExtensionsActions Test', () => {
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery()
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
.then((paged) => {
|
||||
testObject.extension = paged.firstPage[0];
|
||||
const identifier = gallery.identifier;
|
||||
@@ -1320,7 +1321,7 @@ suite('ExtensionsActions Test', () => {
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
const paged = await instantiationService.get(IExtensionsWorkbenchService).queryGallery();
|
||||
const paged = await instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None);
|
||||
testObject.extension = paged.firstPage[0];
|
||||
assert.ok(!testObject.enabled);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ import { IExperimentService, ExperimentService, ExperimentState, ExperimentActio
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
|
||||
import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService';
|
||||
import { ExtensionIdentifier, ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionIdentifier, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
|
||||
|
||||
|
||||
@@ -124,13 +124,13 @@ suite('ExtensionsListView Tests', () => {
|
||||
instantiationService.stubPromise(IExperimentService, 'getExperimentsByType', []);
|
||||
|
||||
instantiationService.stub(IExtensionService, {
|
||||
getExtensions: () => {
|
||||
getExtensions: (): Promise<IExtensionDescription[]> => {
|
||||
return Promise.resolve([
|
||||
{ identifier: new ExtensionIdentifier(localEnabledTheme.identifier.id) },
|
||||
{ identifier: new ExtensionIdentifier(localEnabledLanguage.identifier.id) },
|
||||
{ identifier: new ExtensionIdentifier(localRandom.identifier.id) },
|
||||
{ identifier: new ExtensionIdentifier(builtInTheme.identifier.id) },
|
||||
{ identifier: new ExtensionIdentifier(builtInBasic.identifier.id) }
|
||||
toExtensionDescription(localEnabledTheme),
|
||||
toExtensionDescription(localEnabledLanguage),
|
||||
toExtensionDescription(localRandom),
|
||||
toExtensionDescription(builtInTheme),
|
||||
toExtensionDescription(builtInBasic)
|
||||
]);
|
||||
}
|
||||
});
|
||||
@@ -185,8 +185,8 @@ suite('ExtensionsListView Tests', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('Test installed query results', () => {
|
||||
const allInstalledCheck = testableView.show('@installed').then(result => {
|
||||
test('Test installed query results', async () => {
|
||||
await testableView.show('@installed').then(result => {
|
||||
assert.equal(result.length, 5, 'Unexpected number of results for @installed query');
|
||||
const actual = [result.get(0).name, result.get(1).name, result.get(2).name, result.get(3).name, result.get(4).name].sort();
|
||||
const expected = [localDisabledTheme.manifest.name, localEnabledTheme.manifest.name, localRandom.manifest.name, localDisabledLanguage.manifest.name, localEnabledLanguage.manifest.name];
|
||||
@@ -195,125 +195,102 @@ suite('ExtensionsListView Tests', () => {
|
||||
}
|
||||
});
|
||||
|
||||
const installedCheck = testableView.show('@installed first').then(result => {
|
||||
await testableView.show('@installed first').then(result => {
|
||||
assert.equal(result.length, 2, 'Unexpected number of results for @installed query');
|
||||
assert.equal(result.get(0).name, localDisabledTheme.manifest.name, 'Unexpected extension for @installed query with search text.');
|
||||
assert.equal(result.get(1).name, localEnabledTheme.manifest.name, 'Unexpected extension for @installed query with search text.');
|
||||
});
|
||||
|
||||
const allDisabledCheck = testableView.show('@disabled').then(result => {
|
||||
await testableView.show('@disabled').then(result => {
|
||||
assert.equal(result.length, 2, 'Unexpected number of results for @disabled query');
|
||||
assert.equal(result.get(0).name, localDisabledTheme.manifest.name, 'Unexpected extension for @disabled query.');
|
||||
assert.equal(result.get(1).name, localDisabledLanguage.manifest.name, 'Unexpected extension for @disabled query.');
|
||||
});
|
||||
|
||||
const allEnabledCheck = testableView.show('@enabled').then(result => {
|
||||
await testableView.show('@enabled').then(result => {
|
||||
assert.equal(result.length, 3, 'Unexpected number of results for @enabled query');
|
||||
assert.equal(result.get(0).name, localEnabledTheme.manifest.name, 'Unexpected extension for @enabled query.');
|
||||
assert.equal(result.get(1).name, localRandom.manifest.name, 'Unexpected extension for @enabled query.');
|
||||
assert.equal(result.get(2).name, localEnabledLanguage.manifest.name, 'Unexpected extension for @enabled query.');
|
||||
});
|
||||
|
||||
const allBuiltinThemesCheck = testableView.show('@builtin:themes').then(result => {
|
||||
await testableView.show('@builtin:themes').then(result => {
|
||||
assert.equal(result.length, 1, 'Unexpected number of results for @builtin:themes query');
|
||||
assert.equal(result.get(0).name, builtInTheme.manifest.name, 'Unexpected extension for @builtin:themes query.');
|
||||
});
|
||||
|
||||
const allBuiltinBasicsCheck = testableView.show('@builtin:basics').then(result => {
|
||||
await testableView.show('@builtin:basics').then(result => {
|
||||
assert.equal(result.length, 1, 'Unexpected number of results for @builtin:basics query');
|
||||
assert.equal(result.get(0).name, builtInBasic.manifest.name, 'Unexpected extension for @builtin:basics query.');
|
||||
});
|
||||
|
||||
const allBuiltinCheck = testableView.show('@builtin').then(result => {
|
||||
await testableView.show('@builtin').then(result => {
|
||||
assert.equal(result.length, 2, 'Unexpected number of results for @builtin query');
|
||||
assert.equal(result.get(0).name, builtInBasic.manifest.name, 'Unexpected extension for @builtin query.');
|
||||
assert.equal(result.get(1).name, builtInTheme.manifest.name, 'Unexpected extension for @builtin query.');
|
||||
});
|
||||
|
||||
const builtinCheck = testableView.show('@builtin my-theme').then(result => {
|
||||
await testableView.show('@builtin my-theme').then(result => {
|
||||
assert.equal(result.length, 1, 'Unexpected number of results for @builtin query');
|
||||
assert.equal(result.get(0).name, builtInTheme.manifest.name, 'Unexpected extension for @builtin query.');
|
||||
});
|
||||
|
||||
return Promise.all([
|
||||
allInstalledCheck,
|
||||
installedCheck,
|
||||
allDisabledCheck,
|
||||
allEnabledCheck,
|
||||
allBuiltinThemesCheck,
|
||||
allBuiltinBasicsCheck,
|
||||
allBuiltinCheck,
|
||||
builtinCheck]);
|
||||
});
|
||||
|
||||
test('Test installed query with category', () => {
|
||||
const installedCategoryWithoutQuotesCheck = testableView.show('@installed category:themes').then(result => {
|
||||
test('Test installed query with category', async () => {
|
||||
await testableView.show('@installed category:themes').then(result => {
|
||||
assert.equal(result.length, 2, 'Unexpected number of results for @installed query with category');
|
||||
assert.equal(result.get(0).name, localDisabledTheme.manifest.name, 'Unexpected extension for @installed query with category.');
|
||||
assert.equal(result.get(1).name, localEnabledTheme.manifest.name, 'Unexpected extension for @installed query with category.');
|
||||
});
|
||||
|
||||
const installedCategoryWithQuotesCheck = testableView.show('@installed category:"themes"').then(result => {
|
||||
await testableView.show('@installed category:"themes"').then(result => {
|
||||
assert.equal(result.length, 2, 'Unexpected number of results for @installed query with quoted category');
|
||||
assert.equal(result.get(0).name, localDisabledTheme.manifest.name, 'Unexpected extension for @installed query with quoted category.');
|
||||
assert.equal(result.get(1).name, localEnabledTheme.manifest.name, 'Unexpected extension for @installed query with quoted category.');
|
||||
});
|
||||
|
||||
const installedCategoryWithSpaceCheck = testableView.show('@installed category:"programming languages"').then(result => {
|
||||
await testableView.show('@installed category:"programming languages"').then(result => {
|
||||
assert.equal(result.length, 2, 'Unexpected number of results for @installed query with quoted category including space');
|
||||
assert.equal(result.get(0).name, localDisabledLanguage.manifest.name, 'Unexpected extension for @installed query with quoted category inlcuding space.');
|
||||
assert.equal(result.get(1).name, localEnabledLanguage.manifest.name, 'Unexpected extension for @installed query with quoted category including space.');
|
||||
});
|
||||
|
||||
const installedMultipleCategoryCheck = testableView.show('@installed category:themes category:random').then(result => {
|
||||
await testableView.show('@installed category:themes category:random').then(result => {
|
||||
assert.equal(result.length, 3, 'Unexpected number of results for @installed query with multiple category');
|
||||
assert.equal(result.get(0).name, localDisabledTheme.manifest.name, 'Unexpected extension for @installed query with multiple category.');
|
||||
assert.equal(result.get(1).name, localEnabledTheme.manifest.name, 'Unexpected extension for @installed query with multiple category.');
|
||||
assert.equal(result.get(2).name, localRandom.manifest.name, 'Unexpected extension for @installed query with multiple category.');
|
||||
});
|
||||
|
||||
const enabledCategoryWithoutQuotesCheck = testableView.show('@enabled category:themes').then(result => {
|
||||
await testableView.show('@enabled category:themes').then(result => {
|
||||
assert.equal(result.length, 1, 'Unexpected number of results for @enabled query with category');
|
||||
assert.equal(result.get(0).name, localEnabledTheme.manifest.name, 'Unexpected extension for @enabled query with category.');
|
||||
});
|
||||
|
||||
const enabledCategoryWithQuotesCheck = testableView.show('@enabled category:"themes"').then(result => {
|
||||
await testableView.show('@enabled category:"themes"').then(result => {
|
||||
assert.equal(result.length, 1, 'Unexpected number of results for @enabled query with quoted category');
|
||||
assert.equal(result.get(0).name, localEnabledTheme.manifest.name, 'Unexpected extension for @enabled query with quoted category.');
|
||||
});
|
||||
|
||||
const enabledCategoryWithSpaceCheck = testableView.show('@enabled category:"programming languages"').then(result => {
|
||||
await testableView.show('@enabled category:"programming languages"').then(result => {
|
||||
assert.equal(result.length, 1, 'Unexpected number of results for @enabled query with quoted category inlcuding space');
|
||||
assert.equal(result.get(0).name, localEnabledLanguage.manifest.name, 'Unexpected extension for @enabled query with quoted category including space.');
|
||||
});
|
||||
|
||||
const disabledCategoryWithoutQuotesCheck = testableView.show('@disabled category:themes').then(result => {
|
||||
await testableView.show('@disabled category:themes').then(result => {
|
||||
assert.equal(result.length, 1, 'Unexpected number of results for @disabled query with category');
|
||||
assert.equal(result.get(0).name, localDisabledTheme.manifest.name, 'Unexpected extension for @disabled query with category.');
|
||||
});
|
||||
|
||||
const disabledCategoryWithQuotesCheck = testableView.show('@disabled category:"themes"').then(result => {
|
||||
await testableView.show('@disabled category:"themes"').then(result => {
|
||||
assert.equal(result.length, 1, 'Unexpected number of results for @disabled query with quoted category');
|
||||
assert.equal(result.get(0).name, localDisabledTheme.manifest.name, 'Unexpected extension for @disabled query with quoted category.');
|
||||
});
|
||||
|
||||
const disabledCategoryWithSpaceCheck = testableView.show('@disabled category:"programming languages"').then(result => {
|
||||
await testableView.show('@disabled category:"programming languages"').then(result => {
|
||||
assert.equal(result.length, 1, 'Unexpected number of results for @disabled query with quoted category inlcuding space');
|
||||
assert.equal(result.get(0).name, localDisabledLanguage.manifest.name, 'Unexpected extension for @disabled query with quoted category including space.');
|
||||
});
|
||||
|
||||
return Promise.resolve([
|
||||
installedCategoryWithoutQuotesCheck,
|
||||
installedCategoryWithQuotesCheck,
|
||||
installedCategoryWithSpaceCheck,
|
||||
installedMultipleCategoryCheck,
|
||||
enabledCategoryWithoutQuotesCheck,
|
||||
enabledCategoryWithQuotesCheck,
|
||||
enabledCategoryWithSpaceCheck,
|
||||
disabledCategoryWithoutQuotesCheck,
|
||||
disabledCategoryWithQuotesCheck,
|
||||
disabledCategoryWithSpaceCheck
|
||||
]);
|
||||
});
|
||||
|
||||
test('Test @recommended:workspace query', () => {
|
||||
@@ -523,5 +500,15 @@ suite('ExtensionsListView Tests', () => {
|
||||
function aPage<T>(...objects: T[]): IPager<T> {
|
||||
return { firstPage: objects, total: objects.length, pageSize: objects.length, getPage: () => null! };
|
||||
}
|
||||
|
||||
function toExtensionDescription(local: ILocalExtension): IExtensionDescription {
|
||||
return {
|
||||
identifier: new ExtensionIdentifier(local.identifier.id),
|
||||
isBuiltin: local.type === ExtensionType.System,
|
||||
isUnderDevelopment: false,
|
||||
extensionLocation: local.location,
|
||||
...local.manifest
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -70,10 +70,8 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
|
||||
instantiationService.stub(IWorkspaceContextService, new TestContextService());
|
||||
instantiationService.stub(IConfigurationService, {
|
||||
onDidUpdateConfiguration: () => { },
|
||||
onDidChangeConfiguration: () => { },
|
||||
getConfiguration: () => ({}),
|
||||
getValue: (key) => {
|
||||
onDidChangeConfiguration: () => { return undefined!; },
|
||||
getValue: (key?) => {
|
||||
return (key === AutoCheckUpdatesConfigurationKey || key === AutoUpdateConfigurationKey) ? true : undefined;
|
||||
}
|
||||
});
|
||||
@@ -91,7 +89,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
|
||||
instantiationService.set(IExtensionTipsService, instantiationService.createInstance(ExtensionTipsService));
|
||||
|
||||
instantiationService.stub(INotificationService, { prompt: () => null });
|
||||
instantiationService.stub(INotificationService, { prompt: () => null! });
|
||||
});
|
||||
|
||||
setup(async () => {
|
||||
@@ -133,7 +131,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
testObject = await aWorkbenchService();
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(expected));
|
||||
|
||||
return testObject.queryGallery().then(pagedResponse => {
|
||||
return testObject.queryGallery(CancellationToken.None).then(pagedResponse => {
|
||||
assert.equal(1, pagedResponse.firstPage.length);
|
||||
const actual = pagedResponse.firstPage[0];
|
||||
|
||||
@@ -332,7 +330,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
testObject = await aWorkbenchService();
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
return testObject.queryGallery().then(page => {
|
||||
return testObject.queryGallery(CancellationToken.None).then(page => {
|
||||
const extension = page.firstPage[0];
|
||||
assert.equal(ExtensionState.Uninstalled, extension.state);
|
||||
|
||||
@@ -416,7 +414,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
const target = sinon.spy();
|
||||
|
||||
return testObject.queryGallery().then(page => {
|
||||
return testObject.queryGallery(CancellationToken.None).then(page => {
|
||||
const extension = page.firstPage[0];
|
||||
assert.equal(ExtensionState.Uninstalled, extension.state);
|
||||
|
||||
@@ -437,7 +435,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
const target = sinon.spy();
|
||||
|
||||
return testObject.queryGallery().then(page => {
|
||||
return testObject.queryGallery(CancellationToken.None).then(page => {
|
||||
const extension = page.firstPage[0];
|
||||
assert.equal(ExtensionState.Uninstalled, extension.state);
|
||||
|
||||
@@ -482,7 +480,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
testObject = await aWorkbenchService();
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a')));
|
||||
|
||||
return testObject.queryGallery().then(page => {
|
||||
return testObject.queryGallery(CancellationToken.None).then(page => {
|
||||
return testObject.loadDependencies(page.firstPage[0], CancellationToken.None).then(dependencies => {
|
||||
assert.equal(null, dependencies);
|
||||
});
|
||||
@@ -494,7 +492,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', {}, { dependencies: ['pub.b', 'pub.c', 'pub.d'] })));
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'loadAllDependencies', [aGalleryExtension('b'), aGalleryExtension('c'), aGalleryExtension('d')]);
|
||||
|
||||
return testObject.queryGallery().then(page => {
|
||||
return testObject.queryGallery(CancellationToken.None).then(page => {
|
||||
const extension = page.firstPage[0];
|
||||
return testObject.loadDependencies(extension, CancellationToken.None).then(actual => {
|
||||
assert.ok(actual!.hasDependencies);
|
||||
@@ -533,7 +531,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', {}, { dependencies: ['pub.b', 'pub.a'] })));
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'loadAllDependencies', [aGalleryExtension('b'), aGalleryExtension('a')]);
|
||||
|
||||
return testObject.queryGallery().then(page => {
|
||||
return testObject.queryGallery(CancellationToken.None).then(page => {
|
||||
const extension = page.firstPage[0];
|
||||
return testObject.loadDependencies(extension, CancellationToken.None).then(actual => {
|
||||
assert.ok(actual!.hasDependencies);
|
||||
@@ -565,7 +563,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', {}, { dependencies: ['pub.b', 'pub.a'] })));
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'loadAllDependencies', [aGalleryExtension('a')]);
|
||||
|
||||
return testObject.queryGallery().then(page => {
|
||||
return testObject.queryGallery(CancellationToken.None).then(page => {
|
||||
const extension = page.firstPage[0];
|
||||
return testObject.loadDependencies(extension, CancellationToken.None).then(actual => {
|
||||
assert.ok(actual!.hasDependencies);
|
||||
@@ -599,7 +597,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', {}, { dependencies: ['pub.inbuilt', 'pub.a'] })));
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'loadAllDependencies', [aGalleryExtension('a')]);
|
||||
|
||||
return testObject.queryGallery().then(page => {
|
||||
return testObject.queryGallery(CancellationToken.None).then(page => {
|
||||
const extension = page.firstPage[0];
|
||||
return testObject.loadDependencies(extension, CancellationToken.None).then(actual => {
|
||||
assert.ok(actual!.hasDependencies);
|
||||
@@ -637,7 +635,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
aGalleryExtension('d', {}, { dependencies: ['pub.f', 'pub.c'] }),
|
||||
aGalleryExtension('e')]);
|
||||
|
||||
return testObject.queryGallery().then(page => {
|
||||
return testObject.queryGallery(CancellationToken.None).then(page => {
|
||||
const extension = page.firstPage[0];
|
||||
return testObject.loadDependencies(extension, CancellationToken.None).then(a => {
|
||||
assert.ok(a!.hasDependencies);
|
||||
@@ -726,7 +724,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
.then(async () => {
|
||||
testObject = await aWorkbenchService();
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a')));
|
||||
return testObject.queryGallery().then(pagedResponse => {
|
||||
return testObject.queryGallery(CancellationToken.None).then(pagedResponse => {
|
||||
const actual = pagedResponse.firstPage[0];
|
||||
assert.equal(actual.enablementState, EnablementState.Enabled);
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ import { revertLocalChangesCommand, acceptLocalChangesCommand, CONFLICT_RESOLUTI
|
||||
import { SyncActionDescriptor, MenuId, MenuRegistry, ILocalizedString } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { openWindowCommand, REVEAL_IN_OS_COMMAND_ID, COPY_PATH_COMMAND_ID, REVEAL_IN_EXPLORER_COMMAND_ID, OPEN_TO_SIDE_COMMAND_ID, REVERT_FILE_COMMAND_ID, SAVE_FILE_COMMAND_ID, SAVE_FILE_LABEL, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL, SAVE_ALL_IN_GROUP_COMMAND_ID, OpenEditorsGroupContext, COMPARE_WITH_SAVED_COMMAND_ID, COMPARE_RESOURCE_COMMAND_ID, SELECT_FOR_COMPARE_COMMAND_ID, ResourceSelectedForCompareContext, REVEAL_IN_OS_LABEL, DirtyEditorContext, COMPARE_SELECTED_COMMAND_ID, REMOVE_ROOT_FOLDER_COMMAND_ID, REMOVE_ROOT_FOLDER_LABEL, SAVE_FILES_COMMAND_ID, COPY_RELATIVE_PATH_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_LABEL } from 'vs/workbench/contrib/files/browser/fileCommands';
|
||||
import { openWindowCommand, REVEAL_IN_OS_COMMAND_ID, COPY_PATH_COMMAND_ID, REVEAL_IN_EXPLORER_COMMAND_ID, OPEN_TO_SIDE_COMMAND_ID, REVERT_FILE_COMMAND_ID, SAVE_FILE_COMMAND_ID, SAVE_FILE_LABEL, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL, SAVE_ALL_IN_GROUP_COMMAND_ID, OpenEditorsGroupContext, COMPARE_WITH_SAVED_COMMAND_ID, COMPARE_RESOURCE_COMMAND_ID, SELECT_FOR_COMPARE_COMMAND_ID, ResourceSelectedForCompareContext, REVEAL_IN_OS_LABEL, DirtyEditorContext, COMPARE_SELECTED_COMMAND_ID, REMOVE_ROOT_FOLDER_COMMAND_ID, REMOVE_ROOT_FOLDER_LABEL, SAVE_FILES_COMMAND_ID, COPY_RELATIVE_PATH_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_LABEL, newWindowCommand } from 'vs/workbench/contrib/files/browser/fileCommands';
|
||||
import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
@@ -43,6 +43,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleAutoSaveAction,
|
||||
|
||||
// Commands
|
||||
CommandsRegistry.registerCommand('_files.windowOpen', openWindowCommand);
|
||||
CommandsRegistry.registerCommand('_files.newWindow', newWindowCommand);
|
||||
|
||||
const explorerCommandsWeightBonus = 10; // give our commands a little bit more weight over other default list/tree commands
|
||||
|
||||
|
||||
@@ -653,7 +653,7 @@ export class GlobalCompareResourcesAction extends Action {
|
||||
override: this.editorService.openEditor({
|
||||
leftResource: activeResource,
|
||||
rightResource: resource
|
||||
}).then(() => undefined)
|
||||
}).then(() => null)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -844,7 +844,7 @@ export class ShowActiveFileInExplorer extends Action {
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
const resource = toResource(this.editorService.activeEditor || null, { supportSideBySide: true });
|
||||
const resource = toResource(this.editorService.activeEditor, { supportSideBySide: true });
|
||||
if (resource) {
|
||||
this.commandService.executeCommand(REVEAL_IN_EXPLORER_COMMAND_ID, resource);
|
||||
} else {
|
||||
@@ -916,7 +916,7 @@ export class ShowOpenedFileInNewWindow extends Action {
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
const fileResource = toResource(this.editorService.activeEditor || null, { supportSideBySide: true });
|
||||
const fileResource = toResource(this.editorService.activeEditor, { supportSideBySide: true });
|
||||
if (fileResource) {
|
||||
if (this.fileService.canHandleResource(fileResource)) {
|
||||
this.windowService.openWindow([{ uri: fileResource, typeHint: 'file' }], { forceNewWindow: true, forceOpenWorkspaceAsFile: true });
|
||||
@@ -1019,7 +1019,7 @@ export class CompareWithClipboardAction extends Action {
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
const resource = toResource(this.editorService.activeEditor || null, { supportSideBySide: true });
|
||||
const resource = toResource(this.editorService.activeEditor, { supportSideBySide: true });
|
||||
if (resource && (this.fileService.canHandleResource(resource) || resource.scheme === Schemas.untitled)) {
|
||||
if (!this.registrationDisposal) {
|
||||
const provider = this.instantiationService.createInstance(ClipboardContentProvider);
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
// {{SQL CARBON EDIT}} - Import EditorInput
|
||||
import { toResource, IEditorCommandsContext, EditorInput } from 'vs/workbench/common/editor';
|
||||
import { IWindowsService, IWindowService, IURIToOpen, IOpenSettings } from 'vs/platform/windows/common/windows';
|
||||
import { IWindowsService, IWindowService, IURIToOpen, IOpenSettings, INewWindowOptions } from 'vs/platform/windows/common/windows';
|
||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
@@ -88,6 +88,11 @@ export const openWindowCommand = (accessor: ServicesAccessor, urisToOpen: IURITo
|
||||
}
|
||||
};
|
||||
|
||||
export const newWindowCommand = (accessor: ServicesAccessor, options?: INewWindowOptions) => {
|
||||
const windowsService = accessor.get(IWindowsService);
|
||||
windowsService.openNewWindow(options);
|
||||
};
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
function save(
|
||||
resource: URI | null,
|
||||
@@ -131,7 +136,7 @@ function save(
|
||||
let viewStateOfSource: IEditorViewState | null;
|
||||
const activeTextEditorWidget = getCodeEditor(editorService.activeTextEditorWidget);
|
||||
if (activeTextEditorWidget) {
|
||||
const activeResource = toResource(editorService.activeEditor || null, { supportSideBySide: true });
|
||||
const activeResource = toResource(editorService.activeEditor, { supportSideBySide: true });
|
||||
if (activeResource && (fileService.canHandleResource(activeResource) || resource.scheme === Schemas.untitled) && activeResource.toString() === resource.toString()) {
|
||||
viewStateOfSource = activeTextEditorWidget.saveViewState();
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo
|
||||
return;
|
||||
}
|
||||
|
||||
this.galleryService.query({ text: `tag:lp-${locale}` }).then(tagResult => {
|
||||
this.galleryService.query({ text: `tag:lp-${locale}` }, CancellationToken.None).then(tagResult => {
|
||||
if (tagResult.total === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { getTotalHeight, getTotalWidth } from 'vs/base/browser/dom';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IBroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService';
|
||||
import { IBroadcastService } from 'vs/workbench/services/broadcast/common/broadcast';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ColorIdentifier, editorBackground, foreground } from 'vs/platform/theme/common/colorRegistry';
|
||||
|
||||
@@ -763,7 +763,11 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
if (!this._xterm) {
|
||||
return;
|
||||
}
|
||||
const text = window.getSelection().toString();
|
||||
const selection = window.getSelection();
|
||||
if (!selection) {
|
||||
return;
|
||||
}
|
||||
const text = selection.toString();
|
||||
if (!text || force) {
|
||||
this._xterm.focus();
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ class WebviewProtocolProvider extends Disposable {
|
||||
|
||||
const appRootUri = URI.file(this._environmentService.appRoot);
|
||||
|
||||
registerFileProtocol(contents, WebviewProtocol.CoreResource, this._fileService, null, () => [
|
||||
registerFileProtocol(contents, WebviewProtocol.CoreResource, this._fileService, undefined, () => [
|
||||
appRootUri
|
||||
]);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export function registerFileProtocol(
|
||||
contents: Electron.WebContents,
|
||||
protocol: WebviewProtocol,
|
||||
fileService: IFileService,
|
||||
extensionLocation: URI | null | undefined,
|
||||
extensionLocation: URI | undefined,
|
||||
getRoots: () => ReadonlyArray<URI>
|
||||
) {
|
||||
contents.session.protocol.registerBufferProtocol(protocol, (request, callback: any) => {
|
||||
|
||||
@@ -17,6 +17,7 @@ import { IExperimentService, ExperimentState } from 'vs/workbench/contrib/experi
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { language, locale } from 'vs/base/common/platform';
|
||||
import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
export class TelemetryOptOut implements IWorkbenchContribution {
|
||||
|
||||
@@ -85,7 +86,7 @@ export class TelemetryOptOut implements IWorkbenchContribution {
|
||||
|
||||
let queryPromise = Promise.resolve(undefined);
|
||||
if (locale && locale !== language && locale !== 'en' && locale.indexOf('en-') === -1) {
|
||||
queryPromise = this.galleryService.query({ text: `tag:lp-${locale}` }).then(tagResult => {
|
||||
queryPromise = this.galleryService.query({ text: `tag:lp-${locale}` }, CancellationToken.None).then(tagResult => {
|
||||
if (!tagResult || !tagResult.total) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -9,24 +9,14 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
|
||||
suite('Workbench - GettingStarted', () => {
|
||||
let instantiation: TestInstantiationService | null = null;
|
||||
let welcomePageEnvConfig: string | null = null;
|
||||
let hideWelcomeSettingsValue: string | null = null;
|
||||
// let machineId: string | null = null;
|
||||
let appName: string | null = null;
|
||||
|
||||
suiteSetup(() => {
|
||||
instantiation = new TestInstantiationService();
|
||||
instantiation.stub(IWorkspaceContextService, {
|
||||
getConfiguration: () => {
|
||||
return {
|
||||
env: {
|
||||
welcomePage: welcomePageEnvConfig,
|
||||
appName: appName
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
instantiation.stub(IStorageService, {
|
||||
instantiation.stub(IStorageService, <Partial<IStorageService>>{
|
||||
get: () => hideWelcomeSettingsValue,
|
||||
store: (value) => hideWelcomeSettingsValue = value
|
||||
});
|
||||
@@ -37,8 +27,6 @@ suite('Workbench - GettingStarted', () => {
|
||||
});
|
||||
|
||||
setup(() => {
|
||||
welcomePageEnvConfig = null;
|
||||
hideWelcomeSettingsValue = null;
|
||||
appName = null;
|
||||
});
|
||||
});
|
||||
@@ -40,6 +40,7 @@ import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { IRecentlyOpened, isRecentWorkspace, IRecentWorkspace, IRecentFolder, isRecentFolder } from 'vs/platform/history/common/history';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
used();
|
||||
|
||||
@@ -457,7 +458,7 @@ class WelcomePage {
|
||||
this.notificationService.info(strings.alreadyInstalled.replace('{0}', extensionSuggestion.name));
|
||||
return;
|
||||
}
|
||||
const foundAndInstalled = installedExtension ? Promise.resolve(installedExtension.local) : this.extensionGalleryService.query({ names: [extensionSuggestion.id], source: telemetryFrom })
|
||||
const foundAndInstalled = installedExtension ? Promise.resolve(installedExtension.local) : this.extensionGalleryService.query({ names: [extensionSuggestion.id], source: telemetryFrom }, CancellationToken.None)
|
||||
.then((result): null | Promise<ILocalExtension | null> => {
|
||||
const [extension] = result.firstPage;
|
||||
if (!extension) {
|
||||
@@ -552,7 +553,7 @@ class WelcomePage {
|
||||
from: telemetryFrom,
|
||||
extensionId: extensionSuggestion.id,
|
||||
});
|
||||
this.extensionsWorkbenchService.queryGallery({ names: [extensionSuggestion.id] })
|
||||
this.extensionsWorkbenchService.queryGallery({ names: [extensionSuggestion.id] }, CancellationToken.None)
|
||||
.then(result => this.extensionsWorkbenchService.open(result.firstPage[0]))
|
||||
.then(undefined, onUnexpectedError);
|
||||
}
|
||||
|
||||
30
src/vs/workbench/services/broadcast/common/broadcast.ts
Normal file
30
src/vs/workbench/services/broadcast/common/broadcast.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
export const IBroadcastService = createDecorator<IBroadcastService>('broadcastService');
|
||||
|
||||
export interface IBroadcast {
|
||||
channel: string;
|
||||
payload: any;
|
||||
}
|
||||
|
||||
export interface IBroadcastService {
|
||||
_serviceBrand: any;
|
||||
|
||||
onBroadcast: Event<IBroadcast>;
|
||||
|
||||
broadcast(b: IBroadcast): void;
|
||||
}
|
||||
|
||||
export class NullBroadcastService implements IBroadcastService {
|
||||
_serviceBrand: any;
|
||||
onBroadcast: Event<IBroadcast> = Event.None;
|
||||
broadcast(_b: IBroadcast): void {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,28 +3,13 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ipcRenderer as ipc } from 'electron';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
|
||||
export const IBroadcastService = createDecorator<IBroadcastService>('broadcastService');
|
||||
|
||||
export interface IBroadcast {
|
||||
channel: string;
|
||||
payload: any;
|
||||
}
|
||||
|
||||
export interface IBroadcastService {
|
||||
_serviceBrand: any;
|
||||
|
||||
onBroadcast: Event<IBroadcast>;
|
||||
|
||||
broadcast(b: IBroadcast): void;
|
||||
}
|
||||
import { IBroadcastService, IBroadcast } from 'vs/workbench/services/broadcast/common/broadcast';
|
||||
|
||||
export class BroadcastService extends Disposable implements IBroadcastService {
|
||||
_serviceBrand: any;
|
||||
@@ -63,4 +48,4 @@ export class BroadcastService extends Disposable implements IBroadcastService {
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IBroadcastService, BroadcastService, true);
|
||||
registerSingleton(IBroadcastService, BroadcastService, true);
|
||||
|
||||
@@ -487,7 +487,7 @@ export class ConfigurationEditingService {
|
||||
return { key, jsonPath, value: config.value, resource: resource || undefined, target };
|
||||
}
|
||||
|
||||
private isWorkspaceConfigurationResource(resource: URI | null | undefined): boolean {
|
||||
private isWorkspaceConfigurationResource(resource: URI | null): boolean {
|
||||
const workspace = this.contextService.getWorkspace();
|
||||
return !!(workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath);
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ export class ConfigurationResolverService extends AbstractVariableResolverServic
|
||||
|
||||
const [type, name] = variable.split(':', 2);
|
||||
|
||||
let result: string | undefined | null;
|
||||
let result: string | undefined;
|
||||
|
||||
switch (type) {
|
||||
|
||||
|
||||
@@ -291,7 +291,7 @@ class DecorationProviderWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
private _fetchData(uri: URI): IDecorationData | undefined | null {
|
||||
private _fetchData(uri: URI): IDecorationData | null {
|
||||
|
||||
// check for pending request and cancel it
|
||||
const pendingRequest = this.data.get(uri.toString());
|
||||
@@ -319,11 +319,11 @@ class DecorationProviderWrapper {
|
||||
}));
|
||||
|
||||
this.data.set(uri.toString(), request);
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private _keepItem(uri: URI, data: IDecorationData | null | undefined): IDecorationData | null {
|
||||
private _keepItem(uri: URI, data: IDecorationData | undefined): IDecorationData | null {
|
||||
const deco = data ? data : null;
|
||||
const old = this.data.set(uri.toString(), deco);
|
||||
if (deco || old) {
|
||||
|
||||
@@ -36,7 +36,7 @@ export interface IOpenEditorOverride {
|
||||
* If defined, will prevent the opening of an editor and replace the resulting
|
||||
* promise with the provided promise for the openEditor() call.
|
||||
*/
|
||||
override?: Promise<IEditor | null | undefined>;
|
||||
override?: Promise<IEditor | null>;
|
||||
}
|
||||
|
||||
export interface IVisibleEditor extends IEditor {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
export interface IExtensionDevOptions {
|
||||
readonly isExtensionDevHost: boolean;
|
||||
readonly isExtensionDevDebug: boolean;
|
||||
readonly isExtensionDevDebugBrk: boolean;
|
||||
readonly isExtensionDevTestFromCli: boolean;
|
||||
}
|
||||
|
||||
export function parseExtensionDevOptions(environmentService: IEnvironmentService): IExtensionDevOptions {
|
||||
// handle extension host lifecycle a bit special when we know we are developing an extension that runs inside
|
||||
let isExtensionDevHost = environmentService.isExtensionDevelopment;
|
||||
const extDevLoc = environmentService.extensionDevelopmentLocationURI;
|
||||
const debugOk = !extDevLoc || extDevLoc.scheme === Schemas.file;
|
||||
let isExtensionDevDebug = debugOk && typeof environmentService.debugExtensionHost.port === 'number';
|
||||
let isExtensionDevDebugBrk = debugOk && !!environmentService.debugExtensionHost.break;
|
||||
let isExtensionDevTestFromCli = isExtensionDevHost && !!environmentService.extensionTestsLocationURI && !environmentService.debugExtensionHost.break;
|
||||
return {
|
||||
isExtensionDevHost,
|
||||
isExtensionDevDebug,
|
||||
isExtensionDevDebugBrk,
|
||||
isExtensionDevTestFromCli,
|
||||
};
|
||||
}
|
||||
@@ -218,6 +218,13 @@ export interface IExtensionService extends ICpuProfilerTarget {
|
||||
* Stops the extension host.
|
||||
*/
|
||||
stopExtensionHost(): void;
|
||||
|
||||
_logOrShowMessage(severity: Severity, msg: string): void;
|
||||
_activateById(extensionId: ExtensionIdentifier, activationEvent: string): Promise<void>;
|
||||
_onWillActivateExtension(extensionId: ExtensionIdentifier): void;
|
||||
_onDidActivateExtension(extensionId: ExtensionIdentifier, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string): void;
|
||||
_onExtensionRuntimeError(extensionId: ExtensionIdentifier, err: Error): void;
|
||||
_onExtensionHostExit(code: number): void;
|
||||
}
|
||||
|
||||
export interface ICpuProfilerTarget {
|
||||
@@ -278,4 +285,10 @@ export class NullExtensionService implements IExtensionService {
|
||||
stopExtensionHost(): void { }
|
||||
canAddExtension(): boolean { return false; }
|
||||
canRemoveExtension(): boolean { return false; }
|
||||
}
|
||||
_logOrShowMessage(_severity: Severity, _msg: string): void { }
|
||||
_activateById(_extensionId: ExtensionIdentifier, _activationEvent: string): Promise<void> { return Promise.resolve(); }
|
||||
_onWillActivateExtension(_extensionId: ExtensionIdentifier): void { }
|
||||
_onDidActivateExtension(_extensionId: ExtensionIdentifier, _startup: boolean, _codeLoadingTime: number, _activateCallTime: number, _activateResolvedTime: number, _activationEvent: string): void { }
|
||||
_onExtensionRuntimeError(_extensionId: ExtensionIdentifier, _err: Error): void { }
|
||||
_onExtensionHostExit(code: number): void { }
|
||||
}
|
||||
|
||||
@@ -273,4 +273,4 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IExtensionUrlHandler, ExtensionUrlHandler);
|
||||
registerSingleton(IExtensionUrlHandler, ExtensionUrlHandler);
|
||||
@@ -12,16 +12,15 @@ import { timeout } from 'vs/base/common/async';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IRemoteConsoleLog, log, parse } from 'vs/base/node/console';
|
||||
import { IRemoteConsoleLog, log, parse } from 'vs/base/common/console';
|
||||
import { findFreePort, randomPort } from 'vs/base/node/ports';
|
||||
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc';
|
||||
import { PersistentProtocol, generateRandomPipeName } from 'vs/base/parts/ipc/node/ipc.net';
|
||||
import { IBroadcast, IBroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService';
|
||||
import { IBroadcast, IBroadcastService } from 'vs/workbench/services/broadcast/common/broadcast';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
@@ -36,6 +35,7 @@ import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { MessageType, createMessageOfType, isMessageOfType } from 'vs/workbench/services/extensions/node/extensionHostProtocol';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { parseExtensionDevOptions } from '../common/extensionDevOptions';
|
||||
|
||||
export interface IExtensionHostStarter {
|
||||
readonly onCrashed: Event<[number, string | null]>;
|
||||
@@ -44,28 +44,6 @@ export interface IExtensionHostStarter {
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export interface IExtensionDevOptions {
|
||||
readonly isExtensionDevHost: boolean;
|
||||
readonly isExtensionDevDebug: boolean;
|
||||
readonly isExtensionDevDebugBrk: boolean;
|
||||
readonly isExtensionDevTestFromCli: boolean;
|
||||
}
|
||||
export function parseExtensionDevOptions(environmentService: IEnvironmentService): IExtensionDevOptions {
|
||||
// handle extension host lifecycle a bit special when we know we are developing an extension that runs inside
|
||||
let isExtensionDevHost = environmentService.isExtensionDevelopment;
|
||||
const extDevLoc = environmentService.extensionDevelopmentLocationURI;
|
||||
const debugOk = !extDevLoc || extDevLoc.scheme === Schemas.file;
|
||||
let isExtensionDevDebug = debugOk && typeof environmentService.debugExtensionHost.port === 'number';
|
||||
let isExtensionDevDebugBrk = debugOk && !!environmentService.debugExtensionHost.break;
|
||||
let isExtensionDevTestFromCli = isExtensionDevHost && !!environmentService.extensionTestsLocationURI && !environmentService.debugExtensionHost.break;
|
||||
return {
|
||||
isExtensionDevHost,
|
||||
isExtensionDevDebug,
|
||||
isExtensionDevDebugBrk,
|
||||
isExtensionDevTestFromCli,
|
||||
};
|
||||
}
|
||||
|
||||
export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
|
||||
private readonly _onCrashed: Emitter<[number, string]> = new Emitter<[number, string]>();
|
||||
@@ -87,7 +65,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
private _inspectPort: number;
|
||||
private _extensionHostProcess: ChildProcess | null;
|
||||
private _extensionHostConnection: Socket | null;
|
||||
private _messageProtocol: Promise<IMessagePassingProtocol> | null;
|
||||
private _messageProtocol: Promise<PersistentProtocol> | null;
|
||||
|
||||
constructor(
|
||||
private readonly _autoStart: boolean,
|
||||
@@ -341,9 +319,9 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
});
|
||||
}
|
||||
|
||||
private _tryExtHostHandshake(): Promise<IMessagePassingProtocol> {
|
||||
private _tryExtHostHandshake(): Promise<PersistentProtocol> {
|
||||
|
||||
return new Promise<IMessagePassingProtocol>((resolve, reject) => {
|
||||
return new Promise<PersistentProtocol>((resolve, reject) => {
|
||||
|
||||
// Wait for the extension host to connect to our named pipe
|
||||
// and wrap the socket in the message passing protocol
|
||||
@@ -373,7 +351,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
|
||||
// 1) wait for the incoming `ready` event and send the initialization data.
|
||||
// 2) wait for the incoming `initialized` event.
|
||||
return new Promise<IMessagePassingProtocol>((resolve, reject) => {
|
||||
return new Promise<PersistentProtocol>((resolve, reject) => {
|
||||
|
||||
let timeoutHandle: NodeJS.Timer;
|
||||
const installTimeoutCheck = () => {
|
||||
@@ -549,6 +527,8 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
// (graceful termination)
|
||||
protocol.send(createMessageOfType(MessageType.Terminate));
|
||||
|
||||
protocol.dispose();
|
||||
|
||||
// Give the extension host 10s, after which we will
|
||||
// try to kill the process and release any resources
|
||||
setTimeout(() => this._cleanResources(), 10 * 1000);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import { ipcRenderer as ipc } from 'electron';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { Barrier, runWhenIdle } from 'vs/base/common/async';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
@@ -840,6 +841,10 @@ export class ExtensionService extends Disposable implements IExtensionService {
|
||||
this._extensionHostExtensionRuntimeErrors.get(extensionKey)!.push(err);
|
||||
this._onDidChangeExtensionsStatus.fire([extensionId]);
|
||||
}
|
||||
|
||||
public _onExtensionHostExit(code: number): void {
|
||||
ipc.send('vscode:exit', code);
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IExtensionService, ExtensionService);
|
||||
|
||||
@@ -450,7 +450,7 @@ export class ExtensionScannerInput {
|
||||
|
||||
constructor(
|
||||
public readonly ourVersion: string,
|
||||
public readonly commit: string | null | undefined,
|
||||
public readonly commit: string | undefined,
|
||||
public readonly locale: string | undefined,
|
||||
public readonly devMode: boolean,
|
||||
public readonly absoluteFolderPath: string,
|
||||
|
||||
@@ -217,19 +217,6 @@ export class FileService extends Disposable implements ILegacyFileService {
|
||||
return resource.scheme === Schemas.file;
|
||||
}
|
||||
|
||||
resolveFile(resource: uri, options?: IResolveFileOptions): Promise<IFileStat> {
|
||||
return this.resolve(resource, options);
|
||||
}
|
||||
|
||||
resolveFiles(toResolve: { resource: uri, options?: IResolveFileOptions }[]): Promise<IResolveFileResult[]> {
|
||||
return Promise.all(toResolve.map(resourceAndOptions => this.resolve(resourceAndOptions.resource, resourceAndOptions.options)
|
||||
.then(stat => ({ stat, success: true }), error => ({ stat: undefined, success: false }))));
|
||||
}
|
||||
|
||||
existsFile(resource: uri): Promise<boolean> {
|
||||
return this.resolveFile(resource).then(() => true, () => false);
|
||||
}
|
||||
|
||||
resolveContent(resource: uri, options?: IResolveContentOptions): Promise<IContent> {
|
||||
return this.resolveStreamContent(resource, options).then(streamContent => {
|
||||
return new Promise<IContent>((resolve, reject) => {
|
||||
@@ -1096,6 +1083,15 @@ export class FileService extends Disposable implements ILegacyFileService {
|
||||
|
||||
// Tests only
|
||||
|
||||
resolveFile(resource: uri, options?: IResolveFileOptions): Promise<IFileStat> {
|
||||
return this.resolve(resource, options);
|
||||
}
|
||||
|
||||
resolveFiles(toResolve: { resource: uri, options?: IResolveFileOptions }[]): Promise<IResolveFileResult[]> {
|
||||
return Promise.all(toResolve.map(resourceAndOptions => this.resolve(resourceAndOptions.resource, resourceAndOptions.options)
|
||||
.then(stat => ({ stat, success: true }), error => ({ stat: undefined, success: false }))));
|
||||
}
|
||||
|
||||
createFolder(resource: uri): Promise<IFileStat> {
|
||||
|
||||
// 1.) Create folder
|
||||
@@ -1112,6 +1108,10 @@ export class FileService extends Disposable implements ILegacyFileService {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
existsFile(resource: uri): Promise<boolean> {
|
||||
return this.resolveFile(resource).then(() => true, () => false);
|
||||
}
|
||||
}
|
||||
|
||||
function etag(stat: fs.Stats): string;
|
||||
|
||||
@@ -223,14 +223,6 @@ export class RemoteFileService extends FileService {
|
||||
});
|
||||
}
|
||||
|
||||
existsFile(resource: URI): Promise<boolean> {
|
||||
if (resource.scheme === Schemas.file) {
|
||||
return super.existsFile(resource);
|
||||
} else {
|
||||
return this.resolveFile(resource).then(_data => true, _err => false);
|
||||
}
|
||||
}
|
||||
|
||||
resolveFile(resource: URI, options?: IResolveFileOptions): Promise<IFileStat> {
|
||||
if (resource.scheme === Schemas.file) {
|
||||
return super.resolveFile(resource, options);
|
||||
|
||||
@@ -12,7 +12,7 @@ export class WatcherChannel implements IServerChannel {
|
||||
|
||||
constructor(private service: IWatcherService) { }
|
||||
|
||||
listen(_, event: string, arg?: any): Event<any> {
|
||||
listen(_: unknown, event: string, arg?: any): Event<any> {
|
||||
switch (event) {
|
||||
case 'watch': return this.service.watch(arg);
|
||||
}
|
||||
@@ -20,7 +20,7 @@ export class WatcherChannel implements IServerChannel {
|
||||
throw new Error(`Event not found: ${event}`);
|
||||
}
|
||||
|
||||
call(_, command: string, arg?: any): Promise<any> {
|
||||
call(_: unknown, command: string, arg?: any): Promise<any> {
|
||||
switch (command) {
|
||||
case 'setRoots': return this.service.setRoots(arg);
|
||||
case 'setVerboseLogging': return this.service.setVerboseLogging(arg);
|
||||
|
||||
@@ -12,7 +12,7 @@ export class WatcherChannel implements IServerChannel {
|
||||
|
||||
constructor(private service: IWatcherService) { }
|
||||
|
||||
listen(_, event: string, arg?: any): Event<any> {
|
||||
listen(_: unknown, event: string, arg?: any): Event<any> {
|
||||
switch (event) {
|
||||
case 'watch': return this.service.watch(arg);
|
||||
}
|
||||
@@ -20,7 +20,7 @@ export class WatcherChannel implements IServerChannel {
|
||||
throw new Error(`Event not found: ${event}`);
|
||||
}
|
||||
|
||||
call(_, command: string, arg?: any): Promise<any> {
|
||||
call(_: unknown, command: string, arg?: any): Promise<any> {
|
||||
switch (command) {
|
||||
case 'setRoots': return this.service.setRoots(arg);
|
||||
case 'setVerboseLogging': return this.service.setVerboseLogging(arg);
|
||||
|
||||
@@ -13,7 +13,6 @@ import { URI as uri } from 'vs/base/common/uri';
|
||||
import * as uuid from 'vs/base/common/uuid';
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
import * as encodingLib from 'vs/base/node/encoding';
|
||||
import * as utils from 'vs/workbench/services/files/test/electron-browser/utils';
|
||||
import { TestEnvironmentService, TestContextService, TestTextResourceConfigurationService, TestLifecycleService, TestStorageService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
@@ -407,92 +406,6 @@ suite('FileService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('deleteFile', () => {
|
||||
let event: FileOperationEvent;
|
||||
const toDispose = service.onAfterOperation(e => {
|
||||
event = e;
|
||||
});
|
||||
|
||||
const resource = uri.file(path.join(testDir, 'deep', 'conway.js'));
|
||||
return service.resolveFile(resource).then(source => {
|
||||
return service.del(source.resource).then(() => {
|
||||
assert.equal(fs.existsSync(source.resource.fsPath), false);
|
||||
|
||||
assert.ok(event);
|
||||
assert.equal(event.resource.fsPath, resource.fsPath);
|
||||
assert.equal(event.operation, FileOperation.DELETE);
|
||||
toDispose.dispose();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('deleteFolder (recursive)', function () {
|
||||
let event: FileOperationEvent;
|
||||
const toDispose = service.onAfterOperation(e => {
|
||||
event = e;
|
||||
});
|
||||
|
||||
const resource = uri.file(path.join(testDir, 'deep'));
|
||||
return service.resolveFile(resource).then(source => {
|
||||
return service.del(source.resource, { recursive: true }).then(() => {
|
||||
assert.equal(fs.existsSync(source.resource.fsPath), false);
|
||||
|
||||
assert.ok(event);
|
||||
assert.equal(event.resource.fsPath, resource.fsPath);
|
||||
assert.equal(event.operation, FileOperation.DELETE);
|
||||
toDispose.dispose();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('deleteFolder (non recursive)', function () {
|
||||
const resource = uri.file(path.join(testDir, 'deep'));
|
||||
return service.resolveFile(resource).then(source => {
|
||||
return service.del(source.resource).then(() => {
|
||||
return Promise.reject(new Error('Unexpected'));
|
||||
}, error => {
|
||||
return Promise.resolve(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('resolveFile', () => {
|
||||
return service.resolveFile(uri.file(testDir), { resolveTo: [uri.file(path.join(testDir, 'deep'))] }).then(r => {
|
||||
assert.equal(r.children!.length, 8);
|
||||
|
||||
const deep = utils.getByName(r, 'deep')!;
|
||||
assert.equal(deep.children!.length, 4);
|
||||
});
|
||||
});
|
||||
|
||||
test('resolveFiles', () => {
|
||||
return service.resolveFiles([
|
||||
{ resource: uri.file(testDir), options: { resolveTo: [uri.file(path.join(testDir, 'deep'))] } },
|
||||
{ resource: uri.file(path.join(testDir, 'deep')) }
|
||||
]).then(res => {
|
||||
const r1 = res[0].stat!;
|
||||
|
||||
assert.equal(r1.children!.length, 8);
|
||||
|
||||
const deep = utils.getByName(r1, 'deep')!;
|
||||
assert.equal(deep.children!.length, 4);
|
||||
|
||||
const r2 = res[1].stat!;
|
||||
assert.equal(r2.children!.length, 4);
|
||||
assert.equal(r2.name, 'deep');
|
||||
});
|
||||
});
|
||||
|
||||
test('existsFile', () => {
|
||||
return service.existsFile(uri.file(testDir)).then((exists) => {
|
||||
assert.equal(exists, true);
|
||||
|
||||
return service.existsFile(uri.file(testDir + 'something')).then((exists) => {
|
||||
assert.equal(exists, false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('updateContent', () => {
|
||||
const resource = uri.file(path.join(testDir, 'small.txt'));
|
||||
|
||||
|
||||
@@ -4,13 +4,17 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable, IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IFileService, IResolveFileOptions, IResourceEncodings, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, IResolveContentOptions, IContent, IStreamContent, ITextSnapshot, IUpdateContentOptions, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode } from 'vs/platform/files/common/files';
|
||||
import { IFileService, IResolveFileOptions, IResourceEncodings, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, IResolveContentOptions, IContent, IStreamContent, ITextSnapshot, IUpdateContentOptions, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat } from 'vs/platform/files/common/files';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { isAbsolutePath, dirname, basename, joinPath, isEqual } from 'vs/base/common/resources';
|
||||
import { localize } from 'vs/nls';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { getBaseLabel } from 'vs/base/common/labels';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
export class FileService2 extends Disposable implements IFileService {
|
||||
|
||||
@@ -29,6 +33,10 @@ export class FileService2 extends Disposable implements IFileService {
|
||||
|
||||
_serviceBrand: ServiceIdentifier<any>;
|
||||
|
||||
constructor(@ILogService private logService: ILogService) {
|
||||
super();
|
||||
}
|
||||
|
||||
//#region File System Provider
|
||||
|
||||
private _onDidChangeFileSystemProviderRegistrations: Emitter<IFileSystemProviderRegistrationEvent> = this._register(new Emitter<IFileSystemProviderRegistrationEvent>());
|
||||
@@ -69,7 +77,7 @@ export class FileService2 extends Disposable implements IFileService {
|
||||
]);
|
||||
}
|
||||
|
||||
activateProvider(scheme: string): Promise<void> {
|
||||
async activateProvider(scheme: string): Promise<void> {
|
||||
|
||||
// Emit an event that we are about to activate a provider with the given scheme.
|
||||
// Listeners can participate in the activation by registering a provider for it.
|
||||
@@ -89,7 +97,7 @@ export class FileService2 extends Disposable implements IFileService {
|
||||
|
||||
// If the provider is not yet there, make sure to join on the listeners assuming
|
||||
// that it takes a bit longer to register the file system provider.
|
||||
return Promise.all(joiners).then(() => undefined);
|
||||
await Promise.all(joiners);
|
||||
}
|
||||
|
||||
canHandleResource(resource: URI): boolean {
|
||||
@@ -129,16 +137,130 @@ export class FileService2 extends Disposable implements IFileService {
|
||||
|
||||
//#region File Metadata Resolving
|
||||
|
||||
resolveFile(resource: URI, options?: IResolveFileOptions): Promise<IFileStat> {
|
||||
return this._impl.resolveFile(resource, options);
|
||||
async resolveFile(resource: URI, options?: IResolveFileOptions): Promise<IFileStat> {
|
||||
try {
|
||||
return await this.doResolveFile(resource, options);
|
||||
} catch (error) {
|
||||
|
||||
// Specially handle file not found case as file operation result
|
||||
if (toFileSystemProviderErrorCode(error) === FileSystemProviderErrorCode.FileNotFound) {
|
||||
throw new FileOperationError(
|
||||
localize('fileNotFoundError', "File not found ({0})", resource.toString(true)),
|
||||
FileOperationResult.FILE_NOT_FOUND
|
||||
);
|
||||
}
|
||||
|
||||
// Bubble up any other error as is
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
resolveFiles(toResolve: { resource: URI; options?: IResolveFileOptions; }[]): Promise<IResolveFileResult[]> {
|
||||
return this._impl.resolveFiles(toResolve);
|
||||
private async doResolveFile(resource: URI, options?: IResolveFileOptions): Promise<IFileStat> {
|
||||
const provider = await this.withProvider(resource);
|
||||
|
||||
// leverage a trie to check for recursive resolving
|
||||
const to = options && options.resolveTo;
|
||||
const trie = TernarySearchTree.forPaths<true>();
|
||||
trie.set(resource.toString(), true);
|
||||
if (isNonEmptyArray(to)) {
|
||||
to.forEach(uri => trie.set(uri.toString(), true));
|
||||
}
|
||||
|
||||
const stat = await provider.stat(resource);
|
||||
|
||||
return await this.toFileStat(provider, resource, stat, undefined, (stat, siblings) => {
|
||||
|
||||
// check for recursive resolving
|
||||
if (Boolean(trie.findSuperstr(stat.resource.toString()) || trie.get(stat.resource.toString()))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check for resolving single child folders
|
||||
if (stat.isDirectory && options && options.resolveSingleChildDescendants) {
|
||||
return siblings === 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
existsFile(resource: URI): Promise<boolean> {
|
||||
return this._impl.existsFile(resource);
|
||||
private async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat, siblings: number | undefined, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise<IFileStat> {
|
||||
|
||||
// convert to file stat
|
||||
const fileStat: IFileStat = {
|
||||
resource,
|
||||
name: getBaseLabel(resource),
|
||||
isDirectory: (stat.type & FileType.Directory) !== 0,
|
||||
isSymbolicLink: (stat.type & FileType.SymbolicLink) !== 0,
|
||||
isReadonly: !!(provider.capabilities & FileSystemProviderCapabilities.Readonly),
|
||||
mtime: stat.mtime,
|
||||
size: stat.size,
|
||||
etag: stat.mtime.toString(29) + stat.size.toString(31),
|
||||
};
|
||||
|
||||
// check to recurse for directories
|
||||
if (fileStat.isDirectory && recurse(fileStat, siblings)) {
|
||||
try {
|
||||
const entries = await provider.readdir(resource);
|
||||
|
||||
fileStat.children = await Promise.all(entries.map(async entry => {
|
||||
const childResource = joinPath(resource, entry[0]);
|
||||
const childStat = await provider.stat(childResource);
|
||||
|
||||
return this.toFileStat(provider, childResource, childStat, entries.length, recurse);
|
||||
}));
|
||||
} catch (error) {
|
||||
this.logService.trace(error);
|
||||
|
||||
fileStat.children = []; // gracefully handle errors, we may not have permissions to read
|
||||
}
|
||||
|
||||
return fileStat;
|
||||
}
|
||||
|
||||
return Promise.resolve(fileStat);
|
||||
}
|
||||
|
||||
async resolveFiles(toResolve: { resource: URI; options?: IResolveFileOptions; }[]): Promise<IResolveFileResult[]> {
|
||||
|
||||
// soft-groupBy, keep order, don't rearrange/merge groups
|
||||
const groups: Array<typeof toResolve> = [];
|
||||
let group: typeof toResolve | undefined;
|
||||
for (const request of toResolve) {
|
||||
if (!group || group[0].resource.scheme !== request.resource.scheme) {
|
||||
group = [];
|
||||
groups.push(group);
|
||||
}
|
||||
|
||||
group.push(request);
|
||||
}
|
||||
|
||||
// resolve files
|
||||
const result: IResolveFileResult[] = [];
|
||||
for (const group of groups) {
|
||||
for (const groupEntry of group) {
|
||||
try {
|
||||
const stat = await this.doResolveFile(groupEntry.resource, groupEntry.options);
|
||||
result.push({ stat, success: true });
|
||||
} catch (error) {
|
||||
this.logService.trace(error);
|
||||
|
||||
result.push({ stat: undefined, success: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async existsFile(resource: URI): Promise<boolean> {
|
||||
try {
|
||||
await this.resolveFile(resource);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
@@ -200,11 +322,11 @@ export class FileService2 extends Disposable implements IFileService {
|
||||
}
|
||||
|
||||
break; // we have hit a directory that exists -> good
|
||||
} catch (e) {
|
||||
} catch (error) {
|
||||
|
||||
// Bubble up any other error that is not file not found
|
||||
if (toFileSystemProviderErrorCode(e) !== FileSystemProviderErrorCode.FileNotFound) {
|
||||
throw e;
|
||||
if (toFileSystemProviderErrorCode(error) !== FileSystemProviderErrorCode.FileNotFound) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Upon error, remember directories that need to be created
|
||||
@@ -222,8 +344,18 @@ export class FileService2 extends Disposable implements IFileService {
|
||||
}
|
||||
}
|
||||
|
||||
del(resource: URI, options?: { useTrash?: boolean; recursive?: boolean; }): Promise<void> {
|
||||
return this._impl.del(resource, options);
|
||||
async del(resource: URI, options?: { useTrash?: boolean; recursive?: boolean; }): Promise<void> {
|
||||
if (options && options.useTrash) {
|
||||
return this._impl.del(resource, options); //TODO@ben this is https://github.com/Microsoft/vscode/issues/48259
|
||||
}
|
||||
|
||||
const provider = this.throwIfFileSystemIsReadonly(await this.withProvider(resource));
|
||||
|
||||
// Delete through provider
|
||||
await provider.delete(resource, { recursive: !!(options && options.recursive) });
|
||||
|
||||
// Events
|
||||
this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.DELETE));
|
||||
}
|
||||
|
||||
//#endregion
|
||||
@@ -256,4 +388,4 @@ export class FileService2 extends Disposable implements IFileService {
|
||||
//#endregion
|
||||
}
|
||||
|
||||
registerSingleton(IFileService, FileService2);
|
||||
registerSingleton(IFileService, FileService2);
|
||||
|
||||
@@ -4,14 +4,16 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { mkdir } from 'fs';
|
||||
import { tmpdir } from 'os';
|
||||
import { promisify } from 'util';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IFileSystemProvider, FileSystemProviderCapabilities, IFileChange, IWatchOptions, IStat, FileType, FileDeleteOptions, FileOverwriteOptions, FileWriteOptions, FileOpenOptions, FileSystemProviderErrorCode, createFileSystemProviderError, FileSystemProviderError } from 'vs/platform/files/common/files';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
import { statLink } from 'vs/base/node/pfs';
|
||||
import { statLink, readdir, unlink, del } from 'vs/base/node/pfs';
|
||||
import { normalize } from 'vs/base/common/path';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
|
||||
export class DiskFileSystemProvider extends Disposable implements IFileSystemProvider {
|
||||
|
||||
@@ -54,8 +56,22 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro
|
||||
}
|
||||
}
|
||||
|
||||
readdir(resource: URI): Promise<[string, FileType][]> {
|
||||
throw new Error('Method not implemented.');
|
||||
async readdir(resource: URI): Promise<[string, FileType][]> {
|
||||
try {
|
||||
const children = await readdir(this.toFilePath(resource));
|
||||
|
||||
const result: [string, FileType][] = [];
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const child = children[i];
|
||||
|
||||
const stat = await this.stat(joinPath(resource, child));
|
||||
result.push([child, stat.type]);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
throw this.toFileSystemProviderError(error);
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
@@ -90,12 +106,30 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro
|
||||
|
||||
//#region Move/Copy/Delete/Create Folder
|
||||
|
||||
mkdir(resource: URI): Promise<void> {
|
||||
return promisify(mkdir)(resource.fsPath);
|
||||
async mkdir(resource: URI): Promise<void> {
|
||||
try {
|
||||
await promisify(mkdir)(this.toFilePath(resource));
|
||||
} catch (error) {
|
||||
throw this.toFileSystemProviderError(error);
|
||||
}
|
||||
}
|
||||
|
||||
delete(resource: URI, opts: FileDeleteOptions): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
async delete(resource: URI, opts: FileDeleteOptions): Promise<void> {
|
||||
try {
|
||||
const filePath = this.toFilePath(resource);
|
||||
|
||||
if (opts.recursive) {
|
||||
await del(filePath, tmpdir());
|
||||
} else {
|
||||
await unlink(filePath);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
return Promise.resolve(); // tolerate that the file might not exist
|
||||
}
|
||||
|
||||
throw this.toFileSystemProviderError(error);
|
||||
}
|
||||
}
|
||||
|
||||
rename(from: URI, to: URI, opts: FileOverwriteOptions): Promise<void> {
|
||||
@@ -147,4 +181,4 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,12 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { IFileSystemProviderRegistrationEvent } from 'vs/platform/files/common/files';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { NullFileSystemProvider } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
|
||||
suite('File Service 2', () => {
|
||||
|
||||
test('provider registration', async () => {
|
||||
const service = new FileService2();
|
||||
const service = new FileService2(new NullLogService());
|
||||
|
||||
assert.equal(service.canHandleResource(URI.parse('test://foo/bar')), false);
|
||||
|
||||
@@ -56,4 +57,4 @@ suite('File Service 2', () => {
|
||||
assert.equal(registrations[1].scheme, 'test');
|
||||
assert.equal(registrations[1].added, false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,17 +10,32 @@ import { Schemas } from 'vs/base/common/network';
|
||||
import { DiskFileSystemProvider } from 'vs/workbench/services/files2/node/diskFileSystemProvider';
|
||||
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { join, basename } from 'vs/base/common/path';
|
||||
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||
import { copy, del } from 'vs/base/node/pfs';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { existsSync } from 'fs';
|
||||
import { FileOperation, FileOperationEvent } from 'vs/platform/files/common/files';
|
||||
import { FileOperation, FileOperationEvent, IFileStat } from 'vs/platform/files/common/files';
|
||||
import { FileService } from 'vs/workbench/services/files/node/fileService';
|
||||
import { TestContextService, TestEnvironmentService, TestTextResourceConfigurationService, TestLifecycleService, TestStorageService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
|
||||
function getByName(root: IFileStat, name: string): IFileStat | null {
|
||||
if (root.children === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const child of root.children) {
|
||||
if (child.name === name) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
suite('Disk File Service', () => {
|
||||
|
||||
@@ -30,7 +45,7 @@ suite('Disk File Service', () => {
|
||||
let testDir: string;
|
||||
|
||||
setup(async () => {
|
||||
service = new FileService2();
|
||||
service = new FileService2(new NullLogService());
|
||||
service.registerProvider(Schemas.file, new DiskFileSystemProvider());
|
||||
|
||||
const id = generateUuid();
|
||||
@@ -49,50 +64,240 @@ suite('Disk File Service', () => {
|
||||
});
|
||||
|
||||
test('createFolder', async () => {
|
||||
let event: FileOperationEvent;
|
||||
let event: FileOperationEvent | undefined;
|
||||
const toDispose = service.onAfterOperation(e => {
|
||||
event = e;
|
||||
});
|
||||
|
||||
return service.resolveFile(URI.file(testDir)).then(parent => {
|
||||
const resource = URI.file(join(parent.resource.fsPath, 'newFolder'));
|
||||
const parent = await service.resolveFile(URI.file(testDir));
|
||||
|
||||
return service.createFolder(resource).then(f => {
|
||||
assert.equal(f.name, 'newFolder');
|
||||
assert.equal(existsSync(f.resource.fsPath), true);
|
||||
const resource = URI.file(join(parent.resource.fsPath, 'newFolder'));
|
||||
|
||||
assert.ok(event);
|
||||
assert.equal(event.resource.fsPath, resource.fsPath);
|
||||
assert.equal(event.operation, FileOperation.CREATE);
|
||||
assert.equal(event.target!.resource.fsPath, resource.fsPath);
|
||||
assert.equal(event.target!.isDirectory, true);
|
||||
toDispose.dispose();
|
||||
});
|
||||
});
|
||||
const folder = await service.createFolder(resource);
|
||||
|
||||
assert.equal(folder.name, 'newFolder');
|
||||
assert.equal(existsSync(folder.resource.fsPath), true);
|
||||
|
||||
assert.ok(event);
|
||||
assert.equal(event!.resource.fsPath, resource.fsPath);
|
||||
assert.equal(event!.operation, FileOperation.CREATE);
|
||||
assert.equal(event!.target!.resource.fsPath, resource.fsPath);
|
||||
assert.equal(event!.target!.isDirectory, true);
|
||||
|
||||
toDispose.dispose();
|
||||
});
|
||||
|
||||
test('createFolder: creating multiple folders at once', function () {
|
||||
test('createFolder: creating multiple folders at once', async function () {
|
||||
let event: FileOperationEvent;
|
||||
const toDispose = service.onAfterOperation(e => {
|
||||
event = e;
|
||||
});
|
||||
|
||||
const multiFolderPaths = ['a', 'couple', 'of', 'folders'];
|
||||
return service.resolveFile(URI.file(testDir)).then(parent => {
|
||||
const resource = URI.file(join(parent.resource.fsPath, ...multiFolderPaths));
|
||||
const parent = await service.resolveFile(URI.file(testDir));
|
||||
|
||||
return service.createFolder(resource).then(f => {
|
||||
const lastFolderName = multiFolderPaths[multiFolderPaths.length - 1];
|
||||
assert.equal(f.name, lastFolderName);
|
||||
assert.equal(existsSync(f.resource.fsPath), true);
|
||||
const resource = URI.file(join(parent.resource.fsPath, ...multiFolderPaths));
|
||||
|
||||
assert.ok(event);
|
||||
assert.equal(event.resource.fsPath, resource.fsPath);
|
||||
assert.equal(event.operation, FileOperation.CREATE);
|
||||
assert.equal(event.target!.resource.fsPath, resource.fsPath);
|
||||
assert.equal(event.target!.isDirectory, true);
|
||||
toDispose.dispose();
|
||||
const folder = await service.createFolder(resource);
|
||||
|
||||
const lastFolderName = multiFolderPaths[multiFolderPaths.length - 1];
|
||||
assert.equal(folder.name, lastFolderName);
|
||||
assert.equal(existsSync(folder.resource.fsPath), true);
|
||||
|
||||
assert.ok(event!);
|
||||
assert.equal(event!.resource.fsPath, resource.fsPath);
|
||||
assert.equal(event!.operation, FileOperation.CREATE);
|
||||
assert.equal(event!.target!.resource.fsPath, resource.fsPath);
|
||||
assert.equal(event!.target!.isDirectory, true);
|
||||
|
||||
toDispose.dispose();
|
||||
});
|
||||
|
||||
test('existsFile', async () => {
|
||||
let exists = await service.existsFile(URI.file(testDir));
|
||||
assert.equal(exists, true);
|
||||
|
||||
exists = await service.existsFile(URI.file(testDir + 'something'));
|
||||
assert.equal(exists, false);
|
||||
});
|
||||
|
||||
test('resolveFile', async () => {
|
||||
const resolved = await service.resolveFile(URI.file(testDir), { resolveTo: [URI.file(join(testDir, 'deep'))] });
|
||||
assert.equal(resolved.children!.length, 8);
|
||||
|
||||
const deep = (getByName(resolved, 'deep')!);
|
||||
assert.equal(deep.children!.length, 4);
|
||||
});
|
||||
|
||||
test('resolveFile - directory', async () => {
|
||||
const testsElements = ['examples', 'other', 'index.html', 'site.css'];
|
||||
|
||||
const result = await service.resolveFile(URI.file(getPathFromAmdModule(require, './fixtures/resolver')));
|
||||
|
||||
assert.ok(result);
|
||||
assert.ok(result.children);
|
||||
assert.ok(result.children!.length > 0);
|
||||
assert.ok(result!.isDirectory);
|
||||
assert.equal(result.children!.length, testsElements.length);
|
||||
|
||||
assert.ok(result.children!.every((entry) => {
|
||||
return testsElements.some((name) => {
|
||||
return basename(entry.resource.fsPath) === name;
|
||||
});
|
||||
}));
|
||||
|
||||
result.children!.forEach((value) => {
|
||||
assert.ok(basename(value.resource.fsPath));
|
||||
if (['examples', 'other'].indexOf(basename(value.resource.fsPath)) >= 0) {
|
||||
assert.ok(value.isDirectory);
|
||||
} else if (basename(value.resource.fsPath) === 'index.html') {
|
||||
assert.ok(!value.isDirectory);
|
||||
assert.ok(!value.children);
|
||||
} else if (basename(value.resource.fsPath) === 'site.css') {
|
||||
assert.ok(!value.isDirectory);
|
||||
assert.ok(!value.children);
|
||||
} else {
|
||||
assert.ok(!'Unexpected value ' + basename(value.resource.fsPath));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('resolveFile - directory - resolveTo single directory', async () => {
|
||||
const resolverFixturesPath = getPathFromAmdModule(require, './fixtures/resolver');
|
||||
const result = await service.resolveFile(URI.file(resolverFixturesPath), { resolveTo: [URI.file(join(resolverFixturesPath, 'other/deep'))] });
|
||||
|
||||
assert.ok(result);
|
||||
assert.ok(result.children);
|
||||
assert.ok(result.children!.length > 0);
|
||||
assert.ok(result.isDirectory);
|
||||
|
||||
const children = result.children!;
|
||||
assert.equal(children.length, 4);
|
||||
|
||||
const other = getByName(result, 'other');
|
||||
assert.ok(other);
|
||||
assert.ok(other!.children!.length > 0);
|
||||
|
||||
const deep = getByName(other!, 'deep');
|
||||
assert.ok(deep);
|
||||
assert.ok(deep!.children!.length > 0);
|
||||
assert.equal(deep!.children!.length, 4);
|
||||
});
|
||||
|
||||
test('resolve directory - resolveTo multiple directories', async () => {
|
||||
const resolverFixturesPath = getPathFromAmdModule(require, './fixtures/resolver');
|
||||
const result = await service.resolveFile(URI.file(resolverFixturesPath), {
|
||||
resolveTo: [
|
||||
URI.file(join(resolverFixturesPath, 'other/deep')),
|
||||
URI.file(join(resolverFixturesPath, 'examples'))
|
||||
]
|
||||
});
|
||||
|
||||
assert.ok(result);
|
||||
assert.ok(result.children);
|
||||
assert.ok(result.children!.length > 0);
|
||||
assert.ok(result.isDirectory);
|
||||
|
||||
const children = result.children!;
|
||||
assert.equal(children.length, 4);
|
||||
|
||||
const other = getByName(result, 'other');
|
||||
assert.ok(other);
|
||||
assert.ok(other!.children!.length > 0);
|
||||
|
||||
const deep = getByName(other!, 'deep');
|
||||
assert.ok(deep);
|
||||
assert.ok(deep!.children!.length > 0);
|
||||
assert.equal(deep!.children!.length, 4);
|
||||
|
||||
const examples = getByName(result, 'examples');
|
||||
assert.ok(examples);
|
||||
assert.ok(examples!.children!.length > 0);
|
||||
assert.equal(examples!.children!.length, 4);
|
||||
});
|
||||
|
||||
test('resolve directory - resolveSingleChildFolders', async () => {
|
||||
const resolverFixturesPath = getPathFromAmdModule(require, './fixtures/resolver/other');
|
||||
const result = await service.resolveFile(URI.file(resolverFixturesPath), { resolveSingleChildDescendants: true });
|
||||
|
||||
assert.ok(result);
|
||||
assert.ok(result.children);
|
||||
assert.ok(result.children!.length > 0);
|
||||
assert.ok(result.isDirectory);
|
||||
|
||||
const children = result.children!;
|
||||
assert.equal(children.length, 1);
|
||||
|
||||
let deep = getByName(result, 'deep');
|
||||
assert.ok(deep);
|
||||
assert.ok(deep!.children!.length > 0);
|
||||
assert.equal(deep!.children!.length, 4);
|
||||
});
|
||||
|
||||
test('resolveFiles', async () => {
|
||||
const res = await service.resolveFiles([
|
||||
{ resource: URI.file(testDir), options: { resolveTo: [URI.file(join(testDir, 'deep'))] } },
|
||||
{ resource: URI.file(join(testDir, 'deep')) }
|
||||
]);
|
||||
|
||||
const r1 = (res[0].stat!);
|
||||
assert.equal(r1.children!.length, 8);
|
||||
|
||||
const deep = (getByName(r1, 'deep')!);
|
||||
assert.equal(deep.children!.length, 4);
|
||||
|
||||
const r2 = (res[1].stat!);
|
||||
assert.equal(r2.children!.length, 4);
|
||||
assert.equal(r2.name, 'deep');
|
||||
});
|
||||
|
||||
test('deleteFile', async () => {
|
||||
let event: FileOperationEvent;
|
||||
const toDispose = service.onAfterOperation(e => {
|
||||
event = e;
|
||||
});
|
||||
|
||||
const resource = URI.file(join(testDir, 'deep', 'conway.js'));
|
||||
const source = await service.resolveFile(resource);
|
||||
|
||||
await service.del(source.resource);
|
||||
|
||||
assert.equal(existsSync(source.resource.fsPath), false);
|
||||
assert.ok(event!);
|
||||
assert.equal(event!.resource.fsPath, resource.fsPath);
|
||||
assert.equal(event!.operation, FileOperation.DELETE);
|
||||
|
||||
toDispose.dispose();
|
||||
});
|
||||
|
||||
test('deleteFolder (recursive)', async () => {
|
||||
let event: FileOperationEvent;
|
||||
const toDispose = service.onAfterOperation(e => {
|
||||
event = e;
|
||||
});
|
||||
|
||||
const resource = URI.file(join(testDir, 'deep'));
|
||||
const source = await service.resolveFile(resource);
|
||||
|
||||
await service.del(source.resource, { recursive: true });
|
||||
|
||||
assert.equal(existsSync(source.resource.fsPath), false);
|
||||
assert.ok(event!);
|
||||
assert.equal(event!.resource.fsPath, resource.fsPath);
|
||||
assert.equal(event!.operation, FileOperation.DELETE);
|
||||
|
||||
toDispose.dispose();
|
||||
});
|
||||
|
||||
test('deleteFolder (non recursive)', async () => {
|
||||
const resource = URI.file(join(testDir, 'deep'));
|
||||
const source = await service.resolveFile(resource);
|
||||
try {
|
||||
await service.del(source.resource);
|
||||
return Promise.reject(new Error('Unexpected'));
|
||||
}
|
||||
catch (error) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
33
src/vs/workbench/services/heap/common/heap.ts
Normal file
33
src/vs/workbench/services/heap/common/heap.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export const IHeapService = createDecorator<IHeapService>('heapService');
|
||||
|
||||
export interface ObjectIdentifier {
|
||||
$ident?: number;
|
||||
}
|
||||
|
||||
export interface IHeapService {
|
||||
_serviceBrand: any;
|
||||
|
||||
readonly onGarbageCollection: Event<number[]>;
|
||||
|
||||
/**
|
||||
* Track gc-collection for the given object
|
||||
*/
|
||||
trackObject(obj: ObjectIdentifier | undefined): void;
|
||||
}
|
||||
|
||||
|
||||
|
||||
export class NullHeapService implements IHeapService {
|
||||
_serviceBrand: any;
|
||||
onGarbageCollection = Event.None;
|
||||
trackObject() { }
|
||||
}
|
||||
@@ -3,26 +3,10 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtHostContext, ObjectIdentifier, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { GCSignal } from 'gc-signals';
|
||||
|
||||
export const IHeapService = createDecorator<IHeapService>('heapService');
|
||||
|
||||
export interface IHeapService {
|
||||
_serviceBrand: any;
|
||||
|
||||
readonly onGarbageCollection: Event<number[]>;
|
||||
|
||||
/**
|
||||
* Track gc-collection for the given object
|
||||
*/
|
||||
trackObject(obj: ObjectIdentifier | undefined): void;
|
||||
}
|
||||
import { IHeapService, ObjectIdentifier } from 'vs/workbench/services/heap/common/heap';
|
||||
|
||||
export class HeapService implements IHeapService {
|
||||
|
||||
@@ -93,26 +77,4 @@ export class HeapService implements IHeapService {
|
||||
}
|
||||
}
|
||||
|
||||
@extHostCustomer
|
||||
export class MainThreadHeapService {
|
||||
|
||||
private readonly _toDispose: IDisposable;
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IHeapService heapService: IHeapService,
|
||||
) {
|
||||
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostHeapService);
|
||||
this._toDispose = heapService.onGarbageCollection((ids) => {
|
||||
// send to ext host
|
||||
proxy.$onGarbageCollection(ids);
|
||||
});
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._toDispose.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
registerSingleton(IHeapService, HeapService, true);
|
||||
@@ -577,7 +577,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService {
|
||||
let schemaId = 'vscode://schemas/keybindings';
|
||||
let commandsSchemas: IJSONSchema[] = [];
|
||||
let commandsEnum: string[] = [];
|
||||
let commandsEnumDescriptions: (string | null | undefined)[] = [];
|
||||
let commandsEnumDescriptions: (string | undefined)[] = [];
|
||||
let schema: IJSONSchema = {
|
||||
'id': schemaId,
|
||||
'type': 'array',
|
||||
@@ -636,7 +636,7 @@ function updateSchema() {
|
||||
commandsEnumDescriptions.length = 0;
|
||||
|
||||
const knownCommands = new Set<string>();
|
||||
const addKnownCommand = (commandId: string, description?: string | null) => {
|
||||
const addKnownCommand = (commandId: string, description?: string | undefined) => {
|
||||
if (!/^_/.test(commandId)) {
|
||||
if (!knownCommands.has(commandId)) {
|
||||
knownCommands.add(commandId);
|
||||
@@ -655,7 +655,7 @@ function updateSchema() {
|
||||
for (let commandId in allCommands) {
|
||||
const commandDescription = allCommands[commandId].description;
|
||||
|
||||
addKnownCommand(commandId, commandDescription && commandDescription.description);
|
||||
addKnownCommand(commandId, commandDescription ? commandDescription.description : undefined);
|
||||
|
||||
if (!commandDescription || !commandDescription.args || commandDescription.args.length !== 1 || !commandDescription.args[0].schema) {
|
||||
continue;
|
||||
@@ -684,7 +684,6 @@ function updateSchema() {
|
||||
for (let commandId in menuCommands) {
|
||||
addKnownCommand(commandId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigExtensions.Configuration);
|
||||
|
||||
@@ -11,7 +11,7 @@ export class SearchChannel implements IServerChannel {
|
||||
|
||||
constructor(private service: IRawSearchService) { }
|
||||
|
||||
listen<T>(_, event: string, arg?: any): Event<any> {
|
||||
listen(_: unknown, event: string, arg?: any): Event<any> {
|
||||
switch (event) {
|
||||
case 'fileSearch': return this.service.fileSearch(arg);
|
||||
case 'textSearch': return this.service.textSearch(arg);
|
||||
@@ -19,7 +19,7 @@ export class SearchChannel implements IServerChannel {
|
||||
throw new Error('Event not found');
|
||||
}
|
||||
|
||||
call(_, command: string, arg?: any): Promise<any> {
|
||||
call(_: unknown, command: string, arg?: any): Promise<any> {
|
||||
switch (command) {
|
||||
case 'clearCache': return this.service.clearCache(arg);
|
||||
}
|
||||
|
||||
@@ -17,19 +17,19 @@ import * as pfs from 'vs/base/node/pfs';
|
||||
import { getNextTickChannel } from 'vs/base/parts/ipc/node/ipc';
|
||||
import { Client, IIPCOptions } from 'vs/base/parts/ipc/node/ipc.cp';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IDebugParams, IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { deserializeSearchError, FileMatch, ICachedSearchStats, IFileMatch, IFileQuery, IFileSearchStats, IFolderQuery, IProgress, ISearchComplete, ISearchEngineStats, ISearchProgressItem, ISearchQuery, ISearchResultProvider, ISearchService, ITextQuery, pathIncludedInQuery, QueryType, SearchError, SearchErrorCode, SearchProviderType, ISearchConfiguration, IRawSearchService, ISerializedFileMatch, ISerializedSearchComplete, ISerializedSearchProgressItem, isSerializedSearchComplete, isSerializedSearchSuccess } from 'vs/workbench/services/search/common/search';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { deserializeSearchError, FileMatch, ICachedSearchStats, IFileMatch, IFileQuery, IFileSearchStats, IFolderQuery, IProgress, IRawSearchService, ISearchComplete, ISearchConfiguration, ISearchEngineStats, ISearchProgressItem, ISearchQuery, ISearchResultProvider, ISearchService, ISerializedFileMatch, ISerializedSearchComplete, ISerializedSearchProgressItem, isSerializedSearchComplete, isSerializedSearchSuccess, ITextQuery, pathIncludedInQuery, QueryType, SearchError, SearchErrorCode, SearchProviderType } from 'vs/workbench/services/search/common/search';
|
||||
import { addContextToEditorMatches, editorMatchesToTextSearchResults } from 'vs/workbench/services/search/common/searchHelpers';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { SearchChannelClient } from './searchIpc';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
|
||||
export class SearchService extends Disposable implements ISearchService {
|
||||
_serviceBrand: any;
|
||||
@@ -46,7 +46,8 @@ export class SearchService extends Disposable implements ISearchService {
|
||||
@IEnvironmentService environmentService: IEnvironmentService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IFileService private readonly fileService: IFileService
|
||||
) {
|
||||
super();
|
||||
this.diskSearch = this.instantiationService.createInstance(DiskSearch, !environmentService.isBuilt || environmentService.verbose, environmentService.debugSearch);
|
||||
@@ -376,7 +377,7 @@ export class SearchService extends Disposable implements ISearchService {
|
||||
}
|
||||
|
||||
// Block walkthrough, webview, etc.
|
||||
else if (resource.scheme !== Schemas.file && resource.scheme !== REMOTE_HOST_SCHEME) {
|
||||
else if (!this.fileService.canHandleResource(resource)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -610,8 +610,14 @@ export class TextFileService extends Disposable implements ITextFileService {
|
||||
|
||||
private untitledToAssociatedFileResource(untitled: URI): URI {
|
||||
const authority = this.windowService.getConfiguration().remoteAuthority;
|
||||
|
||||
return authority ? untitled.with({ scheme: REMOTE_HOST_SCHEME, authority }) : untitled.with({ scheme: Schemas.file });
|
||||
if (authority) {
|
||||
let path = untitled.path;
|
||||
if (path && path[0] !== '/') {
|
||||
path = '/' + path;
|
||||
}
|
||||
return untitled.with({ scheme: REMOTE_HOST_SCHEME, authority, path });
|
||||
}
|
||||
return untitled.with({ scheme: Schemas.file });
|
||||
}
|
||||
|
||||
private doSaveAllFiles(resources?: URI[], options: ISaveOptions = Object.create(null)): Promise<ITextFileOperationResult> {
|
||||
|
||||
@@ -104,11 +104,11 @@ class ResourceModelCollection extends ReferenceCollection<Promise<ITextEditorMod
|
||||
private resolveTextModelContent(key: string): Promise<ITextModel> {
|
||||
const resource = URI.parse(key);
|
||||
const providers = this.providers[resource.scheme] || [];
|
||||
const factories = providers.map(p => () => Promise.resolve<ITextModel | undefined | null>(p.provideTextContent(resource)));
|
||||
const factories = providers.map(p => () => Promise.resolve(p.provideTextContent(resource)));
|
||||
|
||||
return first(factories).then(model => {
|
||||
if (!model) {
|
||||
return Promise.reject<any>(new Error('resource is not available'));
|
||||
return Promise.reject(new Error('resource is not available'));
|
||||
}
|
||||
|
||||
return model;
|
||||
|
||||
@@ -15,8 +15,8 @@ import { IMarkerService } from 'vs/platform/markers/common/markers';
|
||||
import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ExtHostLanguageFeatures } from 'vs/workbench/api/node/extHostLanguageFeatures';
|
||||
import { MainThreadLanguageFeatures } from 'vs/workbench/api/electron-browser/mainThreadLanguageFeatures';
|
||||
import { IHeapService } from 'vs/workbench/api/electron-browser/mainThreadHeapService';
|
||||
import { MainThreadLanguageFeatures } from 'vs/workbench/api/browser/mainThreadLanguageFeatures';
|
||||
import { IHeapService, NullHeapService } from 'vs/workbench/services/heap/common/heap';
|
||||
import { ExtHostApiCommands } from 'vs/workbench/api/node/extHostApiCommands';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
|
||||
@@ -67,12 +67,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
{
|
||||
let instantiationService = new TestInstantiationService();
|
||||
rpcProtocol = new TestRPCProtocol();
|
||||
instantiationService.stub(IHeapService, {
|
||||
_serviceBrand: undefined,
|
||||
trackObject(_obj: any) {
|
||||
// nothing
|
||||
}
|
||||
});
|
||||
instantiationService.stub(IHeapService, NullHeapService);
|
||||
instantiationService.stub(ICommandService, {
|
||||
_serviceBrand: undefined,
|
||||
executeCommand(id: string, args: any): any {
|
||||
|
||||
@@ -15,10 +15,10 @@ import { TestRPCProtocol } from './testRPCProtocol';
|
||||
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
||||
import { MarkerService } from 'vs/platform/markers/common/markerService';
|
||||
import { ExtHostLanguageFeatures } from 'vs/workbench/api/node/extHostLanguageFeatures';
|
||||
import { MainThreadLanguageFeatures } from 'vs/workbench/api/electron-browser/mainThreadLanguageFeatures';
|
||||
import { MainThreadLanguageFeatures } from 'vs/workbench/api/browser/mainThreadLanguageFeatures';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { MainThreadCommands } from 'vs/workbench/api/browser/mainThreadCommands';
|
||||
import { IHeapService } from 'vs/workbench/api/electron-browser/mainThreadHeapService';
|
||||
import { IHeapService, NullHeapService } from 'vs/workbench/services/heap/common/heap';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { getDocumentSymbols } from 'vs/editor/contrib/quickOpen/quickOpen';
|
||||
@@ -81,12 +81,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
{
|
||||
let instantiationService = new TestInstantiationService();
|
||||
instantiationService.stub(IMarkerService, MarkerService);
|
||||
instantiationService.stub(IHeapService, {
|
||||
_serviceBrand: undefined,
|
||||
trackObject(_obj: any) {
|
||||
// nothing
|
||||
}
|
||||
});
|
||||
instantiationService.stub(IHeapService, NullHeapService);
|
||||
inst = instantiationService;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user