diff --git a/src/vs/workbench/api/common/configurationExtensionPoint.ts b/src/vs/workbench/api/common/configurationExtensionPoint.ts index 57fa4cef735..496651fe769 100644 --- a/src/vs/workbench/api/common/configurationExtensionPoint.ts +++ b/src/vs/workbench/api/common/configurationExtensionPoint.ts @@ -415,9 +415,9 @@ class SettingsTableRenderer extends Disposable implements IExtensionFeatureTable const rows: IRowData[][] = contrib.sort((a, b) => a.localeCompare(b)) .map(key => { return [ - { data: key, type: 'code' }, + new MarkdownString().appendMarkdown(`\`${key}\``), properties[key].markdownDescription ? new MarkdownString(properties[key].markdownDescription, false) : properties[key].description ?? '', - { data: `${isUndefined(properties[key].default) ? getDefaultValue(properties[key].type) : JSON.stringify(properties[key].default)}`, type: 'code' } + new MarkdownString().appendCodeblock('json', JSON.stringify(isUndefined(properties[key].default) ? getDefaultValue(properties[key].type) : properties[key].default, null, 2)), ]; }); diff --git a/src/vs/workbench/api/common/jsonValidationExtensionPoint.ts b/src/vs/workbench/api/common/jsonValidationExtensionPoint.ts index 94a2f00ff58..1b82d305f19 100644 --- a/src/vs/workbench/api/common/jsonValidationExtensionPoint.ts +++ b/src/vs/workbench/api/common/jsonValidationExtensionPoint.ts @@ -12,6 +12,7 @@ import { Extensions, IExtensionFeatureTableRenderer, IExtensionFeaturesRegistry, import { IExtensionManifest } from 'vs/platform/extensions/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { MarkdownString } from 'vs/base/common/htmlContent'; interface IJSONValidationExtensionPoint { fileMatch: string | string[]; @@ -109,7 +110,7 @@ class JSONValidationDataRenderer extends Disposable implements IExtensionFeature const rows: IRowData[][] = contrib.map(v => { return [ - { data: Array.isArray(v.fileMatch) ? v.fileMatch.join(', ') : v.fileMatch, type: 'code' }, + new MarkdownString().appendMarkdown(`\`${Array.isArray(v.fileMatch) ? v.fileMatch.join(', ') : v.fileMatch}\``), v.url, ]; }); diff --git a/src/vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint.ts b/src/vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint.ts index 4e119df579a..d8581f7d67c 100644 --- a/src/vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint.ts +++ b/src/vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint.ts @@ -11,6 +11,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IExtensionManifest } from 'vs/platform/extensions/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; +import { MarkdownString } from 'vs/base/common/htmlContent'; enum CodeActionExtensionPointFields { languages = 'languages', @@ -100,9 +101,9 @@ class CodeActionsTableRenderer extends Disposable implements IExtensionFeatureTa .map(action => { return [ action.title, - { data: action.kind, type: 'code' }, + new MarkdownString().appendMarkdown(`\`${action.kind}\``), action.description ?? '', - { data: [...action.languages], type: 'code' }, + new MarkdownString().appendMarkdown(`${action.languages.map(lang => `\`${lang}\``).join(' ')}`), ]; }); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionFeaturesTab.ts b/src/vs/workbench/contrib/extensions/browser/extensionFeaturesTab.ts index a778ba34bdb..d09f329de49 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionFeaturesTab.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionFeaturesTab.ts @@ -29,7 +29,6 @@ import { ThemeIcon } from 'vs/base/common/themables'; import Severity from 'vs/base/common/severity'; import { errorIcon, infoIcon, warningIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons'; import { SeverityIcon } from 'vs/platform/severityIcon/browser/severityIcon'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel'; import { OS } from 'vs/base/common/platform'; import { IMarkdownString, MarkdownString, isMarkdownString } from 'vs/base/common/htmlContent'; @@ -38,6 +37,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { Codicon } from 'vs/base/common/codicons'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { fromNow } from 'vs/base/common/date'; +import { ResolvedKeybinding } from 'vs/base/common/keybindings'; class RuntimeStatusMarkdownRenderer extends Disposable implements IExtensionFeatureMarkdownRenderer { @@ -372,7 +372,6 @@ class ExtensionFeatureView extends Disposable { @IInstantiationService private readonly instantiationService: IInstantiationService, @IExtensionFeaturesManagementService private readonly extensionFeaturesManagementService: IExtensionFeaturesManagementService, @IDialogService private readonly dialogService: IDialogService, - @IKeybindingService private readonly keybindingService: IKeybindingService, ) { super(); @@ -470,36 +469,24 @@ class ExtensionFeatureView extends Disposable { if (typeof rowData === 'string') { return $('td', undefined, rowData); } - if (isMarkdownString(rowData)) { - const element = $('td', undefined); - this.renderMarkdown(rowData, element); - return element; - } - const data = Array.isArray(rowData.data) ? rowData.data : [rowData.data]; - if (rowData.type === 'code') { - return $('td', undefined, ...data.map(c => $('code', undefined, c))); - } else if (rowData.type === 'keybinding') { - return $('td', undefined, ...data.map(keybinding => { + const data = Array.isArray(rowData) ? rowData : [rowData]; + return $('td', undefined, ...data.map(item => { + const result: Node[] = []; + if (isMarkdownString(rowData)) { + const element = $('td', undefined); + this.renderMarkdown(rowData, element); + result.push(element); + } else if (item instanceof ResolvedKeybinding) { const element = $(''); const kbl = new KeybindingLabel(element, OS, defaultKeybindingLabelStyles); - kbl.set(this.keybindingService.resolveUserBinding(keybinding)[0]); - return element; - })); - } else if (rowData.type === 'color') { - return $('td', undefined, ...data.map(colorReference => { - const result: Node[] = []; - if (colorReference && colorReference[0] === '#') { - const color = Color.fromHex(colorReference); - if (color) { - result.push($('span', { class: 'colorBox', style: 'background-color: ' + Color.Format.CSS.format(color) }, '')); - } - } - result.push($('code', undefined, colorReference)); - return result; - }).flat()); - } else { - return $('td', undefined, rowData.data[0]); - } + kbl.set(item); + result.push(element); + } else if (item instanceof Color) { + result.push($('span', { class: 'colorBox', style: 'background-color: ' + Color.Format.CSS.format(item) }, '')); + result.push($('code', undefined, Color.Format.CSS.formatHex(item))); + } + return result; + }).flat()); }) ); }))); diff --git a/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css b/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css index 93b10e5bb6e..4243f5ebd44 100644 --- a/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css +++ b/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css @@ -874,11 +874,6 @@ align-items: center; } -.extension-editor .subcontent.feature-contributions .extension-feature-content .feature-body .feature-body-content pre { - white-space: pre-wrap; - word-wrap: break-word; -} - .extension-editor .subcontent.feature-contributions .extension-feature-content .feature-body .feature-body-content .feature-content.markdown .codicon { vertical-align: sub; } diff --git a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts index 981c5a0ed62..a81d30aee5e 100644 --- a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts +++ b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts @@ -22,6 +22,9 @@ import { IExtensionManifest, IKeyBinding } from 'vs/platform/extensions/common/e import { Registry } from 'vs/platform/registry/common/platform'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { platform } from 'vs/base/common/process'; +import { MarkdownString } from 'vs/base/common/htmlContent'; +import { ResolvedKeybinding } from 'vs/base/common/keybindings'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; interface IAPIMenu { readonly key: string; @@ -996,6 +999,10 @@ class CommandsTableRenderer extends Disposable implements IExtensionFeatureTable readonly type = 'table'; + constructor( + @IKeybindingService private readonly _keybindingService: IKeybindingService + ) { super(); } + shouldRender(manifest: IExtensionManifest): boolean { return !!manifest.contributes?.commands; } @@ -1005,7 +1012,7 @@ class CommandsTableRenderer extends Disposable implements IExtensionFeatureTable const commands = rawCommands.map(c => ({ id: c.command, title: c.title, - keybindings: [] as string[], + keybindings: [] as ResolvedKeybinding[], menus: [] as string[] })); @@ -1062,10 +1069,10 @@ class CommandsTableRenderer extends Disposable implements IExtensionFeatureTable const rows: IRowData[][] = commands.sort((a, b) => a.id.localeCompare(b.id)) .map(command => { return [ - { data: command.id, type: 'code' }, + new MarkdownString().appendMarkdown(`\`${command.id}\``), typeof command.title === 'string' ? command.title : command.title.value, - { data: command.keybindings, type: 'keybinding' }, - { data: command.menus, type: 'code' }, + command.keybindings, + new MarkdownString().appendMarkdown(`${command.menus.map(menu => `\`${menu}\``).join(' ')}`), ]; }); @@ -1078,7 +1085,7 @@ class CommandsTableRenderer extends Disposable implements IExtensionFeatureTable }; } - private resolveKeybinding(rawKeyBinding: IKeyBinding): string | undefined { + private resolveKeybinding(rawKeyBinding: IKeyBinding): ResolvedKeybinding | undefined { let key: string | undefined; switch (platform) { @@ -1087,7 +1094,7 @@ class CommandsTableRenderer extends Disposable implements IExtensionFeatureTable case 'darwin': key = rawKeyBinding.mac; break; } - return key ?? rawKeyBinding.key; + return this._keybindingService.resolveUserBinding(key ?? rawKeyBinding.key)[0]; } } diff --git a/src/vs/workbench/services/extensionManagement/common/extensionFeatures.ts b/src/vs/workbench/services/extensionManagement/common/extensionFeatures.ts index e72d5eee735..2e02427e40f 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionFeatures.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionFeatures.ts @@ -12,6 +12,8 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import Severity from 'vs/base/common/severity'; import { IStringDictionary } from 'vs/base/common/collections'; +import { ResolvedKeybinding } from 'vs/base/common/keybindings'; +import { Color } from 'vs/base/common/color'; export namespace Extensions { export const ExtensionFeaturesRegistry = 'workbench.registry.extensionFeatures'; @@ -33,7 +35,7 @@ export interface IExtensionFeatureMarkdownRenderer extends IExtensionFeatureRend render(manifest: IExtensionManifest): IRenderedData; } -export type IRowData = string | IMarkdownString | { readonly data: string | string[]; readonly type: 'code' | 'keybinding' | 'color' }; +export type IRowData = string | IMarkdownString | ResolvedKeybinding | Color | ReadonlyArray; export interface ITableData { headers: string[]; diff --git a/src/vs/workbench/services/language/common/languageService.ts b/src/vs/workbench/services/language/common/languageService.ts index c7e93a09c44..c788168597a 100644 --- a/src/vs/workbench/services/language/common/languageService.ts +++ b/src/vs/workbench/services/language/common/languageService.ts @@ -22,6 +22,7 @@ import { Extensions, IExtensionFeatureTableRenderer, IExtensionFeaturesRegistry, import { Registry } from 'vs/platform/registry/common/platform'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { index } from 'vs/base/common/arrays'; +import { MarkdownString } from 'vs/base/common/htmlContent'; export interface IRawLanguageExtensionPoint { id: string; @@ -181,7 +182,7 @@ class LanguageTableRenderer extends Disposable implements IExtensionFeatureTable .map(l => { return [ l.id, l.name, - { data: l.extensions, type: 'code' }, + new MarkdownString().appendMarkdown(`${l.extensions.map(e => `\`${e}\``).join(' ')}`), l.hasGrammar ? '✔︎' : '\u2014', l.hasSnippets ? '✔︎' : '\u2014' ]; diff --git a/src/vs/workbench/services/themes/common/colorExtensionPoint.ts b/src/vs/workbench/services/themes/common/colorExtensionPoint.ts index 30f8cd24987..9a7bf4aa503 100644 --- a/src/vs/workbench/services/themes/common/colorExtensionPoint.ts +++ b/src/vs/workbench/services/themes/common/colorExtensionPoint.ts @@ -12,6 +12,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { Extensions, IExtensionFeatureTableRenderer, IExtensionFeaturesRegistry, IRenderedData, IRowData, ITableData } from 'vs/workbench/services/extensionManagement/common/extensionFeatures'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IExtensionManifest } from 'vs/platform/extensions/common/extensions'; +import { MarkdownString } from 'vs/base/common/htmlContent'; interface IColorExtensionPoint { id: string; @@ -175,14 +176,17 @@ class ColorDataRenderer extends Disposable implements IExtensionFeatureTableRend nls.localize('defaultLight', "Light Default"), nls.localize('defaultHC', "High Contrast Default"), ]; + + const toColor = (colorReference: string): Color | undefined => colorReference[0] === '#' ? Color.fromHex(colorReference) : undefined; + const rows: IRowData[][] = colors.sort((a, b) => a.id.localeCompare(b.id)) .map(color => { return [ - { data: color.id, type: 'code' }, + new MarkdownString().appendMarkdown(`\`${color.id}\``), color.description, - { data: color.defaults.dark, type: 'color' }, - { data: color.defaults.light, type: 'color' }, - { data: color.defaults.highContrast, type: 'color' }, + toColor(color.defaults.dark) ?? new MarkdownString().appendMarkdown(`\`${color.defaults.dark}\``), + toColor(color.defaults.light) ?? new MarkdownString().appendMarkdown(`\`${color.defaults.light}\``), + toColor(color.defaults.highContrast) ?? new MarkdownString().appendMarkdown(`\`${color.defaults.highContrast}\``), ]; });