Merge remote-tracking branch 'origin/master' into searchView/context/extensionPoints

This commit is contained in:
digeff
2020-11-10 12:58:25 -08:00
646 changed files with 25832 additions and 23631 deletions

View File

@@ -28,6 +28,10 @@ const configurationEntrySchema: IJSONSchema = {
properties: {
description: nls.localize('vscode.extension.contributes.configuration.properties', 'Description of the configuration properties.'),
type: 'object',
propertyNames: {
pattern: '\\S+',
patternErrorMessage: nls.localize('vscode.extension.contributes.configuration.property.empty', 'Property should not be empty.'),
},
additionalProperties: {
anyOf: [
{ $ref: 'http://json-schema.org/draft-07/schema#' },

View File

@@ -57,7 +57,7 @@ import { Dto } from 'vs/base/common/types';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { DebugConfigurationProviderTriggerKind } from 'vs/workbench/api/common/extHostTypes';
import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility';
import { IExtensionIdWithVersion } from 'vs/platform/userDataSync/common/storageKeys';
import { IExtensionIdWithVersion } from 'vs/platform/userDataSync/common/extensionsStorageSync';
export interface IEnvironment {
isExtensionDevelopmentDebug: boolean;
@@ -292,7 +292,7 @@ export interface MainThreadTextEditorsShape extends IDisposable {
export interface MainThreadTreeViewsShape extends IDisposable {
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean; }): void;
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem; }): Promise<void>;
$reveal(treeViewId: string, treeItem: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise<void>;
$reveal(treeViewId: string, itemInfo: { item: ITreeItem, parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise<void>;
$setMessage(treeViewId: string, message: string): void;
$setTitle(treeViewId: string, title: string, description: string | undefined): void;
}
@@ -920,7 +920,7 @@ export interface MainThreadDebugServiceShape extends IDisposable {
$acceptDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void;
$acceptDAError(handle: number, name: string, message: string, stack: string | undefined): void;
$acceptDAExit(handle: number, code: number | undefined, signal: string | undefined): void;
$registerDebugConfigurationProvider(type: string, triggerKind: DebugConfigurationProviderTriggerKind, hasProvideMethod: boolean, hasResolveMethod: boolean, hasResolve2Method: boolean, hasProvideDaMethod: boolean, handle: number): Promise<void>;
$registerDebugConfigurationProvider(type: string, triggerKind: DebugConfigurationProviderTriggerKind, hasProvideMethod: boolean, hasResolveMethod: boolean, hasResolve2Method: boolean, handle: number): Promise<void>;
$registerDebugAdapterDescriptorFactory(type: string, handle: number): Promise<void>;
$unregisterDebugConfigurationProvider(handle: number): void;
$unregisterDebugAdapterDescriptorFactory(handle: number): void;
@@ -1602,7 +1602,6 @@ export interface ExtHostDebugServiceShape {
$resolveDebugConfiguration(handle: number, folder: UriComponents | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>;
$resolveDebugConfigurationWithSubstitutedVariables(handle: number, folder: UriComponents | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>;
$provideDebugConfigurations(handle: number, folder: UriComponents | undefined, token: CancellationToken): Promise<IConfig[]>;
$legacyDebugAdapterExecutable(handle: number, folderUri: UriComponents | undefined): Promise<IAdapterDescriptor>; // TODO@AW legacy
$provideDebugAdapter(handle: number, session: IDebugSessionDto): Promise<IAdapterDescriptor>;
$acceptDebugSessionStarted(session: IDebugSessionDto): void;
$acceptDebugSessionTerminated(session: IDebugSessionDto): void;

View File

@@ -23,7 +23,6 @@ import { ExtHostConfigProvider, IExtHostConfiguration } from '../common/extHostC
import { convertToVSCPaths, convertToDAPaths, isDebuggerMainContribution } from 'vs/workbench/contrib/debug/common/debugUtils';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import { ISignService } from 'vs/platform/sign/common/sign';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
@@ -97,7 +96,6 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
private readonly _onDidChangeBreakpoints: Emitter<vscode.BreakpointsChangeEvent>;
private _aexCommands: Map<string, string>;
private _debugAdapters: Map<number, IDebugAdapter>;
private _debugAdaptersTrackers: Map<number, vscode.DebugAdapterTracker>;
@@ -105,14 +103,12 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
private _signService: ISignService | undefined;
constructor(
@IExtHostRpcService extHostRpcService: IExtHostRpcService,
@IExtHostWorkspace private _workspaceService: IExtHostWorkspace,
@IExtHostExtensionService private _extensionService: IExtHostExtensionService,
@IExtHostDocumentsAndEditors private _editorsService: IExtHostDocumentsAndEditors,
@IExtHostConfiguration protected _configurationService: IExtHostConfiguration,
@IExtHostCommands private _commandService: IExtHostCommands
) {
this._configProviderHandleCounter = 0;
this._configProviders = [];
@@ -123,7 +119,6 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
this._trackerFactoryHandleCounter = 0;
this._trackerFactories = [];
this._aexCommands = new Map();
this._debugAdapters = new Map();
this._debugAdaptersTrackers = new Map();
@@ -182,7 +177,6 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
private registerAllDebugTypes(extensionRegistry: ExtensionDescriptionRegistry) {
const debugTypes: string[] = [];
this._aexCommands.clear();
for (const ed of extensionRegistry.getAllExtensionDescriptions()) {
if (ed.contributes) {
@@ -191,9 +185,6 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
for (const dbg of debuggers) {
if (isDebuggerMainContribution(dbg)) {
debugTypes.push(dbg.type);
if (dbg.adapterExecutableCommand) {
this._aexCommands.set(dbg.type, dbg.adapterExecutableCommand);
}
}
}
}
@@ -312,10 +303,6 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
return new Disposable(() => { });
}
if (provider.debugAdapterExecutable) {
console.error('DebugConfigurationProvider.debugAdapterExecutable is deprecated and will be removed soon; please use DebugAdapterDescriptorFactory.createDebugAdapterDescriptor instead.');
}
const handle = this._configProviderHandleCounter++;
this._configProviders.push({ type, handle, provider });
@@ -323,7 +310,6 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
!!provider.provideDebugConfigurations,
!!provider.resolveDebugConfiguration,
!!provider.resolveDebugConfigurationWithSubstitutedVariables,
!!provider.debugAdapterExecutable, // TODO@AW: deprecated
handle);
return new Disposable(() => {
@@ -651,26 +637,6 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
});
}
// TODO@AW deprecated and legacy
public $legacyDebugAdapterExecutable(configProviderHandle: number, folderUri: UriComponents | undefined): Promise<IAdapterDescriptor> {
return asPromise(async () => {
const provider = this.getConfigProviderByHandle(configProviderHandle);
if (!provider) {
throw new Error('no DebugConfigurationProvider found');
}
if (!provider.debugAdapterExecutable) {
throw new Error('DebugConfigurationProvider has no method debugAdapterExecutable');
}
const folder = await this.getFolder(folderUri);
return provider.debugAdapterExecutable(folder, CancellationToken.None);
}).then(executable => {
if (!executable) {
throw new Error('nothing returned from DebugConfigurationProvider.debugAdapterExecutable');
}
return this.convertToDto(executable);
});
}
public async $provideDebugAdapter(adapterFactoryHandle: number, sessionDto: IDebugSessionDto): Promise<IAdapterDescriptor> {
const adapterDescriptorFactory = this.getAdapterDescriptorFactoryByHandle(adapterFactoryHandle);
if (!adapterDescriptorFactory) {
@@ -830,18 +796,6 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
return Promise.resolve(new DebugAdapterServer(serverPort));
}
// TODO@AW legacy
const pair = this._configProviders.filter(p => p.type === session.type).pop();
if (pair && pair.provider.debugAdapterExecutable) {
const func = pair.provider.debugAdapterExecutable;
return asPromise(() => func(session.workspaceFolder, CancellationToken.None)).then(executable => {
if (executable) {
return executable;
}
return undefined;
});
}
if (adapterDescriptorFactory) {
const extensionRegistry = await this._extensionService.getExtensionRegistry();
return asPromise(() => adapterDescriptorFactory.createDebugAdapterDescriptor(session, this.daExecutableFromPackage(session, extensionRegistry))).then(daDescriptor => {
@@ -852,17 +806,6 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
});
}
// try deprecated command based extension API "adapterExecutableCommand" to determine the executable
// TODO@AW legacy
const aex = this._aexCommands.get(session.type);
if (aex) {
const folder = session.workspaceFolder;
const rootFolder = folder ? folder.uri.toString() : undefined;
return this._commandService.executeCommand(aex, rootFolder).then((ae: any) => {
return new DebugAdapterExecutable(ae.command, ae.args || []);
});
}
// fallback: use executable information from package.json
const extensionRegistry = await this._extensionService.getExtensionRegistry();
return Promise.resolve(this.daExecutableFromPackage(session, extensionRegistry));
@@ -1118,10 +1061,9 @@ export class WorkerExtHostDebugService extends ExtHostDebugServiceBase {
@IExtHostWorkspace workspaceService: IExtHostWorkspace,
@IExtHostExtensionService extensionService: IExtHostExtensionService,
@IExtHostDocumentsAndEditors editorsService: IExtHostDocumentsAndEditors,
@IExtHostConfiguration configurationService: IExtHostConfiguration,
@IExtHostCommands commandService: IExtHostCommands
@IExtHostConfiguration configurationService: IExtHostConfiguration
) {
super(extHostRpcService, workspaceService, extensionService, editorsService, configurationService, commandService);
super(extHostRpcService, workspaceService, extensionService, editorsService, configurationService);
}
protected createVariableResolver(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider): AbstractVariableResolverService {

View File

@@ -13,6 +13,7 @@ import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors';
import { Schemas } from 'vs/base/common/network';
import { ILogService } from 'vs/platform/log/common/log';
import { CancellationToken } from 'vs/base/common/cancellation';
import { splitLines } from 'vs/base/common/strings';
export class ExtHostDocumentContentProvider implements ExtHostDocumentContentProvidersShape {
@@ -61,7 +62,7 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro
}
// create lines and compare
const lines = value.split(/\r\n|\r|\n/);
const lines = splitLines(value);
// broadcast event when content changed
if (!document.equalLines(lines)) {

View File

@@ -32,7 +32,6 @@ import { IdGenerator } from 'vs/base/common/idGenerator';
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
import { Cache } from './cache';
import { StopWatch } from 'vs/base/common/stopwatch';
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
// --- adapter
@@ -117,65 +116,57 @@ class CodeLensAdapter {
private readonly _provider: vscode.CodeLensProvider
) { }
provideCodeLenses(resource: URI, token: CancellationToken): Promise<extHostProtocol.ICodeLensListDto | undefined> {
async provideCodeLenses(resource: URI, token: CancellationToken): Promise<extHostProtocol.ICodeLensListDto | undefined> {
const doc = this._documents.getDocument(resource);
return asPromise(() => this._provider.provideCodeLenses(doc, token)).then(lenses => {
if (!lenses || token.isCancellationRequested) {
return undefined;
}
const cacheId = this._cache.add(lenses);
const disposables = new DisposableStore();
this._disposables.set(cacheId, disposables);
const result: extHostProtocol.ICodeLensListDto = {
cacheId,
lenses: [],
};
for (let i = 0; i < lenses.length; i++) {
result.lenses.push({
cacheId: [cacheId, i],
range: typeConvert.Range.from(lenses[i].range),
command: this._commands.toInternal(lenses[i].command, disposables)
});
}
return result;
});
const lenses = await this._provider.provideCodeLenses(doc, token);
if (!lenses || token.isCancellationRequested) {
return undefined;
}
const cacheId = this._cache.add(lenses);
const disposables = new DisposableStore();
this._disposables.set(cacheId, disposables);
const result: extHostProtocol.ICodeLensListDto = {
cacheId,
lenses: [],
};
for (let i = 0; i < lenses.length; i++) {
result.lenses.push({
cacheId: [cacheId, i],
range: typeConvert.Range.from(lenses[i].range),
command: this._commands.toInternal(lenses[i].command, disposables)
});
}
return result;
}
resolveCodeLens(symbol: extHostProtocol.ICodeLensDto, token: CancellationToken): Promise<extHostProtocol.ICodeLensDto | undefined> {
async resolveCodeLens(symbol: extHostProtocol.ICodeLensDto, token: CancellationToken): Promise<extHostProtocol.ICodeLensDto | undefined> {
const lens = symbol.cacheId && this._cache.get(...symbol.cacheId);
if (!lens) {
return Promise.resolve(undefined);
return undefined;
}
let resolve: Promise<vscode.CodeLens | undefined | null>;
let resolvedLens: vscode.CodeLens | undefined | null;
if (typeof this._provider.resolveCodeLens !== 'function' || lens.isResolved) {
resolve = Promise.resolve(lens);
resolvedLens = lens;
} else {
resolve = asPromise(() => this._provider.resolveCodeLens!(lens, token));
resolvedLens = await this._provider.resolveCodeLens(lens, token);
}
if (!resolvedLens) {
resolvedLens = lens;
}
return resolve.then(newLens => {
if (token.isCancellationRequested) {
return undefined;
}
const disposables = symbol.cacheId && this._disposables.get(symbol.cacheId[0]);
if (!disposables) {
// We've already been disposed of
return undefined;
}
newLens = newLens || lens;
symbol.command = this._commands.toInternal(newLens.command || CodeLensAdapter._badCmd, disposables);
return symbol;
});
if (token.isCancellationRequested) {
return undefined;
}
const disposables = symbol.cacheId && this._disposables.get(symbol.cacheId[0]);
if (!disposables) {
// disposed in the meantime
return undefined;
}
symbol.command = this._commands.toInternal(resolvedLens.command ?? CodeLensAdapter._badCmd, disposables);
return symbol;
}
releaseCodeLenses(cachedId: number): void {
@@ -1814,7 +1805,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(URI.revive(resource), colorInfo, token), undefined);
}
registerFoldingRangeProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.FoldingRangeProvider2): vscode.Disposable {
registerFoldingRangeProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.FoldingRangeProvider): vscode.Disposable {
const handle = this._nextHandle();
const eventHandle = typeof provider.onDidChangeFoldingRanges === 'function' ? this._nextHandle() : undefined;
@@ -1823,8 +1814,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
let result = this._createDisposable(handle);
if (eventHandle !== undefined) {
checkProposedApiEnabled(extension);
const subscription = provider.onDidChangeFoldingRanges!(_ => this._proxy.$emitFoldingRangeEvent(eventHandle));
const subscription = provider.onDidChangeFoldingRanges!(() => this._proxy.$emitFoldingRangeEvent(eventHandle));
result = Disposable.from(result, subscription);
}

View File

@@ -7,7 +7,7 @@ import { MainContext, MainThreadStorageShape, ExtHostStorageShape } from './extH
import { Emitter } from 'vs/base/common/event';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionIdWithVersion } from 'vs/platform/userDataSync/common/storageKeys';
import { IExtensionIdWithVersion } from 'vs/platform/userDataSync/common/extensionsStorageSync';
export interface IStorageChangeEvent {
shared: boolean;

View File

@@ -188,6 +188,10 @@ export namespace CustomExecutionDTO {
customExecution: 'customExecution'
};
}
export function to(taskId: string, providedCustomExeutions: Map<string, types.CustomExecution>): types.CustomExecution | undefined {
return providedCustomExeutions.get(taskId);
}
}
@@ -274,15 +278,17 @@ export namespace TaskDTO {
};
return result;
}
export async function to(value: tasks.TaskDTO | undefined, workspace: IExtHostWorkspaceProvider): Promise<types.Task | undefined> {
export async function to(value: tasks.TaskDTO | undefined, workspace: IExtHostWorkspaceProvider, providedCustomExeutions: Map<string, types.CustomExecution>): Promise<types.Task | undefined> {
if (value === undefined || value === null) {
return undefined;
}
let execution: types.ShellExecution | types.ProcessExecution | undefined;
let execution: types.ShellExecution | types.ProcessExecution | types.CustomExecution | undefined;
if (ProcessExecutionDTO.is(value.execution)) {
execution = ProcessExecutionDTO.to(value.execution);
} else if (ShellExecutionDTO.is(value.execution)) {
execution = ShellExecutionDTO.to(value.execution);
} else if (CustomExecutionDTO.is(value.execution)) {
execution = CustomExecutionDTO.to(value._id, providedCustomExeutions);
}
const definition: vscode.TaskDefinition | undefined = TaskDefinitionDTO.to(value.definition);
let scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder | undefined;
@@ -354,13 +360,6 @@ class TaskExecutionImpl implements vscode.TaskExecution {
}
export namespace TaskExecutionDTO {
export async function to(value: tasks.TaskExecutionDTO, tasks: ExtHostTaskBase, workspaceProvider: IExtHostWorkspaceProvider): Promise<vscode.TaskExecution> {
const task = await TaskDTO.to(value.task, workspaceProvider);
if (!task) {
throw new Error('Unexpected: Task cannot be created.');
}
return new TaskExecutionImpl(tasks, value.id, task);
}
export function from(value: vscode.TaskExecution): tasks.TaskExecutionDTO {
return {
id: (value as TaskExecutionImpl)._id,
@@ -447,7 +446,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape, IExtHostTask
return this._proxy.$fetchTasks(TaskFilterDTO.from(filter)).then(async (values) => {
const result: vscode.Task[] = [];
for (let value of values) {
const task = await TaskDTO.to(value, this._workspaceProvider);
const task = await TaskDTO.to(value, this._workspaceProvider, this._providedCustomExecutions2);
if (task) {
result.push(task);
}
@@ -573,7 +572,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape, IExtHostTask
throw new Error(`Unexpected: Task of type [${taskDTO.definition.type}] cannot be resolved by provider of type [${handler.type}].`);
}
const task = await TaskDTO.to(taskDTO, this._workspaceProvider);
const task = await TaskDTO.to(taskDTO, this._workspaceProvider, this._providedCustomExecutions2);
if (!task) {
throw new Error('Unexpected: Task cannot be resolved.');
}
@@ -631,7 +630,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape, IExtHostTask
return result;
}
const createdResult: Promise<TaskExecutionImpl> = new Promise(async (resolve, reject) => {
const taskToCreate = task ? task : await TaskDTO.to(execution.task, this._workspaceProvider);
const taskToCreate = task ? task : await TaskDTO.to(execution.task, this._workspaceProvider, this._providedCustomExecutions2);
if (!taskToCreate) {
reject('Unexpected: Task does not exist.');
} else {
@@ -705,6 +704,10 @@ export class WorkerExtHostTask extends ExtHostTaskBase {
}
public async executeTask(extension: IExtensionDescription, task: vscode.Task): Promise<vscode.TaskExecution> {
if (!task.execution) {
throw new Error('Tasks to execute must include an execution');
}
const dto = TaskDTO.from(task, extension);
if (dto === undefined) {
throw new Error('Task is not valid');

View File

@@ -293,7 +293,7 @@ class ExtHostTreeView<T> extends Disposable {
return this.elements.get(treeItemHandle);
}
reveal(element: T, options?: IRevealOptions): Promise<void> {
reveal(element: T | undefined, options?: IRevealOptions): Promise<void> {
options = options ? options : { select: true, focus: false };
const select = isUndefinedOrNull(options.select) ? true : options.select;
const focus = isUndefinedOrNull(options.focus) ? false : options.focus;
@@ -302,10 +302,15 @@ class ExtHostTreeView<T> extends Disposable {
if (typeof this.dataProvider.getParent !== 'function') {
return Promise.reject(new Error(`Required registered TreeDataProvider to implement 'getParent' method to access 'reveal' method`));
}
return this.refreshPromise
.then(() => this.resolveUnknownParentChain(element))
.then(parentChain => this.resolveTreeNode(element, parentChain[parentChain.length - 1])
.then(treeNode => this.proxy.$reveal(this.viewId, treeNode.item, parentChain.map(p => p.item), { select, focus, expand })), error => this.logService.error(error));
if (element) {
return this.refreshPromise
.then(() => this.resolveUnknownParentChain(element))
.then(parentChain => this.resolveTreeNode(element, parentChain[parentChain.length - 1])
.then(treeNode => this.proxy.$reveal(this.viewId, { item: treeNode.item, parentChain: parentChain.map(p => p.item) }, { select, focus, expand })), error => this.logService.error(error));
} else {
return this.proxy.$reveal(this.viewId, undefined, { select, focus, expand });
}
}
private _message: string = '';

View File

@@ -1183,6 +1183,7 @@ export namespace FoldingRangeKind {
export interface TextEditorOpenOptions extends vscode.TextDocumentShowOptions {
background?: boolean;
override?: boolean;
}
export namespace TextEditorOpenOptions {
@@ -1194,6 +1195,7 @@ export namespace TextEditorOpenOptions {
inactive: options.background,
preserveFocus: options.preserveFocus,
selection: typeof options.selection === 'object' ? Range.from(options.selection) : undefined,
override: typeof options.override === 'boolean' ? false : undefined
};
}

View File

@@ -4,10 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import { coalesceInPlace, equals } from 'vs/base/common/arrays';
import { escapeCodicons } from 'vs/base/common/codicons';
import { illegalArgument } from 'vs/base/common/errors';
import { IRelativePattern } from 'vs/base/common/glob';
import { isMarkdownString } from 'vs/base/common/htmlContent';
import { isMarkdownString, MarkdownString as BaseMarkdownString } from 'vs/base/common/htmlContent';
import { ResourceMap } from 'vs/base/common/map';
import { isStringArray } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
@@ -1290,40 +1289,7 @@ export class CodeInset {
@es5ClassCompat
export class MarkdownString {
value: string;
isTrusted?: boolean;
readonly supportThemeIcons?: boolean;
constructor(value?: string, supportThemeIcons: boolean = false) {
this.value = value ?? '';
this.supportThemeIcons = supportThemeIcons;
}
appendText(value: string): MarkdownString {
// escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
this.value += (this.supportThemeIcons ? escapeCodicons(value) : value)
.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
.replace(/\n/, '\n\n');
return this;
}
appendMarkdown(value: string): MarkdownString {
this.value += value;
return this;
}
appendCodeblock(code: string, language: string = ''): MarkdownString {
this.value += '\n```';
this.value += language;
this.value += '\n';
this.value += code;
this.value += '\n```\n';
return this;
}
export class MarkdownString extends BaseMarkdownString implements vscode.MarkdownString {
static isMarkdownString(thing: any): thing is vscode.MarkdownString {
if (thing instanceof MarkdownString) {
@@ -1331,6 +1297,11 @@ export class MarkdownString {
}
return thing && thing.appendCodeblock && thing.appendMarkdown && thing.appendText && (thing.value !== undefined);
}
constructor(value?: string, supportThemeIcons: boolean = false) {
super(value ?? '', { supportThemeIcons });
}
}
@es5ClassCompat

View File

@@ -10,17 +10,18 @@ import { Emitter, Event } from 'vs/base/common/event';
import { TernarySearchTree } from 'vs/base/common/map';
import { Schemas } from 'vs/base/common/network';
import { Counter } from 'vs/base/common/numbers';
import { isLinux } from 'vs/base/common/platform';
import { basename, basenameOrAuthority, dirname, isEqual, relativePath } from 'vs/base/common/resources';
import { compare } from 'vs/base/common/strings';
import { withUndefinedAsNull } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { FileSystemProviderCapabilities } from 'vs/platform/files/common/files';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
import { Severity } from 'vs/platform/notification/common/notification';
import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { Range, RelativePattern } from 'vs/workbench/api/common/extHostTypes';
@@ -59,6 +60,11 @@ function delta(oldFolders: vscode.WorkspaceFolder[], newFolders: vscode.Workspac
return arrayDelta(oldSortedFolders, newSortedFolders, compare);
}
function ignorePathCasing(uri: URI, extHostFileSystemInfo: IExtHostFileSystemInfo): boolean {
const capabilities = extHostFileSystemInfo.getCapabilities(uri.scheme);
return !(capabilities && (capabilities & FileSystemProviderCapabilities.PathCaseSensitive));
}
interface MutableWorkspaceFolder extends vscode.WorkspaceFolder {
name: string;
index: number;
@@ -66,7 +72,7 @@ interface MutableWorkspaceFolder extends vscode.WorkspaceFolder {
class ExtHostWorkspaceImpl extends Workspace {
static toExtHostWorkspace(data: IWorkspaceData | null, previousConfirmedWorkspace?: ExtHostWorkspaceImpl, previousUnconfirmedWorkspace?: ExtHostWorkspaceImpl): { workspace: ExtHostWorkspaceImpl | null, added: vscode.WorkspaceFolder[], removed: vscode.WorkspaceFolder[] } {
static toExtHostWorkspace(data: IWorkspaceData | null, previousConfirmedWorkspace: ExtHostWorkspaceImpl | undefined, previousUnconfirmedWorkspace: ExtHostWorkspaceImpl | undefined, extHostFileSystemInfo: IExtHostFileSystemInfo): { workspace: ExtHostWorkspaceImpl | null, added: vscode.WorkspaceFolder[], removed: vscode.WorkspaceFolder[] } {
if (!data) {
return { workspace: null, added: [], removed: [] };
}
@@ -99,7 +105,7 @@ class ExtHostWorkspaceImpl extends Workspace {
// make sure to restore sort order based on index
newWorkspaceFolders.sort((f1, f2) => f1.index < f2.index ? -1 : 1);
const workspace = new ExtHostWorkspaceImpl(id, name, newWorkspaceFolders, configuration ? URI.revive(configuration) : null, !!isUntitled);
const workspace = new ExtHostWorkspaceImpl(id, name, newWorkspaceFolders, configuration ? URI.revive(configuration) : null, !!isUntitled, uri => ignorePathCasing(uri, extHostFileSystemInfo));
const { added, removed } = delta(oldWorkspace ? oldWorkspace.workspaceFolders : [], workspace.workspaceFolders, compareWorkspaceFolderByUri);
return { workspace, added, removed };
@@ -117,10 +123,11 @@ class ExtHostWorkspaceImpl extends Workspace {
}
private readonly _workspaceFolders: vscode.WorkspaceFolder[] = [];
private readonly _structure = TernarySearchTree.forUris<vscode.WorkspaceFolder>(!isLinux);
private readonly _structure: TernarySearchTree<URI, vscode.WorkspaceFolder>;
constructor(id: string, private _name: string, folders: vscode.WorkspaceFolder[], configuration: URI | null, private _isUntitled: boolean) {
super(id, folders.map(f => new WorkspaceFolder(f)), configuration);
constructor(id: string, private _name: string, folders: vscode.WorkspaceFolder[], configuration: URI | null, private _isUntitled: boolean, ignorePathCasing: (key: URI) => boolean) {
super(id, folders.map(f => new WorkspaceFolder(f)), configuration, ignorePathCasing);
this._structure = TernarySearchTree.forUris2<vscode.WorkspaceFolder>(ignorePathCasing);
// setup the workspace folder data structure
folders.forEach(folder => {
@@ -170,22 +177,25 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
private readonly _proxy: MainThreadWorkspaceShape;
private readonly _messageService: MainThreadMessageServiceShape;
private readonly _extHostFileSystemInfo: IExtHostFileSystemInfo;
private readonly _activeSearchCallbacks: ((match: IRawFileMatch2) => any)[] = [];
constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService,
@IExtHostInitDataService initData: IExtHostInitDataService,
@IExtHostFileSystemInfo extHostFileSystemInfo: IExtHostFileSystemInfo,
@ILogService logService: ILogService,
) {
this._logService = logService;
this._extHostFileSystemInfo = extHostFileSystemInfo;
this._requestIdProvider = new Counter();
this._barrier = new Barrier();
this._proxy = extHostRpc.getProxy(MainContext.MainThreadWorkspace);
this._messageService = extHostRpc.getProxy(MainContext.MainThreadMessageService);
const data = initData.workspace;
this._confirmedWorkspace = data ? new ExtHostWorkspaceImpl(data.id, data.name, [], data.configuration ? URI.revive(data.configuration) : null, !!data.isUntitled) : undefined;
this._confirmedWorkspace = data ? new ExtHostWorkspaceImpl(data.id, data.name, [], data.configuration ? URI.revive(data.configuration) : null, !!data.isUntitled, uri => ignorePathCasing(uri, extHostFileSystemInfo)) : undefined;
}
$initializeWorkspace(data: IWorkspaceData | null): void {
@@ -391,13 +401,13 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
configuration: this._actualWorkspace.configuration,
folders,
isUntitled: this._actualWorkspace.isUntitled
} as IWorkspaceData, this._actualWorkspace).workspace || undefined;
} as IWorkspaceData, this._actualWorkspace, undefined, this._extHostFileSystemInfo).workspace || undefined;
}
}
$acceptWorkspaceData(data: IWorkspaceData | null): void {
const { workspace, added, removed } = ExtHostWorkspaceImpl.toExtHostWorkspace(data, this._confirmedWorkspace, this._unconfirmedWorkspace);
const { workspace, added, removed } = ExtHostWorkspaceImpl.toExtHostWorkspace(data, this._confirmedWorkspace, this._unconfirmedWorkspace, this._extHostFileSystemInfo);
// Update our workspace object. We have a confirmed workspace, so we drop our
// unconfirmed workspace.

View File

@@ -625,6 +625,7 @@ submenusExtensionPoint.setHandler(extensions => {
const _apiMenusByKey = new Map(Iterable.map(Iterable.from(apiMenus), menu => ([menu.key, menu])));
const _menuRegistrations = new DisposableStore();
const _submenuMenuItems = new Map<number /* menu id */, Set<number /* submenu id */>>();
const menusExtensionPoint = ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: (schema.IUserFriendlyMenuItem | schema.IUserFriendlySubmenuItem)[] }>({
extensionPoint: 'menus',
@@ -636,6 +637,7 @@ menusExtensionPoint.setHandler(extensions => {
// remove all previous menu registrations
_menuRegistrations.clear();
_submenuMenuItems.clear();
const items: { id: MenuId, item: IMenuItem | ISubmenuItem }[] = [];
@@ -703,6 +705,20 @@ menusExtensionPoint.setHandler(extensions => {
continue;
}
let submenuRegistrations = _submenuMenuItems.get(menu.id.id);
if (!submenuRegistrations) {
submenuRegistrations = new Set();
_submenuMenuItems.set(menu.id.id, submenuRegistrations);
}
if (submenuRegistrations.has(submenu.id.id)) {
collector.warn(localize('submenuItem.duplicate', "The `{0}` submenu was already contributed to the `{1}` menu.", menuItem.submenu, entry.key));
continue;
}
submenuRegistrations.add(submenu.id.id);
item = { submenu: submenu.id, icon: submenu.icon, title: submenu.label, group: undefined, order: undefined, when: undefined };
}