Merge from vscode 2f984aad710215f4e4684a035bb02f55d1a9e2cc (#9819)

This commit is contained in:
Anthony Dresser
2020-04-01 00:44:39 -07:00
committed by GitHub
parent 0e27aaa61f
commit 0bfbdc62ed
247 changed files with 5402 additions and 3311 deletions

View File

@@ -14,7 +14,7 @@ import { IResolvedBackup, IBackupFileService } from 'vs/workbench/services/backu
import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
import { ITextSnapshot } from 'vs/editor/common/model';
import { createTextBufferFactoryFromStream, createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
import { keys, ResourceMap } from 'vs/base/common/map';
import { ResourceMap } from 'vs/base/common/map';
import { Schemas } from 'vs/base/common/network';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { VSBuffer } from 'vs/base/common/buffer';
@@ -434,7 +434,7 @@ export class InMemoryBackupFileService implements IBackupFileService {
}
async getBackups(): Promise<URI[]> {
return keys(this.backups).map(key => URI.parse(key));
return Array.from(this.backups.keys()).map(key => URI.parse(key));
}
async discardBackup(resource: URI): Promise<void> {

View File

@@ -203,7 +203,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
return;
}
} catch (e) { /* Ignore */ }
storedFoldersToAdd.push(getStoredWorkspaceFolder(folderURI, folderToAdd.name, workspaceConfigFolder, slashForPath));
storedFoldersToAdd.push(getStoredWorkspaceFolder(folderURI, false, folderToAdd.name, workspaceConfigFolder, slashForPath));
}));
// Apply to array of newStoredFolders

View File

