Merge from vscode 1fbacccbc900bb59ba8a8f26a4128d48a1c97842

This commit is contained in:
ADS Merger
2020-02-13 02:56:02 +00:00
parent 9af1f3b0eb
commit 73ea8b79b2
229 changed files with 3192 additions and 2103 deletions

View File

@@ -13,6 +13,10 @@ import { OVERRIDE_PROPERTY_PATTERN, ConfigurationScope, IConfigurationRegistry,
import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfigurationModel, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, removeFromValueTree, toOverrides, IConfigurationValue, ConfigurationTarget, compare, IConfigurationChangeEvent, IConfigurationChange } from 'vs/platform/configuration/common/configuration';
import { Workspace } from 'vs/platform/workspace/common/workspace';
import { Registry } from 'vs/platform/registry/common/platform';
import { Disposable } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
import { IFileService } from 'vs/platform/files/common/files';
import { dirname } from 'vs/base/common/resources';
export class ConfigurationModel implements IConfigurationModel {
@@ -335,6 +339,40 @@ export class ConfigurationModelParser {
}
}
export class UserSettings extends Disposable {
private readonly parser: ConfigurationModelParser;
protected readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
readonly onDidChange: Event<void> = this._onDidChange.event;
constructor(
private readonly userSettingsResource: URI,
private readonly scopes: ConfigurationScope[] | undefined,
private readonly fileService: IFileService
) {
super();
this.parser = new ConfigurationModelParser(this.userSettingsResource.toString(), this.scopes);
this._register(this.fileService.watch(dirname(this.userSettingsResource)));
this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.userSettingsResource))(() => this._onDidChange.fire()));
}
async loadConfiguration(): Promise<ConfigurationModel> {
try {
const content = await this.fileService.readFile(this.userSettingsResource);
this.parser.parseContent(content.value.toString() || '{}');
return this.parser.configurationModel;
} catch (e) {
return new ConfigurationModel();
}
}
reprocess(): ConfigurationModel {
this.parser.parse();
return this.parser.configurationModel;
}
}
export class Configuration {
private _workspaceConsolidatedConfiguration: ConfigurationModel | null = null;

View File

@@ -7,54 +7,39 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, isConfigurationOverrides, IConfigurationData, IConfigurationValue, IConfigurationChange } from 'vs/platform/configuration/common/configuration';
import { DefaultConfigurationModel, Configuration, ConfigurationModel, ConfigurationModelParser, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels';
import { DefaultConfigurationModel, Configuration, ConfigurationModel, ConfigurationChangeEvent, UserSettings } from 'vs/platform/configuration/common/configurationModels';
import { Event, Emitter } from 'vs/base/common/event';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { ConfigWatcher } from 'vs/base/node/config';
import { onUnexpectedError } from 'vs/base/common/errors';
import { URI } from 'vs/base/common/uri';
import { Schemas } from 'vs/base/common/network';
import { IFileService } from 'vs/platform/files/common/files';
import { RunOnceScheduler } from 'vs/base/common/async';
export class ConfigurationService extends Disposable implements IConfigurationService, IDisposable {
_serviceBrand: undefined;
private configuration: Configuration;
private userConfigModelWatcher: ConfigWatcher<ConfigurationModelParser> | undefined;
private userConfiguration: UserSettings;
private readonly reloadConfigurationScheduler: RunOnceScheduler;
private readonly _onDidChangeConfiguration: Emitter<IConfigurationChangeEvent> = this._register(new Emitter<IConfigurationChangeEvent>());
readonly onDidChangeConfiguration: Event<IConfigurationChangeEvent> = this._onDidChangeConfiguration.event;
constructor(
private readonly settingsResource: URI
private readonly settingsResource: URI,
fileService: IFileService
) {
super();
this.userConfiguration = this._register(new UserSettings(this.settingsResource, undefined, fileService));
this.configuration = new Configuration(new DefaultConfigurationModel(), new ConfigurationModel());
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reloadConfiguration(), 50));
this._register(Registry.as<IConfigurationRegistry>(Extensions.Configuration).onDidUpdateConfiguration(configurationProperties => this.onDidDefaultConfigurationChange(configurationProperties)));
this._register(this.userConfiguration.onDidChange(() => this.reloadConfigurationScheduler.schedule()));
}
initialize(): Promise<void> {
if (this.userConfigModelWatcher) {
this.userConfigModelWatcher.dispose();
}
if (this.settingsResource.scheme !== Schemas.file) {
return Promise.resolve();
}
return new Promise<void>((c, e) => {
this.userConfigModelWatcher = this._register(new ConfigWatcher(this.settingsResource.fsPath, {
changeBufferDelay: 300, onError: error => onUnexpectedError(error), defaultConfig: new ConfigurationModelParser(this.settingsResource.fsPath), parse: (content: string, parseErrors: any[]) => {
const userConfigModelParser = new ConfigurationModelParser(this.settingsResource.fsPath);
userConfigModelParser.parseContent(content);
parseErrors = [...userConfigModelParser.errors];
return userConfigModelParser;
}, initCallback: () => {
this.configuration = new Configuration(new DefaultConfigurationModel(), this.userConfigModelWatcher!.getConfig().configurationModel);
this._register(this.userConfigModelWatcher!.onDidUpdateConfiguration(() => this.onDidChangeUserConfiguration(this.userConfigModelWatcher!.getConfig().configurationModel)));
c();
}
}));
});
async initialize(): Promise<void> {
const userConfiguration = await this.userConfiguration.loadConfiguration();
this.configuration = new Configuration(new DefaultConfigurationModel(), userConfiguration);
}
getConfigurationData(): IConfigurationData {
@@ -92,14 +77,9 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
return this.configuration.keys(undefined);
}
reloadConfiguration(folder?: IWorkspaceFolder): Promise<void> {
if (this.userConfigModelWatcher) {
return new Promise<void>(c => this.userConfigModelWatcher!.reload(userConfigModelParser => {
this.onDidChangeUserConfiguration(userConfigModelParser.configurationModel);
c();
}));
}
return this.initialize();
async reloadConfiguration(): Promise<void> {
const configurationModel = await this.userConfiguration.loadConfiguration();
this.onDidChangeUserConfiguration(configurationModel);
}
private onDidChangeUserConfiguration(userConfigurationModel: ConfigurationModel): void {

View File

@@ -16,14 +16,32 @@ import { testFile } from 'vs/base/test/node/utils';
import { URI } from 'vs/base/common/uri';
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { Event } from 'vs/base/common/event';
import { NullLogService } from 'vs/platform/log/common/log';
import { FileService } from 'vs/platform/files/common/fileService';
import { IDisposable } from 'vs/base/common/lifecycle';
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
import { Schemas } from 'vs/base/common/network';
import { IFileService } from 'vs/platform/files/common/files';
suite('ConfigurationService - Node', () => {
let fileService: IFileService;
const disposables: IDisposable[] = [];
setup(() => {
const logService = new NullLogService();
fileService = new FileService(logService);
disposables.push(fileService);
const diskFileSystemProvider = new DiskFileSystemProvider(logService);
disposables.push(diskFileSystemProvider);
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
});
test('simple', async () => {
const res = await testFile('config', 'config.json');
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
const service = new ConfigurationService(URI.file(res.testFile));
const service = new ConfigurationService(URI.file(res.testFile), fileService);
await service.initialize();
const config = service.getValue<{
foo: string;
@@ -41,7 +59,7 @@ suite('ConfigurationService - Node', () => {
fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }');
const service = new ConfigurationService(URI.file(res.testFile));
const service = new ConfigurationService(URI.file(res.testFile), fileService);
await service.initialize();
const config = service.getValue<{
testworkbench: {
@@ -64,7 +82,7 @@ suite('ConfigurationService - Node', () => {
fs.writeFileSync(res.testFile, ',,,,');
const service = new ConfigurationService(URI.file(res.testFile));
const service = new ConfigurationService(URI.file(res.testFile), fileService);
await service.initialize();
const config = service.getValue<{
foo: string;
@@ -81,7 +99,7 @@ suite('ConfigurationService - Node', () => {
const newDir = path.join(parentDir, 'config', id);
const testFile = path.join(newDir, 'config.json');
const service = new ConfigurationService(URI.file(testFile));
const service = new ConfigurationService(URI.file(testFile), fileService);
await service.initialize();
const config = service.getValue<{ foo: string }>();
@@ -90,10 +108,10 @@ suite('ConfigurationService - Node', () => {
service.dispose();
});
test('trigger configuration change event', async () => {
test('trigger configuration change event when file does not exist', async () => {
const res = await testFile('config', 'config.json');
const service = new ConfigurationService(URI.file(res.testFile));
const service = new ConfigurationService(URI.file(res.testFile), fileService);
await service.initialize();
return new Promise((c, e) => {
const disposable = Event.filter(service.onDidChangeConfiguration, e => e.source === ConfigurationTarget.USER)(async (e) => {
@@ -108,12 +126,31 @@ suite('ConfigurationService - Node', () => {
});
test('trigger configuration change event when file exists', async () => {
const res = await testFile('config', 'config.json');
const service = new ConfigurationService(URI.file(res.testFile), fileService);
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
await service.initialize();
return new Promise((c, e) => {
const disposable = Event.filter(service.onDidChangeConfiguration, e => e.source === ConfigurationTarget.USER)(async (e) => {
disposable.dispose();
assert.equal(service.getValue('foo'), 'barz');
service.dispose();
await res.cleanUp();
c();
});
fs.writeFileSync(res.testFile, '{ "foo": "barz" }');
});
});
test('reloadConfiguration', async () => {
const res = await testFile('config', 'config.json');
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
const service = new ConfigurationService(URI.file(res.testFile));
const service = new ConfigurationService(URI.file(res.testFile), fileService);
await service.initialize();
let config = service.getValue<{
foo: string;
@@ -162,7 +199,7 @@ suite('ConfigurationService - Node', () => {
}
});
let serviceWithoutFile = new ConfigurationService(URI.file('__testFile'));
let serviceWithoutFile = new ConfigurationService(URI.file('__testFile'), fileService);
await serviceWithoutFile.initialize();
let setting = serviceWithoutFile.getValue<ITestSetting>();
@@ -172,7 +209,7 @@ suite('ConfigurationService - Node', () => {
return testFile('config', 'config.json').then(async res => {
fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }');
const service = new ConfigurationService(URI.file(res.testFile));
const service = new ConfigurationService(URI.file(res.testFile), fileService);
let setting = service.getValue<ITestSetting>();
@@ -205,7 +242,7 @@ suite('ConfigurationService - Node', () => {
});
const r = await testFile('config', 'config.json');
const service = new ConfigurationService(URI.file(r.testFile));
const service = new ConfigurationService(URI.file(r.testFile), fileService);
service.initialize();
let res = service.inspect('something.missing');
@@ -243,7 +280,7 @@ suite('ConfigurationService - Node', () => {
});
const r = await testFile('config', 'config.json');
const service = new ConfigurationService(URI.file(r.testFile));
const service = new ConfigurationService(URI.file(r.testFile), fileService);
service.initialize();
let res = service.inspect('lookup.service.testNullSetting');

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ipcMain as ipc, app } from 'electron';
import { ipcMain as ipc, app, BrowserWindow } from 'electron';
import { ILogService } from 'vs/platform/log/common/log';
import { IStateService } from 'vs/platform/state/node/state';
import { Event, Emitter } from 'vs/base/common/event';
@@ -12,7 +12,7 @@ import { ICodeWindow } from 'vs/platform/windows/electron-main/windows';
import { handleVetos } from 'vs/platform/lifecycle/common/lifecycle';
import { isMacintosh, isWindows } from 'vs/base/common/platform';
import { Disposable } from 'vs/base/common/lifecycle';
import { Barrier } from 'vs/base/common/async';
import { Barrier, timeout } from 'vs/base/common/async';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
export const ILifecycleMainService = createDecorator<ILifecycleMainService>('lifecycleMainService');
@@ -106,7 +106,7 @@ export interface ILifecycleMainService {
/**
* Forcefully shutdown the application. No livecycle event handlers are triggered.
*/
kill(code?: number): void;
kill(code?: number): Promise<void>;
/**
* Returns a promise that resolves when a certain lifecycle phase
@@ -550,9 +550,45 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe
this.quit().then(veto => quitVetoed = veto);
}
kill(code?: number): void {
async kill(code?: number): Promise<void> {
this.logService.trace('Lifecycle#kill()');
// The kill() method is only used in 2 situations:
// - when an instance fails to start at all
// - when extension tests run from CLI to report proper exit code
//
// From extension tests we have seen issues where calling app.exit()
// with an opened window can lead to native crashes (Linux) when webviews
// are involved. As such, we should make sure to destroy any opened
// window before calling app.exit().
//
// Note: Electron implements a similar logic here:
// https://github.com/electron/electron/blob/fe5318d753637c3903e23fc1ed1b263025887b6a/spec-main/window-helpers.ts#L5
await Promise.race([
// still do not block more than 1s
timeout(1000),
// destroy any opened window
(async () => {
for (const window of BrowserWindow.getAllWindows()) {
if (window && !window.isDestroyed()) {
let whenWindowClosed: Promise<void>;
if (window.webContents && !window.webContents.isDestroyed()) {
whenWindowClosed = new Promise(c => window.once('closed', c));
} else {
whenWindowClosed = Promise.resolve();
}
window.destroy();
await whenWindowClosed;
}
}
})()
]);
// Now exit either after 1s or all windows destroyed
app.exit(code);
}
}

View File

@@ -243,11 +243,13 @@ export class WorkbenchList<T> extends List<T> {
readonly contextKeyService: IContextKeyService;
private readonly configurationService: IConfigurationService;
private readonly themeService: IThemeService;
private listHasSelectionOrFocus: IContextKey<boolean>;
private listDoubleSelection: IContextKey<boolean>;
private listMultiSelection: IContextKey<boolean>;
private _styler: IDisposable | undefined;
private _useAltAsMultipleSelectionModifier: boolean;
constructor(
@@ -278,6 +280,7 @@ export class WorkbenchList<T> extends List<T> {
this.contextKeyService = createScopedContextKeyService(contextKeyService, this);
this.configurationService = configurationService;
this.themeService = themeService;
const listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);
listSupportsMultiSelect.set(!(options.multipleSelectionSupport === false));
@@ -292,7 +295,7 @@ export class WorkbenchList<T> extends List<T> {
this.disposables.add((listService as ListService).register(this));
if (options.overrideStyles) {
this.disposables.add(attachListStyler(this, themeService, options.overrideStyles));
this.updateStyles(options.overrideStyles);
}
this.disposables.add(this.onSelectionChange(() => {
@@ -313,6 +316,29 @@ export class WorkbenchList<T> extends List<T> {
this.registerListeners();
}
updateOptions(options: IWorkbenchListOptions<T>): void {
super.updateOptions(options);
if (options.overrideStyles) {
this.updateStyles(options.overrideStyles);
}
}
dispose(): void {
super.dispose();
if (this._styler) {
this._styler.dispose();
}
}
private updateStyles(styles: IColorMapping): void {
if (this._styler) {
this._styler.dispose();
}
this._styler = attachListStyler(this, this.themeService, styles);
}
private registerListeners(): void {
this.disposables.add(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(multiSelectModifierSettingKey)) {
@@ -738,7 +764,7 @@ export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void>
@IKeybindingService keybindingService: IKeybindingService,
@IAccessibilityService accessibilityService: IAccessibilityService
) {
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble<T, TFilterData, IWorkbenchObjectTreeOptions<T, TFilterData>>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
super(user, container, delegate, renderers, treeOptions);
this.disposables.add(disposable);
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
@@ -769,12 +795,20 @@ export class WorkbenchCompressibleObjectTree<T extends NonNullable<any>, TFilter
@IKeybindingService keybindingService: IKeybindingService,
@IAccessibilityService accessibilityService: IAccessibilityService
) {
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble<T, TFilterData, IWorkbenchCompressibleObjectTreeOptions<T, TFilterData>>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
super(user, container, delegate, renderers, treeOptions);
this.disposables.add(disposable);
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
this.disposables.add(this.internals);
}
updateOptions(options: IWorkbenchAsyncDataTreeOptions<T, TFilterData> = {}): void {
super.updateOptions(options);
if (options.overrideStyles) {
this.internals.updateStyleOverrides(options.overrideStyles);
}
}
}
export interface IWorkbenchDataTreeOptions<T, TFilterData> extends IDataTreeOptions<T, TFilterData> {
@@ -801,7 +835,7 @@ export class WorkbenchDataTree<TInput, T, TFilterData = void> extends DataTree<T
@IKeybindingService keybindingService: IKeybindingService,
@IAccessibilityService accessibilityService: IAccessibilityService
) {
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble<T, TFilterData, IWorkbenchDataTreeOptions<T, TFilterData>>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
super(user, container, delegate, renderers, dataSource, treeOptions);
this.disposables.add(disposable);
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
@@ -841,7 +875,7 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
@IKeybindingService keybindingService: IKeybindingService,
@IAccessibilityService accessibilityService: IAccessibilityService
) {
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble<T, TFilterData, IWorkbenchAsyncDataTreeOptions<T, TFilterData>>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
super(user, container, delegate, renderers, dataSource, treeOptions);
this.disposables.add(disposable);
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
@@ -882,7 +916,7 @@ export class WorkbenchCompressibleAsyncDataTree<TInput, T, TFilterData = void> e
@IKeybindingService keybindingService: IKeybindingService,
@IAccessibilityService accessibilityService: IAccessibilityService
) {
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble<T, TFilterData, IWorkbenchCompressibleAsyncDataTreeOptions<T, TFilterData>>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
super(user, container, virtualDelegate, compressionDelegate, renderers, dataSource, treeOptions);
this.disposables.add(disposable);
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);

View File

@@ -64,7 +64,7 @@ class MarkerStats implements MarkerStatistics {
this._data = undefined;
}
private _update(resources: URI[]): void {
private _update(resources: readonly URI[]): void {
if (!this._data) {
return;
}
@@ -343,7 +343,7 @@ export class MarkerService implements IMarkerService {
private static _dedupeMap: { [uri: string]: boolean };
private static _debouncer(last: URI[], event: URI[]): URI[] {
private static _debouncer(last: URI[] | undefined, event: readonly URI[]): URI[] {
if (!last) {
MarkerService._dedupeMap = Object.create(null);
last = [];

View File

@@ -0,0 +1,64 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { $ } from 'vs/base/browser/dom';
import { domEvent } from 'vs/base/browser/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { Disposable } from 'vs/base/common/lifecycle';
import { Color } from 'vs/base/common/color';
export interface ILinkDescriptor {
readonly label: string;
readonly href: string;
readonly title?: string;
}
export interface ILinkStyles {
readonly textLinkForeground?: Color;
}
export class Link extends Disposable {
readonly el: HTMLAnchorElement;
private styles: ILinkStyles = {
textLinkForeground: Color.fromHex('#006AB1')
};
constructor(
link: ILinkDescriptor,
@IOpenerService openerService: IOpenerService
) {
super();
this.el = $<HTMLAnchorElement>('a', {
tabIndex: 0,
href: link.href,
title: link.title
}, link.label);
const onClick = domEvent(this.el, 'click');
const onEnterPress = Event.chain(domEvent(this.el, 'keypress'))
.map(e => new StandardKeyboardEvent(e))
.filter(e => e.keyCode === KeyCode.Enter)
.event;
const onOpen = Event.any(onClick, onEnterPress);
this._register(onOpen(_ => openerService.open(link.href)));
this.applyStyles();
}
style(styles: ILinkStyles): void {
this.styles = styles;
this.applyStyles();
}
private applyStyles(): void {
this.el.style.color = this.styles.textLinkForeground?.toString() || '';
}
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService';
import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground, simpleCheckboxBackground, simpleCheckboxBorder, simpleCheckboxForeground, ColorValue, resolveColorValue } from 'vs/platform/theme/common/colorRegistry';
import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground, simpleCheckboxBackground, simpleCheckboxBorder, simpleCheckboxForeground, ColorValue, resolveColorValue, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Color } from 'vs/base/common/color';
import { IThemable, styleFn } from 'vs/base/common/styler';
@@ -269,6 +269,16 @@ export function attachButtonStyler(widget: IThemable, themeService: IThemeServic
} as IButtonStyleOverrides, widget);
}
export interface ILinkStyleOverrides extends IStyleOverrides {
textLinkForeground?: ColorIdentifier;
}
export function attachLinkStyler(widget: IThemable, themeService: IThemeService, style?: ILinkStyleOverrides): IDisposable {
return attachStyler(themeService, {
textLinkForeground: (style && style.textLinkForeground) || textLinkForeground,
} as ILinkStyleOverrides, widget);
}
export interface IProgressBarStyleOverrides extends IStyleOverrides {
progressBarBackground?: ColorIdentifier;
}