@@ -20,7 +20,7 @@ import { IEditorGroupsService, IEditorGroup, GroupsOrder, IEditorReplacement, Gr
import { IResourceEditorInputType, SIDE_GROUP, IResourceEditorReplacement, IOpenEditorOverrideHandler, IEditorService, SIDE_GROUP_TYPE, ACTIVE_GROUP_TYPE, ISaveEditorsOptions, ISaveAllEditorsOptions, IRevertAllEditorsOptions, IBaseSaveRevertAllEditorOptions } from 'vs/workbench/services/editor/common/editorService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { Disposable, IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { coalesce, distinct } from 'vs/base/common/arrays';
import { coalesce, distinct, insert } from 'vs/base/common/arrays';
import { isCodeEditor, isDiffEditor, ICodeEditor, IDiffEditor, isCompositeEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorGroupView, IEditorOpeningEvent, EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
import { ILabelService } from 'vs/platform/label/common/label';
@@ -476,14 +476,9 @@ export class EditorService extends Disposable implements EditorServiceImpl {
private readonly openEditorHandlers: IOpenEditorOverrideHandler[] = [];
overrideOpenEditor(handler: IOpenEditorOverrideHandler): IDisposable {
this.openEditorHandlers.push(handler);
const remove = insert(this.openEditorHandlers, handler);
return toDisposable(() => {
const index = this.openEditorHandlers.indexOf(handler);
if (index >= 0) {
this.openEditorHandlers.splice(index, 1);
}
});
return toDisposable(() => remove());
}
private onGroupWillOpenEditor(group: IEditorGroup, event: IEditorOpeningEvent): void {

View File

@@ -12,7 +12,6 @@ import { IPath, IWindowConfiguration } from 'vs/platform/windows/common/windows'
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api';
import product from 'vs/platform/product/common/product';
import { serializableToMap } from 'vs/base/common/map';
import { memoize } from 'vs/base/common/decorators';
export class BrowserWindowConfiguration implements IWindowConfiguration {
@@ -69,6 +68,7 @@ interface IExtensionHostDebugEnvironment {
isExtensionDevelopment: boolean;
extensionDevelopmentLocationURI?: URI[];
extensionTestsLocationURI?: URI;
extensionEnabledProposedApi?: string[];
}
export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironmentService {
@@ -156,6 +156,14 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
return this._extensionHostDebugEnvironment.extensionTestsLocationURI;
}
get extensionEnabledProposedApi(): string[] | undefined {
if (!this._extensionHostDebugEnvironment) {
this._extensionHostDebugEnvironment = this.resolveExtensionHostDebugEnvironment();
}
return this._extensionHostDebugEnvironment.extensionEnabledProposedApi;
}
@memoize
get webviewExternalEndpoint(): string {
// TODO: get fallback from product.json
@@ -184,7 +192,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
constructor(readonly options: IBrowserWorkbenchEnvironmentConstructionOptions) {
if (options.workspaceProvider && Array.isArray(options.workspaceProvider.payload)) {
this.payload = serializableToMap(options.workspaceProvider.payload);
this.payload = new Map(options.workspaceProvider.payload);
}
}
@@ -216,6 +224,9 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
extensionHostDebugEnvironment.params.port = parseInt(value);
extensionHostDebugEnvironment.params.break = true;
break;
case 'enableProposedApi':
extensionHostDebugEnvironment.extensionEnabledProposedApi = [];
break;
}
}
}

View File

@@ -457,12 +457,12 @@ class ProposedApiController {
@IProductService productService: IProductService
) {
// Make enabled proposed API be lowercase for case insensitive comparison
this.enableProposedApiFor = (environmentService.args['enable-proposed-api'] || []).map(id => id.toLowerCase());
this.enableProposedApiFor = (environmentService.extensionEnabledProposedApi || []).map(id => id.toLowerCase());
this.enableProposedApiForAll =
!environmentService.isBuilt || // always allow proposed API when running out of sources
(!!environmentService.extensionDevelopmentLocationURI && productService.quality !== 'stable') || // do not allow proposed API against stable builds when developing an extension
(this.enableProposedApiFor.length === 0 && 'enable-proposed-api' in environmentService.args); // always allow proposed API if --enable-proposed-api is provided without extension ID
(this.enableProposedApiFor.length === 0 && Array.isArray(environmentService.extensionEnabledProposedApi)); // always allow proposed API if --enable-proposed-api is provided without extension ID
this.productAllowProposedApi = new Set<string>();
if (isNonEmptyArray(productService.extensionAllowedProposedApi)) {

View File

@@ -20,7 +20,6 @@ export interface IRPCProtocol {
assertRegistered(identifiers: ProxyIdentifier<any>[]): void;
}
// @ts-ignore
export class ProxyIdentifier<T> {
public static count = 0;
_proxyIdentifierBrand: void;

View File

@@ -5,7 +5,7 @@
import * as nativeWatchdog from 'native-watchdog';
import * as net from 'net';
import * as minimist from 'vscode-minimist';
import * as minimist from 'minimist';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Event } from 'vs/base/common/event';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';

View File

@@ -17,7 +17,6 @@ import { trackFocus } from 'vs/base/browser/dom';
import { Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { mapToSerializable } from 'vs/base/common/map';
/**
* A workspace to open in the workbench can either be:
@@ -142,7 +141,7 @@ export class BrowserHostService extends Disposable implements IHostService {
const environment = new Map<string, string>();
environment.set('openFile', openable.fileUri.toString());
this.workspaceProvider.open(undefined, { payload: mapToSerializable(environment) });
this.workspaceProvider.open(undefined, { payload: Array.from(environment.entries()) });
}
}
}

View File

@@ -14,7 +14,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { IWorkspaceContextService, IWorkspace } from 'vs/platform/workspace/common/workspace';
import { isEqual, basenameOrAuthority, basename, joinPath, dirname } from 'vs/base/common/resources';
import { tildify, getPathLabel } from 'vs/base/common/labels';
import { ltrim, endsWith } from 'vs/base/common/strings';
import { ltrim } from 'vs/base/common/strings';
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, WORKSPACE_EXTENSION, toWorkspaceIdentifier, isWorkspaceIdentifier, isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces';
import { ILabelService, ResourceLabelFormatter, ResourceLabelFormatting, IFormatterChangeEvent } from 'vs/platform/label/common/label';
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
@@ -200,7 +200,7 @@ export class LabelService extends Disposable implements ILabelService {
// Workspace: Saved
let filename = basename(workspace.configPath);
if (endsWith(filename, WORKSPACE_EXTENSION)) {
if (filename.endsWith(WORKSPACE_EXTENSION)) {
filename = filename.substr(0, filename.length - WORKSPACE_EXTENSION.length - 1);
}
let label;
@@ -275,7 +275,7 @@ export class LabelService extends Disposable implements ILabelService {
private appendSeparatorIfMissing(label: string, formatting: ResourceLabelFormatting): string {
let appendedLabel = label;
if (!endsWith(label, formatting.separator)) {
if (!label.endsWith(formatting.separator)) {
appendedLabel += formatting.separator;
}
return appendedLabel;

View File

@@ -11,7 +11,6 @@ import { Event } from 'vs/base/common/event';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IAction, Action } from 'vs/base/common/actions';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
export class NotificationService extends Disposable implements INotificationService {
@@ -21,8 +20,7 @@ export class NotificationService extends Disposable implements INotificationServ
get model(): INotificationsModel { return this._model; }
constructor(
@IStorageService private readonly storageService: IStorageService,
@IStorageKeysSyncRegistryService private readonly storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
@IStorageService private readonly storageService: IStorageService
) {
super();
}
@@ -70,11 +68,6 @@ export class NotificationService extends Disposable implements INotificationServ
const scope = notification.neverShowAgain.scope === NeverShowAgainScope.WORKSPACE ? StorageScope.WORKSPACE : StorageScope.GLOBAL;
const id = notification.neverShowAgain.id;
// opt-in to syncing if global
if (scope === StorageScope.GLOBAL) {
this.storageKeysSyncRegistryService.registerStorageKey({ key: id, version: 1 });
}
// If the user already picked to not show the notification
// again, we return with a no-op notification here
if (this.storageService.getBoolean(id, scope)) {
@@ -126,11 +119,6 @@ export class NotificationService extends Disposable implements INotificationServ
const scope = options.neverShowAgain.scope === NeverShowAgainScope.WORKSPACE ? StorageScope.WORKSPACE : StorageScope.GLOBAL;
const id = options.neverShowAgain.id;
// opt-in to syncing if global
if (scope === StorageScope.GLOBAL) {
this.storageKeysSyncRegistryService.registerStorageKey({ key: id, version: 1 });
}
// If the user already picked to not show the notification
// again, we return with a no-op notification here
if (this.storageService.getBoolean(id, scope)) {

View File

@@ -77,7 +77,7 @@ export class FileWalker {
this.errors = [];
if (this.filePattern) {
this.normalizedFilePatternLowercase = prepareQuery(this.filePattern).valueLowercase;
this.normalizedFilePatternLowercase = prepareQuery(this.filePattern).normalizedLowercase;
}
this.globalExcludePattern = config.excludePattern && glob.parse(config.excludePattern);

View File

@@ -312,7 +312,7 @@ export class SearchService implements IRawSearchService {
// Pattern match on results
const results: IRawFileMatch[] = [];
const normalizedSearchValueLowercase = prepareQuery(searchValue).valueLowercase;
const normalizedSearchValueLowercase = prepareQuery(searchValue).normalizedLowercase;
for (const entry of cachedEntries) {
// Check if this entry is a match for the search value

View File

@@ -11,6 +11,7 @@ import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/
import { ITextFileSaveParticipant, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
import { SaveReason } from 'vs/workbench/common/editor';
import { IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { insert } from 'vs/base/common/arrays';
export class TextFileSaveParticipant extends Disposable {
@@ -24,9 +25,9 @@ export class TextFileSaveParticipant extends Disposable {
}
addSaveParticipant(participant: ITextFileSaveParticipant): IDisposable {
this.saveParticipants.push(participant);
const remove = insert(this.saveParticipants, participant);
return toDisposable(() => this.saveParticipants.splice(this.saveParticipants.indexOf(participant), 1));
return toDisposable(() => remove());
}
participate(model: ITextFileEditorModel, context: { reason: SaveReason; }, token: CancellationToken): Promise<void> {

View File

@@ -40,6 +40,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService
import { IRemotePathService } from 'vs/workbench/services/path/common/remotePathService';
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService';
import { ILogService } from 'vs/platform/log/common/log';
export class NativeTextFileService extends AbstractTextFileService {
@@ -58,7 +59,8 @@ export class NativeTextFileService extends AbstractTextFileService {
@ITextModelService textModelService: ITextModelService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@IRemotePathService remotePathService: IRemotePathService,
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService,
@ILogService private readonly logService: ILogService
) {
super(fileService, untitledTextEditorService, lifecycleService, instantiationService, modelService, environmentService, dialogService, fileDialogService, textResourceConfigurationService, filesConfigurationService, textModelService, codeEditorService, remotePathService, workingCopyFileService);
}
@@ -298,8 +300,16 @@ export class NativeTextFileService extends AbstractTextFileService {
sudoCommand.push('--file-write', `"${source}"`, `"${target}"`);
sudoPrompt.exec(sudoCommand.join(' '), promptOptions, (error: string, stdout: string, stderr: string) => {
if (error || stderr) {
reject(error || stderr);
if (stdout) {
this.logService.trace(`[sudo-prompt] received stdout: ${stdout}`);
}
if (stderr) {
this.logService.trace(`[sudo-prompt] received stderr: ${stderr}`);
}
if (error) {
reject(error);
} else {
resolve(undefined);
}

View File

@@ -86,7 +86,7 @@ export class ProductIconThemeData implements IWorkbenchProductIconTheme {
static get defaultTheme(): ProductIconThemeData {
let themeData = ProductIconThemeData._defaultProductIconTheme;
if (!themeData) {
themeData = ProductIconThemeData._defaultProductIconTheme = new ProductIconThemeData(DEFAULT_PRODUCT_ICON_THEME_ID, nls.localize('defaultTheme', 'Default theme'), DEFAULT_PRODUCT_ICON_THEME_SETTING_VALUE);
themeData = ProductIconThemeData._defaultProductIconTheme = new ProductIconThemeData(DEFAULT_PRODUCT_ICON_THEME_ID, nls.localize('defaultTheme', 'Default'), DEFAULT_PRODUCT_ICON_THEME_SETTING_VALUE);
themeData.isLoaded = true;
themeData.extensionData = undefined;
themeData.watch = false;

View File

@@ -115,7 +115,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
this.currentFileIconTheme = FileIconThemeData.createUnloadedTheme('');
this.productIconThemeWatcher = new ThemeFileWatcher(fileService, environmentService, this.reloadCurrentProductIconTheme.bind(this));
this.productIconThemeRegistry = new ThemeRegistry(extensionService, productIconThemesExtPoint, ProductIconThemeData.fromExtensionTheme, true, ProductIconThemeData.defaultTheme);
this.productIconThemeRegistry = new ThemeRegistry(extensionService, productIconThemesExtPoint, ProductIconThemeData.fromExtensionTheme, true, ProductIconThemeData.defaultTheme, true);
this.onProductIconThemeChange = new Emitter<IWorkbenchProductIconTheme>();
this.currentProductIconTheme = ProductIconThemeData.createUnloadedTheme('');
@@ -265,7 +265,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
if (e.affectsConfiguration(ThemeSettings.PREFERRED_HC_THEME) && this.getPreferredColorScheme() === HIGH_CONTRAST) {
this.applyPreferredColorTheme(HIGH_CONTRAST);
}
if (e.affectsConfiguration(ThemeSettings.ICON_THEME)) {
if (e.affectsConfiguration(ThemeSettings.FILE_ICON_THEME)) {
this.restoreFileIconTheme();
}
if (e.affectsConfiguration(ThemeSettings.PRODUCT_ICON_THEME)) {

View File

@@ -170,25 +170,6 @@ export class ColorThemeData implements IWorkbenchColorTheme {
}
}
}
for (const rule of tokenClassificationRegistry.getTokenStylingDefaultRules()) {
const matchScore = rule.selector.match(type, modifiers, language);
if (matchScore >= 0) {
let style: TokenStyle | undefined;
if (rule.defaults.scopesToProbe) {
style = this.resolveScopes(rule.defaults.scopesToProbe);
if (style) {
_processStyle(matchScore, style, rule.defaults.scopesToProbe);
}
}
if (!style && useDefault !== false) {
const tokenStyleValue = rule.defaults[this.type];
style = this.resolveTokenStyleValue(tokenStyleValue);
if (style) {
_processStyle(matchScore, style, tokenStyleValue!);
}
}
}
}
for (const rule of this.tokenStylingRules) {
const matchScore = rule.selector.match(type, modifiers, language);
if (matchScore >= 0) {
@@ -201,6 +182,36 @@ export class ColorThemeData implements IWorkbenchColorTheme {
_processStyle(matchScore, rule.style, rule);
}
}
let hasUndefinedStyleProperty = false;
for (let k in score) {
const key = k as keyof TokenStyle;
if (score[key] === -1) {
hasUndefinedStyleProperty = true;
} else {
score[key] = Number.MAX_VALUE; // set it to the max, so it won't be replaced by a default
}
}
if (hasUndefinedStyleProperty) {
for (const rule of tokenClassificationRegistry.getTokenStylingDefaultRules()) {
const matchScore = rule.selector.match(type, modifiers, language);
if (matchScore >= 0) {
let style: TokenStyle | undefined;
if (rule.defaults.scopesToProbe) {
style = this.resolveScopes(rule.defaults.scopesToProbe);
if (style) {
_processStyle(matchScore, style, rule.defaults.scopesToProbe);
}
}
if (!style && useDefault !== false) {
const tokenStyleValue = rule.defaults[this.type];
style = this.resolveTokenStyleValue(tokenStyleValue);
if (style) {
_processStyle(matchScore, style, tokenStyleValue!);
}
}
}
}
}
return TokenStyle.fromData(result);
}
@@ -212,8 +223,8 @@ export class ColorThemeData implements IWorkbenchColorTheme {
if (tokenStyleValue === undefined) {
return undefined;
} else if (typeof tokenStyleValue === 'string') {
const { type, modifiers, language } = parseClassifierString(tokenStyleValue);
return this.getTokenStyle(type, modifiers, language || '');
const { type, modifiers, language } = parseClassifierString(tokenStyleValue, '');
return this.getTokenStyle(type, modifiers, language);
} else if (typeof tokenStyleValue === 'object') {
return tokenStyleValue;
}
@@ -248,8 +259,8 @@ export class ColorThemeData implements IWorkbenchColorTheme {
}
public getTokenStyleMetadata(typeWithLanguage: string, modifiers: string[], defaultLanguage: string, useDefault = true, definitions: TokenStyleDefinitions = {}): ITokenStyle | undefined {
const { type, language } = parseClassifierString(typeWithLanguage);
let style = this.getTokenStyle(type, modifiers, language || defaultLanguage, useDefault, definitions);
const { type, language } = parseClassifierString(typeWithLanguage, defaultLanguage);
let style = this.getTokenStyle(type, modifiers, language, useDefault, definitions);
if (!style) {
return undefined;
}

View File

@@ -78,11 +78,10 @@ const colorCustomizationsSchema: IConfigurationPropertySchema = {
}
}]
};
const fileIconThemeSettingSchema: IConfigurationPropertySchema = {
type: ['string', 'null'],
default: DEFAULT_FILE_ICON_THEME_SETTING_VALUE,
description: nls.localize('iconTheme', "Specifies the icon theme used in the workbench or 'null' to not show any file icons."),
description: nls.localize('iconTheme', "Specifies the file icon theme used in the workbench or 'null' to not show any file icons."),
enum: [null],
enumDescriptions: [nls.localize('noIconThemeDesc', 'No file icons')],
errorMessage: nls.localize('iconThemeError', "File icon theme is unknown or not installed.")
@@ -106,7 +105,7 @@ const themeSettingsConfiguration: IConfigurationNode = {
[ThemeSettings.PREFERRED_LIGHT_THEME]: preferredLightThemeSettingSchema,
[ThemeSettings.PREFERRED_HC_THEME]: preferredHCThemeSettingSchema,
[ThemeSettings.DETECT_COLOR_SCHEME]: detectColorSchemeSettingSchema,
[ThemeSettings.ICON_THEME]: fileIconThemeSettingSchema,
[ThemeSettings.FILE_ICON_THEME]: fileIconThemeSettingSchema,
[ThemeSettings.COLOR_CUSTOMIZATIONS]: colorCustomizationsSchema,
[ThemeSettings.PRODUCT_ICON_THEME]: productIconThemeSettingSchema
}
@@ -212,7 +211,7 @@ export class ThemeConfiguration {
}
public get fileIconTheme(): string | null {
return this.configurationService.getValue<string | null>(ThemeSettings.ICON_THEME);
return this.configurationService.getValue<string | null>(ThemeSettings.FILE_ICON_THEME);
}
public get productIconTheme(): string {
@@ -237,7 +236,7 @@ export class ThemeConfiguration {
}
public async setFileIconTheme(theme: IWorkbenchFileIconTheme, settingsTarget: ConfigurationTarget | undefined | 'auto'): Promise<IWorkbenchFileIconTheme> {
await this.writeConfiguration(ThemeSettings.ICON_THEME, theme.settingsId, settingsTarget);
await this.writeConfiguration(ThemeSettings.FILE_ICON_THEME, theme.settingsId, settingsTarget);
return theme;
}
@@ -257,6 +256,8 @@ export class ThemeConfiguration {
settingsTarget = ConfigurationTarget.WORKSPACE_FOLDER;
} else if (!types.isUndefined(settings.workspaceValue)) {
settingsTarget = ConfigurationTarget.WORKSPACE;
} else if (!types.isUndefined(settings.userRemote)) {
settingsTarget = ConfigurationTarget.USER_REMOTE;
} else {
settingsTarget = ConfigurationTarget.USER;
}
@@ -271,12 +272,11 @@ export class ThemeConfiguration {
}
value = undefined; // remove configuration from user settings
}
} else if (settingsTarget === ConfigurationTarget.WORKSPACE || settingsTarget === ConfigurationTarget.WORKSPACE_FOLDER) {
} else if (settingsTarget === ConfigurationTarget.WORKSPACE || settingsTarget === ConfigurationTarget.WORKSPACE_FOLDER || settingsTarget === ConfigurationTarget.USER_REMOTE) {
if (value === settings.value) {
return Promise.resolve(undefined); // nothing to do
}
}
return this.configurationService.updateValue(key, value, settingsTarget);
}
}

View File

@@ -10,7 +10,7 @@ import * as resources from 'vs/base/common/resources';
import { ExtensionMessageCollector, IExtensionPoint, ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { ExtensionData, IThemeExtensionPoint, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionService, checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
import { Event, Emitter } from 'vs/base/common/event';
import { URI } from 'vs/base/common/uri';
@@ -128,7 +128,8 @@ export class ThemeRegistry<T extends IThemeData> {
private readonly themesExtPoint: IExtensionPoint<IThemeExtensionPoint[]>,
private create: (theme: IThemeExtensionPoint, themeLocation: URI, extensionData: ExtensionData) => T,
private idRequired = false,
private builtInTheme: T | undefined = undefined
private builtInTheme: T | undefined = undefined,
private isProposedApi = false
) {
this.extensionThemes = [];
this.initialize();
@@ -144,6 +145,10 @@ export class ThemeRegistry<T extends IThemeData> {
}
this.extensionThemes.length = 0;
for (let ext of extensions) {
if (this.isProposedApi) {
checkProposedApiEnabled(ext.description);
return;
}
let extensionData: ExtensionData = {
extensionId: ext.description.identifier.value,
extensionPublisher: ext.description.publisher,

View File

@@ -5,8 +5,7 @@
import * as nls from 'vs/nls';
import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { getTokenClassificationRegistry, ITokenClassificationRegistry, typeAndModifierIdPattern, TokenStyleDefaults, TokenStyle, fontStylePattern, selectorPattern } from 'vs/platform/theme/common/tokenClassificationRegistry';
import { textmateColorSettingsSchemaId } from 'vs/workbench/services/themes/common/colorThemeSchema';
import { getTokenClassificationRegistry, ITokenClassificationRegistry, typeAndModifierIdPattern } from 'vs/platform/theme/common/tokenClassificationRegistry';
interface ITokenTypeExtensionPoint {
id: string;
@@ -20,24 +19,10 @@ interface ITokenModifierExtensionPoint {
}
interface ITokenStyleDefaultExtensionPoint {
selector: string;
scope?: string[];
light?: {
foreground?: string;
fontStyle?: string;
};
dark?: {
foreground?: string;
fontStyle?: string;
};
highContrast?: {
foreground?: string;
fontStyle?: string;
};
language?: string;
scopes: { [selector: string]: string[] };
}
const colorPattern = '^#([0-9A-Fa-f]{6})([0-9A-Fa-f]{2})?$';
const tokenClassificationRegistry: ITokenClassificationRegistry = getTokenClassificationRegistry();
const tokenTypeExtPoint = ExtensionsRegistry.registerExtensionPoint<ITokenTypeExtensionPoint[]>({
@@ -54,6 +39,12 @@ const tokenTypeExtPoint = ExtensionsRegistry.registerExtensionPoint<ITokenTypeEx
pattern: typeAndModifierIdPattern,
patternErrorMessage: nls.localize('contributes.semanticTokenTypes.id.format', 'Identifiers should be in the form letterOrDigit[_-letterOrDigit]*'),
},
superType: {
type: 'string',
description: nls.localize('contributes.semanticTokenTypes.superType', 'The super type of the semantic token type'),
pattern: typeAndModifierIdPattern,
patternErrorMessage: nls.localize('contributes.semanticTokenTypes.superType.format', 'Super types should be in the form letterOrDigit[_-letterOrDigit]*'),
},
description: {
type: 'string',
description: nls.localize('contributes.color.description', 'The description of the semantic token type'),
@@ -86,37 +77,26 @@ const tokenModifierExtPoint = ExtensionsRegistry.registerExtensionPoint<ITokenMo
});
const tokenStyleDefaultsExtPoint = ExtensionsRegistry.registerExtensionPoint<ITokenStyleDefaultExtensionPoint[]>({
extensionPoint: 'semanticTokenStyleDefaults',
extensionPoint: 'semanticTokenScopes',
jsonSchema: {
description: nls.localize('contributes.semanticTokenStyleDefaults', 'Contributes semantic token style defaults.'),
description: nls.localize('contributes.semanticTokenScopes', 'Contributes semantic token scope maps.'),
type: 'array',
items: {
type: 'object',
properties: {
selector: {
type: 'string',
description: nls.localize('contributes.semanticTokenStyleDefaults.selector', 'The selector matching token types and modifiers.'),
pattern: selectorPattern,
patternErrorMessage: nls.localize('contributes.semanticTokenStyleDefaults.selector.format', 'Selectors should be in the form (type|*)(.modifier)*(:language)?'),
language: {
description: nls.localize('contributes.semanticTokenScopes.languages', 'Lists the languge for which the defaults are.'),
type: 'string'
},
scope: {
type: 'array',
description: nls.localize('contributes.semanticTokenStyleDefaults.scope', 'A TextMate scope against the current color theme is matched to find the style for the given selector'),
items: {
type: 'string'
scopes: {
description: nls.localize('contributes.semanticTokenScopes.scopes', 'Maps a semantic token (described by semantic token selector) to one or more textMate scopes used to represent that token.'),
type: 'object',
additionalProperties: {
type: 'array',
items: {
type: 'string'
}
}
},
light: {
description: nls.localize('contributes.semanticTokenStyleDefaults.light', 'The default style used for light themes'),
$ref: textmateColorSettingsSchemaId
},
dark: {
description: nls.localize('contributes.semanticTokenStyleDefaults.dark', 'The default style used for dark themes'),
$ref: textmateColorSettingsSchemaId
},
highContrast: {
description: nls.localize('contributes.semanticTokenStyleDefaults.hc', 'The default style used for high contrast themes'),
$ref: textmateColorSettingsSchemaId
}
}
}
@@ -147,24 +127,6 @@ export class TokenClassificationExtensionPoints {
}
return true;
}
function validateStyle(style: { foreground?: string; fontStyle?: string; } | undefined, extensionPoint: string, collector: ExtensionMessageCollector): TokenStyle | undefined {
if (!style) {
return undefined;
}
if (style.foreground) {
if (typeof style.foreground !== 'string' || !style.foreground.match(colorPattern)) {
collector.error(nls.localize('invalid.color', "'configuration.{0}.foreground' must follow the pattern #RRGGBB[AA]", extensionPoint));
return undefined;
}
}
if (style.fontStyle) {
if (typeof style.fontStyle !== 'string' || !style.fontStyle.match(fontStylePattern)) {
collector.error(nls.localize('invalid.fontStyle', "'configuration.{0}.fontStyle' must be one or a combination of \'italic\', \'bold\' or \'underline\' or the empty string", extensionPoint));
return undefined;
}
}
return TokenStyle.fromSettings(style.foreground, style.fontStyle);
}
tokenTypeExtPoint.setHandler((extensions, delta) => {
for (const extension of delta.added) {
@@ -216,49 +178,45 @@ export class TokenClassificationExtensionPoints {
const collector = extension.collector;
if (!extensionValue || !Array.isArray(extensionValue)) {
collector.error(nls.localize('invalid.semanticTokenStyleDefaultConfiguration', "'configuration.semanticTokenStyleDefaults' must be an array"));
collector.error(nls.localize('invalid.semanticTokenScopes.configuration', "'configuration.semanticTokenScopes' must be an array"));
return;
}
for (const contribution of extensionValue) {
if (typeof contribution.selector !== 'string' || contribution.selector.length === 0) {
collector.error(nls.localize('invalid.selector', "'configuration.semanticTokenStyleDefaults.selector' must be defined and can not be empty"));
if (contribution.language && typeof contribution.language !== 'string') {
collector.error(nls.localize('invalid.semanticTokenScopes.language', "'configuration.semanticTokenScopes.language' must be a string"));
continue;
}
if (!contribution.selector.match(selectorPattern)) {
collector.error(nls.localize('invalid.selector.format', "'configuration.semanticTokenStyleDefaults.selector' must be in the form (type|*)(.modifier)*(:language)?"));
if (!contribution.scopes || typeof contribution.scopes !== 'object') {
collector.error(nls.localize('invalid.semanticTokenScopes.scopes', "'configuration.semanticTokenScopes.scopes' must be defined as an object"));
continue;
}
const tokenStyleDefault: TokenStyleDefaults = {};
if (contribution.scope) {
if ((!Array.isArray(contribution.scope) || contribution.scope.some(s => typeof s !== 'string'))) {
collector.error(nls.localize('invalid.scope', "If defined, 'configuration.semanticTokenStyleDefaults.scope' must be an array of strings"));
for (let selectorString in contribution.scopes) {
const tmScopes = contribution.scopes[selectorString];
if (!Array.isArray(tmScopes) || tmScopes.some(l => typeof l !== 'string')) {
collector.error(nls.localize('invalid.semanticTokenScopes.scopes.value', "'configuration.semanticTokenScopes.scopes' values must be an array of strings"));
continue;
}
tokenStyleDefault.scopesToProbe = [contribution.scope];
}
tokenStyleDefault.light = validateStyle(contribution.light, 'semanticTokenStyleDefaults.light', collector);
tokenStyleDefault.dark = validateStyle(contribution.dark, 'semanticTokenStyleDefaults.dark', collector);
tokenStyleDefault.hc = validateStyle(contribution.highContrast, 'semanticTokenStyleDefaults.highContrast', collector);
try {
const selector = tokenClassificationRegistry.parseTokenSelector(contribution.selector);
tokenClassificationRegistry.registerTokenStyleDefault(selector, tokenStyleDefault);
} catch (e) {
collector.error(nls.localize('invalid.selector.parsing', "configuration.semanticTokenStyleDefaults.selector': Problems parsing {0}.", contribution.selector));
// invalid selector, ignore
try {
const selector = tokenClassificationRegistry.parseTokenSelector(selectorString, contribution.language);
tokenClassificationRegistry.registerTokenStyleDefault(selector, { scopesToProbe: tmScopes.map(s => s.split(' ')) });
} catch (e) {
collector.error(nls.localize('invalid.semanticTokenScopes.scopes.selector', "configuration.semanticTokenScopes.scopes': Problems parsing selector {0}.", selectorString));
// invalid selector, ignore
}
}
}
}
for (const extension of delta.removed) {
const extensionValue = <ITokenStyleDefaultExtensionPoint[]>extension.value;
for (const contribution of extensionValue) {
try {
const selector = tokenClassificationRegistry.parseTokenSelector(contribution.selector);
tokenClassificationRegistry.deregisterTokenStyleDefault(selector);
} catch (e) {
// invalid selector, ignore
for (let selectorString in contribution.scopes) {
const tmScopes = contribution.scopes[selectorString];
try {
const selector = tokenClassificationRegistry.parseTokenSelector(selectorString, contribution.language);
tokenClassificationRegistry.registerTokenStyleDefault(selector, { scopesToProbe: tmScopes.map(s => s.split(' ')) });
} catch (e) {
// invalid selector, ignore
}
}
}
}

View File

@@ -20,7 +20,8 @@ export const HC_THEME_ID = 'Default High Contrast';
export enum ThemeSettings {
COLOR_THEME = 'workbench.colorTheme',
ICON_THEME = 'workbench.iconTheme',
FILE_ICON_THEME = 'workbench.iconTheme',
PRODUCT_ICON_THEME = 'workbench.productIconTheme',
COLOR_CUSTOMIZATIONS = 'workbench.colorCustomizations',
TOKEN_COLOR_CUSTOMIZATIONS = 'editor.tokenColorCustomizations',
TOKEN_COLOR_CUSTOMIZATIONS_EXPERIMENTAL = 'editor.tokenColorCustomizationsExperimental',
@@ -29,18 +30,19 @@ export enum ThemeSettings {
PREFERRED_LIGHT_THEME = 'workbench.preferredLightColorTheme',
PREFERRED_HC_THEME = 'workbench.preferredHighContrastColorTheme',
DETECT_COLOR_SCHEME = 'window.autoDetectColorScheme',
DETECT_HC = 'window.autoDetectHighContrast',
PRODUCT_ICON_THEME = 'workbench.productIconTheme'
DETECT_HC = 'window.autoDetectHighContrast'
}
export interface IWorkbenchColorTheme extends IColorTheme {
export interface IWorkbenchTheme {
readonly id: string;
readonly label: string;
readonly settingsId: string;
readonly extensionData?: ExtensionData;
readonly description?: string;
readonly isLoaded: boolean;
readonly settingsId: string | null;
}
export interface IWorkbenchColorTheme extends IWorkbenchTheme, IColorTheme {
readonly settingsId: string;
readonly tokenColors: ITextMateThemingRule[];
}
@@ -48,44 +50,28 @@ export interface IColorMap {
[id: string]: Color;
}
export interface IWorkbenchFileIconTheme extends IFileIconTheme {
readonly id: string;
readonly label: string;
readonly settingsId: string | null;
readonly description?: string;
readonly extensionData?: ExtensionData;
readonly isLoaded: boolean;
readonly hasFileIcons: boolean;
readonly hasFolderIcons: boolean;
readonly hidesExplorerArrows: boolean;
export interface IWorkbenchFileIconTheme extends IWorkbenchTheme, IFileIconTheme {
}
export interface IWorkbenchProductIconTheme {
readonly id: string;
readonly label: string;
export interface IWorkbenchProductIconTheme extends IWorkbenchTheme {
readonly settingsId: string;
readonly description?: string;
readonly extensionData?: ExtensionData;
readonly isLoaded: boolean;
}
export interface IWorkbenchThemeService extends IThemeService {
_serviceBrand: undefined;
setColorTheme(themeId: string | undefined, settingsTarget: ConfigurationTarget | undefined): Promise<IWorkbenchColorTheme | null>;
setColorTheme(themeId: string | undefined, settingsTarget: ConfigurationTarget | undefined | 'auto'): Promise<IWorkbenchColorTheme | null>;
getColorTheme(): IWorkbenchColorTheme;
getColorThemes(): Promise<IWorkbenchColorTheme[]>;
onDidColorThemeChange: Event<IWorkbenchColorTheme>;
restoreColorTheme(): void;
setFileIconTheme(iconThemeId: string | undefined, settingsTarget: ConfigurationTarget | undefined): Promise<IWorkbenchFileIconTheme>;
setFileIconTheme(iconThemeId: string | undefined, settingsTarget: ConfigurationTarget | undefined | 'auto'): Promise<IWorkbenchFileIconTheme>;
getFileIconTheme(): IWorkbenchFileIconTheme;
getFileIconThemes(): Promise<IWorkbenchFileIconTheme[]>;
onDidFileIconThemeChange: Event<IWorkbenchFileIconTheme>;
setProductIconTheme(iconThemeId: string | undefined, settingsTarget: ConfigurationTarget | undefined): Promise<IWorkbenchProductIconTheme>;
setProductIconTheme(iconThemeId: string | undefined, settingsTarget: ConfigurationTarget | undefined | 'auto'): Promise<IWorkbenchProductIconTheme>;
getProductIconTheme(): IWorkbenchProductIconTheme;
getProductIconThemes(): Promise<IWorkbenchProductIconTheme[]>;
onDidProductIconThemeChange: Event<IWorkbenchProductIconTheme>;

View File

@@ -398,8 +398,11 @@ suite('Themes - TokenStyleResolving', () => {
test('language - scope resolving', async () => {
const registry = getTokenClassificationRegistry();
registry.registerTokenStyleDefault(registry.parseTokenSelector('type:typescript'), { scopesToProbe: [['entity.name.type.ts']] });
const numberOfDefaultRules = registry.getTokenStylingDefaultRules().length;
registry.registerTokenStyleDefault(registry.parseTokenSelector('type', 'typescript1'), { scopesToProbe: [['entity.name.type.ts1']] });
registry.registerTokenStyleDefault(registry.parseTokenSelector('type:javascript1'), { scopesToProbe: [['entity.name.type.js1']] });
try {
const themeData = ColorThemeData.createLoadedEmptyTheme('test', 'test');
@@ -411,17 +414,20 @@ suite('Themes - TokenStyleResolving', () => {
settings: { foreground: '#aa0000' }
},
{
scope: 'entity.name.type.ts',
scope: 'entity.name.type.ts1',
settings: { foreground: '#bb0000' }
}
]
});
assertTokenStyles(themeData, { 'type': ts('#aa0000', undefined) }, 'javascript');
assertTokenStyles(themeData, { 'type': ts('#bb0000', undefined) }, 'typescript');
assertTokenStyles(themeData, { 'type': ts('#aa0000', undefined) }, 'javascript1');
assertTokenStyles(themeData, { 'type': ts('#bb0000', undefined) }, 'typescript1');
} finally {
registry.deregisterTokenType('type/typescript');
registry.deregisterTokenStyleDefault(registry.parseTokenSelector('type', 'typescript1'));
registry.deregisterTokenStyleDefault(registry.parseTokenSelector('type:javascript1'));
assert.equal(registry.getTokenStylingDefaultRules().length, numberOfDefaultRules);
}
});
});

View File

@@ -15,6 +15,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { Event, Emitter } from 'vs/base/common/event';
import { firstIndex } from 'vs/base/common/arrays';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
class CounterSet<T> implements IReadableSet<T> {
@@ -219,7 +220,8 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IStorageService private readonly storageService: IStorageService,
@IExtensionService private readonly extensionService: IExtensionService,
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService,
) {
super();
@@ -452,6 +454,43 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
if (!skipCacheUpdate) {
this.saveViewPositionsToCache();
const containerToString = (container: ViewContainer): string => {
if (container.id.startsWith(ViewDescriptorService.COMMON_CONTAINER_ID_PREFIX)) {
return 'custom';
}
if (!container.extensionId) {
return container.id;
}
return 'extension';
};
// Log on cache update to avoid duplicate events in other windows
const viewCount = views.length;
const fromContainer = containerToString(from);
const toContainer = containerToString(to);
const fromLocation = oldLocation === ViewContainerLocation.Panel ? 'panel' : 'sidebar';
const toLocation = newLocation === ViewContainerLocation.Panel ? 'panel' : 'sidebar';
interface ViewDescriptorServiceMoveViewsEvent {
viewCount: number;
fromContainer: string;
toContainer: string;
fromLocation: string;
toLocation: string;
}
type ViewDescriptorServiceMoveViewsClassification = {
viewCount: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
fromContainer: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
toContainer: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
fromLocation: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
toLocation: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
};
this.telemetryService.publicLog2<ViewDescriptorServiceMoveViewsEvent, ViewDescriptorServiceMoveViewsClassification>('viewDescriptorService.moveViews', { viewCount, fromContainer, toContainer, fromLocation, toLocation });
}
}

View File

@@ -13,6 +13,7 @@ import { IWorkingCopyFileOperationParticipant } from 'vs/workbench/services/work
import { URI } from 'vs/base/common/uri';
import { FileOperation } from 'vs/platform/files/common/files';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { insert } from 'vs/base/common/arrays';
export class WorkingCopyFileOperationParticipant extends Disposable {
@@ -27,9 +28,9 @@ export class WorkingCopyFileOperationParticipant extends Disposable {
}
addFileOperationParticipant(participant: IWorkingCopyFileOperationParticipant): IDisposable {
this.participants.push(participant);
const remove = insert(this.participants, participant);
return toDisposable(() => this.participants.splice(this.participants.indexOf(participant), 1));
return toDisposable(() => remove());
}
async participate(target: URI, source: URI | undefined, operation: FileOperation): Promise<void> {

View File

@@ -8,7 +8,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { Event, Emitter } from 'vs/base/common/event';
import { URI } from 'vs/base/common/uri';
import { Disposable, IDisposable, toDisposable, DisposableStore, dispose } from 'vs/base/common/lifecycle';
import { values, ResourceMap } from 'vs/base/common/map';
import { ResourceMap } from 'vs/base/common/map';
import { ISaveOptions, IRevertOptions } from 'vs/workbench/common/editor';
import { ITextSnapshot } from 'vs/editor/common/model';
import { Schemas } from 'vs/base/common/network'; // {{SQL CARBON EDIT}} @chlafreniere need to block working copies of notebook editors from being tracked
@@ -185,7 +185,7 @@ export class WorkingCopyService extends Disposable implements IWorkingCopyServic
//#region Registry
get workingCopies(): IWorkingCopy[] { return values(this._workingCopies); }
get workingCopies(): IWorkingCopy[] { return Array.from(this._workingCopies.values()); }
private _workingCopies = new Set<IWorkingCopy>();
private readonly mapResourceToWorkingCopy = new ResourceMap<IWorkingCopy>();

View File

@@ -8,7 +8,7 @@ import { URI } from 'vs/base/common/uri';
import * as nls from 'vs/nls';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IJSONEditingService, JSONEditingError, JSONEditingErrorCode } from 'vs/workbench/services/configuration/common/jsonEditing';
import { IWorkspaceIdentifier, IWorkspaceFolderCreationData, IWorkspacesService, rewriteWorkspaceFileForNewLocation, WORKSPACE_FILTER, IEnterWorkspaceResult, hasWorkspaceFileExtension, WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces';
import { IWorkspaceIdentifier, IWorkspaceFolderCreationData, IWorkspacesService, rewriteWorkspaceFileForNewLocation, WORKSPACE_FILTER, IEnterWorkspaceResult, hasWorkspaceFileExtension, WORKSPACE_EXTENSION, isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces';
import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService';
import { ConfigurationScope, IConfigurationRegistry, Extensions as ConfigurationExtensions, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
@@ -234,9 +234,11 @@ export abstract class AbstractWorkspaceEditingService implements IWorkspaceEditi
return;
}
const isFromUntitledWorkspace = isUntitledWorkspace(configPathURI, this.environmentService);
// Read the contents of the workspace file, update it to new location and save it.
const raw = await this.fileService.readFile(configPathURI);
const newRawWorkspaceContents = rewriteWorkspaceFileForNewLocation(raw.value.toString(), configPathURI, targetConfigPathURI);
const newRawWorkspaceContents = rewriteWorkspaceFileForNewLocation(raw.value.toString(), configPathURI, isFromUntitledWorkspace, targetConfigPathURI);
await this.textFileService.create(targetConfigPathURI, newRawWorkspaceContents, { overwrite: true });
}

View File

@@ -139,7 +139,7 @@ export class BrowserWorkspacesService extends Disposable implements IWorkspacesS
const storedWorkspaceFolder: IStoredWorkspaceFolder[] = [];
if (folders) {
for (const folder of folders) {
storedWorkspaceFolder.push(getStoredWorkspaceFolder(folder.uri, folder.name, this.environmentService.untitledWorkspacesHome));
storedWorkspaceFolder.push(getStoredWorkspaceFolder(folder.uri, true, folder.name, this.environmentService.untitledWorkspacesHome));
}
}
@@ -165,6 +165,15 @@ export class BrowserWorkspacesService extends Disposable implements IWorkspacesS
}
//#endregion
//#region Dirty Workspaces
async getDirtyWorkspaces(): Promise<Array<IWorkspaceIdentifier | URI>> {
return []; // Currently not supported in web
}
//#endregion
}
registerSingleton(IWorkspacesService, BrowserWorkspacesService, true);

View File

@@ -140,8 +140,6 @@ export class NativeWorkspaceEditingService extends AbstractWorkspaceEditingServi
return false;
}
}
return false;
}
async isValidTargetWorkspacePath(path: URI): Promise<boolean> {