diff --git a/src/vs/editor/common/model/tokensStore.ts b/src/vs/editor/common/model/tokensStore.ts index f464c9a40e3..4f209036e54 100644 --- a/src/vs/editor/common/model/tokensStore.ts +++ b/src/vs/editor/common/model/tokensStore.ts @@ -1018,6 +1018,7 @@ export class TokensStore2 { ((bMetadata & MetadataConsts.SEMANTIC_USE_ITALIC) ? MetadataConsts.ITALIC_MASK : 0) | ((bMetadata & MetadataConsts.SEMANTIC_USE_BOLD) ? MetadataConsts.BOLD_MASK : 0) | ((bMetadata & MetadataConsts.SEMANTIC_USE_UNDERLINE) ? MetadataConsts.UNDERLINE_MASK : 0) + | ((bMetadata & MetadataConsts.SEMANTIC_USE_STRIKETHROUGH) ? MetadataConsts.STRIKETHROUGH_MASK : 0) | ((bMetadata & MetadataConsts.SEMANTIC_USE_FOREGROUND) ? MetadataConsts.FOREGROUND_MASK : 0) | ((bMetadata & MetadataConsts.SEMANTIC_USE_BACKGROUND) ? MetadataConsts.BACKGROUND_MASK : 0) ) >>> 0; diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 2217211ce54..0eb734a5eba 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -92,16 +92,19 @@ export const enum MetadataConsts { FOREGROUND_MASK = 0b00000000011111111100000000000000, BACKGROUND_MASK = 0b11111111100000000000000000000000, - ITALIC_MASK = 0b00000000000000000000010000000000, - BOLD_MASK = 0b00000000000000000000100000000000, - UNDERLINE_MASK = 0b00000000000000000001000000000000, - STRIKETHROUGH_MASK = 0b00000000000000000010000000000000, + ITALIC_MASK = 0b00000000000000000000010000000000, + BOLD_MASK = 0b00000000000000000000100000000000, + UNDERLINE_MASK = 0b00000000000000000001000000000000, + STRIKETHROUGH_MASK = 0b00000000000000000010000000000000, + // Semantic tokens cannot set the language id, so we can + // use the first 8 bits for control purposes SEMANTIC_USE_ITALIC = 0b00000000000000000000000000000001, SEMANTIC_USE_BOLD = 0b00000000000000000000000000000010, SEMANTIC_USE_UNDERLINE = 0b00000000000000000000000000000100, - SEMANTIC_USE_FOREGROUND = 0b00000000000000000000000000001000, - SEMANTIC_USE_BACKGROUND = 0b00000000000000000000000000010000, + SEMANTIC_USE_STRIKETHROUGH = 0b00000000000000000000000000001000, + SEMANTIC_USE_FOREGROUND = 0b00000000000000000000000000010000, + SEMANTIC_USE_BACKGROUND = 0b00000000000000000000000000100000, LANGUAGEID_OFFSET = 0, TOKEN_TYPE_OFFSET = 8, @@ -149,6 +152,9 @@ export class TokenMetadata { if (fontStyle & FontStyle.Underline) { className += ' mtku'; } + if (fontStyle & FontStyle.Strikethrough) { + className += ' mtks'; + } return className; } @@ -164,8 +170,16 @@ export class TokenMetadata { if (fontStyle & FontStyle.Bold) { result += 'font-weight: bold;'; } + let textDecoration = ''; if (fontStyle & FontStyle.Underline) { - result += 'text-decoration: underline;'; + textDecoration += ' underline'; + } + if (fontStyle & FontStyle.Strikethrough) { + textDecoration += ' line-through'; + } + if (textDecoration) { + result += `text-decoration:${textDecoration};`; + } return result; } diff --git a/src/vs/editor/common/modes/supports/tokenization.ts b/src/vs/editor/common/modes/supports/tokenization.ts index 02de8c49ec3..5c0caa937e0 100644 --- a/src/vs/editor/common/modes/supports/tokenization.ts +++ b/src/vs/editor/common/modes/supports/tokenization.ts @@ -69,6 +69,9 @@ export function parseTokenTheme(source: ITokenThemeRule[]): ParsedTokenThemeRule case 'underline': fontStyle = fontStyle | FontStyle.Underline; break; + case 'strikethrough': + fontStyle = fontStyle | FontStyle.Strikethrough; + break; } } } @@ -414,5 +417,7 @@ export function generateTokensCSSForColorMap(colorMap: readonly Color[]): string rules.push('.mtki { font-style: italic; }'); rules.push('.mtkb { font-weight: bold; }'); rules.push('.mtku { text-decoration: underline; text-underline-position: under; }'); + rules.push('.mtks { text-decoration: line-through; }'); + rules.push('.mtks.mtku { text-decoration: underline line-through; text-underline-position: under; }'); return rules.join('\n'); } diff --git a/src/vs/editor/common/services/semanticTokensProviderStyling.ts b/src/vs/editor/common/services/semanticTokensProviderStyling.ts index 186dd85c007..8d7230522de 100644 --- a/src/vs/editor/common/services/semanticTokensProviderStyling.ts +++ b/src/vs/editor/common/services/semanticTokensProviderStyling.ts @@ -70,6 +70,10 @@ export class SemanticTokensProviderStyling { const underlineBit = (tokenStyle.underline ? FontStyle.Underline : 0) << MetadataConsts.FONT_STYLE_OFFSET; metadata |= underlineBit | MetadataConsts.SEMANTIC_USE_UNDERLINE; } + if (typeof tokenStyle.strikethrough !== 'undefined') { + const strikethroughBit = (tokenStyle.strikethrough ? FontStyle.Strikethrough : 0) << MetadataConsts.FONT_STYLE_OFFSET; + metadata |= strikethroughBit | MetadataConsts.SEMANTIC_USE_STRIKETHROUGH; + } if (tokenStyle.foreground) { const foregroundBits = (tokenStyle.foreground) << MetadataConsts.FOREGROUND_OFFSET; metadata |= foregroundBits | MetadataConsts.SEMANTIC_USE_FOREGROUND; diff --git a/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts index 044107118ce..8e6213d2f42 100644 --- a/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts +++ b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts @@ -285,6 +285,9 @@ class InspectTokensWidget extends Disposable implements IContentWidget { if (fontStyle & FontStyle.Underline) { r += 'underline '; } + if (fontStyle & FontStyle.Strikethrough) { + r += 'strikethrough '; + } if (r.length === 0) { r = '---'; } diff --git a/src/vs/editor/standalone/browser/standaloneLanguages.ts b/src/vs/editor/standalone/browser/standaloneLanguages.ts index e3fb9d72557..d74e7ef43b0 100644 --- a/src/vs/editor/standalone/browser/standaloneLanguages.ts +++ b/src/vs/editor/standalone/browser/standaloneLanguages.ts @@ -250,11 +250,11 @@ export interface IEncodedLineTokens { * 3322 2222 2222 1111 1111 1100 0000 0000 * 1098 7654 3210 9876 5432 1098 7654 3210 * - ------------------------------------------- - * bbbb bbbb bfff ffff ffFF FTTT LLLL LLLL + * bbbb bbbb bfff ffff ffFF FFTT LLLL LLLL * - ------------------------------------------- * - L = EncodedLanguageId (8 bits): Use `getEncodedLanguageId` to get the encoded ID of a language. - * - T = StandardTokenType (3 bits): Other = 0, Comment = 1, String = 2, RegEx = 4. - * - F = FontStyle (3 bits): None = 0, Italic = 1, Bold = 2, Underline = 4. + * - T = StandardTokenType (2 bits): Other = 0, Comment = 1, String = 2, RegEx = 3. + * - F = FontStyle (4 bits): None = 0, Italic = 1, Bold = 2, Underline = 4, Strikethrough = 8. * - f = foreground ColorId (9 bits) * - b = background ColorId (9 bits) * - The color value for each colorId is defined in IStandaloneThemeData.customTokenColors: diff --git a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts index 565d3ee9dcc..fefbc5e44d9 100644 --- a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts +++ b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts @@ -164,7 +164,8 @@ class StandaloneTheme implements IStandaloneTheme { foreground: foreground, italic: Boolean(fontStyle & FontStyle.Italic), bold: Boolean(fontStyle & FontStyle.Bold), - underline: Boolean(fontStyle & FontStyle.Underline) + underline: Boolean(fontStyle & FontStyle.Underline), + strikethrough: Boolean(fontStyle & FontStyle.Strikethrough) }; } diff --git a/src/vs/editor/test/common/model/tokensStore.test.ts b/src/vs/editor/test/common/model/tokensStore.test.ts index f17ca9f9eae..88954388130 100644 --- a/src/vs/editor/test/common/model/tokensStore.test.ts +++ b/src/vs/editor/test/common/model/tokensStore.test.ts @@ -175,15 +175,15 @@ suite('TokensStore', () => { const model = createTextModel(' else if ($s = 08) then \'\\b\''); model.setSemanticTokens([ new MultilineTokens2(1, new SparseEncodedTokens(new Uint32Array([ - 0, 20, 24, 245768, - 0, 25, 27, 245768, - 0, 28, 29, 16392, - 0, 29, 31, 262152, - 0, 32, 33, 16392, - 0, 34, 36, 98312, - 0, 36, 37, 16392, - 0, 38, 42, 245768, - 0, 43, 47, 180232, + 0, 20, 24, 0b0111100000000010000, + 0, 25, 27, 0b0111100000000010000, + 0, 28, 29, 0b0000100000000010000, + 0, 29, 31, 0b1000000000000010000, + 0, 32, 33, 0b0000100000000010000, + 0, 34, 36, 0b0011000000000010000, + 0, 36, 37, 0b0000100000000010000, + 0, 38, 42, 0b0111100000000010000, + 0, 43, 47, 0b0101100000000010000, ]))) ], true); const lineTokens = model.getLineTokens(1); diff --git a/src/vs/editor/test/common/modes/supports/tokenization.test.ts b/src/vs/editor/test/common/modes/supports/tokenization.test.ts index 435ba7787a6..2b631a8caf6 100644 --- a/src/vs/editor/test/common/modes/supports/tokenization.test.ts +++ b/src/vs/editor/test/common/modes/supports/tokenization.test.ts @@ -39,6 +39,7 @@ suite('Token theme matching', () => { { token: 'constant.numeric', foreground: '400000' }, { token: 'constant.numeric.hex', fontStyle: 'bold' }, { token: 'constant.numeric.oct', fontStyle: 'bold italic underline' }, + { token: 'constant.numeric.bin', fontStyle: 'bold strikethrough' }, { token: 'constant.numeric.dec', fontStyle: '', foreground: '500000' }, { token: 'storage.object.bar', fontStyle: '', foreground: '600000' }, ], []); @@ -103,6 +104,10 @@ suite('Token theme matching', () => { assertSimpleMatch('constant.numeric.oct', FontStyle.Bold | FontStyle.Italic | FontStyle.Underline, _E, _B); assertSimpleMatch('constant.numeric.oct.baz', FontStyle.Bold | FontStyle.Italic | FontStyle.Underline, _E, _B); + // matches constant.numeric.bin + assertSimpleMatch('constant.numeric.bin', FontStyle.Bold | FontStyle.Strikethrough, _E, _B); + assertSimpleMatch('constant.numeric.bin.baz', FontStyle.Bold | FontStyle.Strikethrough, _E, _B); + // matches constant.numeric.dec assertSimpleMatch('constant.numeric.dec', FontStyle.None, _F, _B); assertSimpleMatch('constant.numeric.dec.baz', FontStyle.None, _F, _B); diff --git a/src/vs/editor/test/common/services/semanticTokensProviderStyling.test.ts b/src/vs/editor/test/common/services/semanticTokensProviderStyling.test.ts index 5d5f1129e44..3ed07ec3458 100644 --- a/src/vs/editor/test/common/services/semanticTokensProviderStyling.test.ts +++ b/src/vs/editor/test/common/services/semanticTokensProviderStyling.test.ts @@ -38,7 +38,11 @@ suite('ModelService', () => { return { getTokenStyleMetadata: (tokenType, tokenModifiers, languageId): ITokenStyle => { return { - foreground: parseInt(tokenType.substr(2), 10) + foreground: parseInt(tokenType.substr(2), 10), + bold: undefined, + underline: undefined, + strikethrough: undefined, + italic: undefined }; } }; diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 2827c0577ec..74debc29154 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5294,11 +5294,11 @@ declare namespace monaco.languages { * 3322 2222 2222 1111 1111 1100 0000 0000 * 1098 7654 3210 9876 5432 1098 7654 3210 * - ------------------------------------------- - * bbbb bbbb bfff ffff ffFF FTTT LLLL LLLL + * bbbb bbbb bfff ffff ffFF FFTT LLLL LLLL * - ------------------------------------------- * - L = EncodedLanguageId (8 bits): Use `getEncodedLanguageId` to get the encoded ID of a language. - * - T = StandardTokenType (3 bits): Other = 0, Comment = 1, String = 2, RegEx = 4. - * - F = FontStyle (3 bits): None = 0, Italic = 1, Bold = 2, Underline = 4. + * - T = StandardTokenType (2 bits): Other = 0, Comment = 1, String = 2, RegEx = 3. + * - F = FontStyle (4 bits): None = 0, Italic = 1, Bold = 2, Underline = 4, Strikethrough = 8. * - f = foreground ColorId (9 bits) * - b = background ColorId (9 bits) * - The color value for each colorId is defined in IStandaloneThemeData.customTokenColors: diff --git a/src/vs/platform/theme/common/themeService.ts b/src/vs/platform/theme/common/themeService.ts index b2f9b5691b7..691ff19c4ec 100644 --- a/src/vs/platform/theme/common/themeService.ts +++ b/src/vs/platform/theme/common/themeService.ts @@ -101,10 +101,11 @@ export function getThemeTypeSelector(type: ColorScheme): string { } export interface ITokenStyle { - readonly foreground?: number; - readonly bold?: boolean; - readonly underline?: boolean; - readonly italic?: boolean; + readonly foreground: number | undefined; + readonly bold: boolean | undefined; + readonly underline: boolean | undefined; + readonly strikethrough: boolean | undefined; + readonly italic: boolean | undefined; } export interface IColorTheme { diff --git a/src/vs/platform/theme/common/tokenClassificationRegistry.ts b/src/vs/platform/theme/common/tokenClassificationRegistry.ts index 87a87855d92..b171d0186a4 100644 --- a/src/vs/platform/theme/common/tokenClassificationRegistry.ts +++ b/src/vs/platform/theme/common/tokenClassificationRegistry.ts @@ -24,7 +24,7 @@ export const typeAndModifierIdPattern = `^${idPattern}$`; export const selectorPattern = `^(${idPattern}|\\*)(\\${CLASSIFIER_MODIFIER_SEPARATOR}${idPattern})*(${TOKEN_CLASSIFIER_LANGUAGE_SEPARATOR}${idPattern})?$`; -export const fontStylePattern = '^(\\s*(italic|bold|underline))*\\s*$'; +export const fontStylePattern = '^(\\s*(italic|bold|underline|strikethrough))*\\s*$'; export interface TokenSelector { match(type: string, modifiers: string[], language: string): number; @@ -41,18 +41,20 @@ export interface TokenTypeOrModifierContribution { export interface TokenStyleData { - foreground?: Color; - bold?: boolean; - underline?: boolean; - italic?: boolean; + foreground: Color | undefined; + bold: boolean | undefined; + underline: boolean | undefined; + strikethrough: boolean | undefined; + italic: boolean | undefined; } export class TokenStyle implements Readonly { constructor( - public readonly foreground?: Color, - public readonly bold?: boolean, - public readonly underline?: boolean, - public readonly italic?: boolean, + public readonly foreground: Color | undefined, + public readonly bold: boolean | undefined, + public readonly underline: boolean | undefined, + public readonly strikethrough: boolean | undefined, + public readonly italic: boolean | undefined, ) { } } @@ -64,13 +66,20 @@ export namespace TokenStyle { _bold: style.bold === undefined ? null : style.bold, _underline: style.underline === undefined ? null : style.underline, _italic: style.italic === undefined ? null : style.italic, + _strikethrough: style.strikethrough === undefined ? null : style.strikethrough, }; } export function fromJSONObject(obj: any): TokenStyle | undefined { if (obj) { const boolOrUndef = (b: any) => (typeof b === 'boolean') ? b : undefined; const colorOrUndef = (s: any) => (typeof s === 'string') ? Color.fromHex(s) : undefined; - return new TokenStyle(colorOrUndef(obj._foreground), boolOrUndef(obj._bold), boolOrUndef(obj._underline), boolOrUndef(obj._italic)); + return new TokenStyle( + colorOrUndef(obj._foreground), + boolOrUndef(obj._bold), + boolOrUndef(obj._underline), + boolOrUndef(obj._strikethrough), + boolOrUndef(obj._italic) + ); } return undefined; } @@ -82,32 +91,36 @@ export namespace TokenStyle { && (s1.foreground instanceof Color ? s1.foreground.equals(s2.foreground) : s2.foreground === undefined) && s1.bold === s2.bold && s1.underline === s2.underline + && s1.strikethrough === s2.strikethrough && s1.italic === s2.italic; } export function is(s: any): s is TokenStyle { return s instanceof TokenStyle; } - export function fromData(data: { foreground?: Color, bold?: boolean, underline?: boolean, italic?: boolean }): TokenStyle { - return new TokenStyle(data.foreground, data.bold, data.underline, data.italic); + export function fromData(data: { foreground: Color | undefined, bold: boolean | undefined, underline: boolean | undefined, strikethrough: boolean | undefined, italic: boolean | undefined }): TokenStyle { + return new TokenStyle(data.foreground, data.bold, data.underline, data.strikethrough, data.italic); } - export function fromSettings(foreground: string | undefined, fontStyle: string | undefined, bold?: boolean, underline?: boolean, italic?: boolean): TokenStyle { + export function fromSettings(foreground: string | undefined, fontStyle: string | undefined): TokenStyle; + export function fromSettings(foreground: string | undefined, fontStyle: string | undefined, bold: boolean | undefined, underline: boolean | undefined, strikethrough: boolean | undefined, italic: boolean | undefined): TokenStyle; + export function fromSettings(foreground: string | undefined, fontStyle: string | undefined, bold?: boolean, underline?: boolean, strikethrough?: boolean, italic?: boolean): TokenStyle { let foregroundColor = undefined; if (foreground !== undefined) { foregroundColor = Color.fromHex(foreground); } if (fontStyle !== undefined) { - bold = italic = underline = false; - const expression = /italic|bold|underline/g; + bold = italic = underline = strikethrough = false; + const expression = /italic|bold|underline|strikethrough/g; let match; while ((match = expression.exec(fontStyle))) { switch (match[0]) { case 'bold': bold = true; break; case 'italic': italic = true; break; case 'underline': underline = true; break; + case 'strikethrough': strikethrough = true; break; } } } - return new TokenStyle(foregroundColor, bold, underline, italic); + return new TokenStyle(foregroundColor, bold, underline, strikethrough, italic); } } @@ -287,10 +300,27 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { }, fontStyle: { type: 'string', - description: nls.localize('schema.token.fontStyle', 'Sets the all font styles of the rule: \'italic\', \'bold\' or \'underline\' or a combination. All styles that are not listed are unset. The empty string unsets all styles.'), + description: nls.localize('schema.token.fontStyle', 'Sets the all font styles of the rule: \'italic\', \'bold\', \'underline\' or \'strikethrough\' or a combination. All styles that are not listed are unset. The empty string unsets all styles.'), pattern: fontStylePattern, - patternErrorMessage: nls.localize('schema.fontStyle.error', 'Font style must be \'italic\', \'bold\' or \'underline\' or a combination. The empty string unsets all styles.'), - defaultSnippets: [{ label: nls.localize('schema.token.fontStyle.none', 'None (clear inherited style)'), bodyText: '""' }, { body: 'italic' }, { body: 'bold' }, { body: 'underline' }, { body: 'italic underline' }, { body: 'bold underline' }, { body: 'italic bold underline' }] + patternErrorMessage: nls.localize('schema.fontStyle.error', 'Font style must be \'italic\', \'bold\', \'underline\' or \'strikethrough\' or a combination. The empty string unsets all styles.'), + defaultSnippets: [ + { label: nls.localize('schema.token.fontStyle.none', 'None (clear inherited style)'), bodyText: '""' }, + { body: 'italic' }, + { body: 'bold' }, + { body: 'underline' }, + { body: 'strikethrough' }, + { body: 'italic bold' }, + { body: 'italic underline' }, + { body: 'italic strikethrough' }, + { body: 'bold underline' }, + { body: 'bold strikethrough' }, + { body: 'underline strikethrough' }, + { body: 'italic bold underline' }, + { body: 'italic bold strikethrough' }, + { body: 'italic underline strikethrough' }, + { body: 'bold underline strikethrough' }, + { body: 'italic bold underline strikethrough' } + ] }, bold: { type: 'boolean', @@ -303,6 +333,10 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry { underline: { type: 'boolean', description: nls.localize('schema.token.underline', 'Sets or unsets the font style to underline. Note, the presence of \'fontStyle\' overrides this setting.'), + }, + strikethrough: { + type: 'boolean', + description: nls.localize('schema.token.strikethrough', 'Sets or unsets the font style to strikethrough. Note, the presence of \'fontStyle\' overrides this setting.'), } }, diff --git a/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts b/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts index 485e02c1ecd..7fa8aee4460 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts @@ -143,11 +143,12 @@ interface ISemanticTokenInfo { interface IDecodedMetadata { languageId: string; tokenType: StandardTokenType; - bold?: boolean; - italic?: boolean; - underline?: boolean; - foreground?: string; - background?: string; + bold: boolean | undefined; + italic: boolean | undefined; + underline: boolean | undefined; + strikethrough: boolean | undefined; + foreground: string | undefined; + background: string | undefined; } function renderTokenText(tokenText: string): string { @@ -314,7 +315,7 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget { )); } if (semanticTokenInfo.metadata) { - const properties: (keyof TokenStyleData)[] = ['foreground', 'bold', 'italic', 'underline']; + const properties: (keyof TokenStyleData)[] = ['foreground', 'bold', 'italic', 'underline', 'strikethrough']; const propertiesByDefValue: { [rule: string]: string[] } = {}; const allDefValues = new Array<[Array, string]>(); // remember the order // first collect to detect when the same rule is used for multiple properties @@ -421,7 +422,7 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget { const fontStyleLabels = new Array(); - function addStyle(key: 'bold' | 'italic' | 'underline') { + function addStyle(key: 'bold' | 'italic' | 'underline' | 'strikethrough') { let label: HTMLElement | string | undefined; if (semantic && semantic[key]) { label = $('span.tiw-metadata-semantic', undefined, key); @@ -438,6 +439,7 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget { addStyle('bold'); addStyle('italic'); addStyle('underline'); + addStyle('strikethrough'); if (fontStyleLabels.length) { elements.push($('tr', undefined, $('td.tiw-metadata-key', undefined, 'font style' as string), @@ -460,6 +462,7 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget { bold: (fontStyle & FontStyle.Bold) ? true : undefined, italic: (fontStyle & FontStyle.Italic) ? true : undefined, underline: (fontStyle & FontStyle.Underline) ? true : undefined, + strikethrough: (fontStyle & FontStyle.Strikethrough) ? true : undefined, foreground: colorMap[foreground], background: colorMap[background] }; @@ -583,7 +586,9 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget { bold: tokenStyle?.bold, italic: tokenStyle?.italic, underline: tokenStyle?.underline, - foreground: colorMap[tokenStyle?.foreground || ColorId.None] + strikethrough: tokenStyle?.strikethrough, + foreground: colorMap[tokenStyle?.foreground || ColorId.None], + background: undefined }; } diff --git a/src/vs/workbench/services/textMate/common/TMHelper.ts b/src/vs/workbench/services/textMate/common/TMHelper.ts index f959abeb57e..32d73fa14b7 100644 --- a/src/vs/workbench/services/textMate/common/TMHelper.ts +++ b/src/vs/workbench/services/textMate/common/TMHelper.ts @@ -16,7 +16,7 @@ export interface ITokenColorizationRule { export interface ITokenColorizationSetting { foreground?: string; background?: string; - fontStyle?: string; // italic, underline, bold + fontStyle?: string; // italic, underline, strikethrough, bold } export function findMatchingThemeRule(theme: IColorTheme, scopes: string[], onlyColorRules: boolean = true): ThemeRule | null { diff --git a/src/vs/workbench/services/themes/common/colorThemeData.ts b/src/vs/workbench/services/themes/common/colorThemeData.ts index 13eb1d31e1c..f99657d109e 100644 --- a/src/vs/workbench/services/themes/common/colorThemeData.ts +++ b/src/vs/workbench/services/themes/common/colorThemeData.ts @@ -148,12 +148,14 @@ export class ColorThemeData implements IWorkbenchColorTheme { foreground: undefined, bold: undefined, underline: undefined, + strikethrough: undefined, italic: undefined }; let score = { foreground: -1, bold: -1, underline: -1, + strikethrough: -1, italic: -1 }; @@ -163,7 +165,7 @@ export class ColorThemeData implements IWorkbenchColorTheme { result.foreground = style.foreground; definitions.foreground = definition; } - for (let p of ['bold', 'underline', 'italic']) { + for (let p of ['bold', 'underline', 'strikethrough', 'italic']) { const property = p as keyof TokenStyle; const info = style[property]; if (info !== undefined) { @@ -272,7 +274,8 @@ export class ColorThemeData implements IWorkbenchColorTheme { foreground: this.getTokenColorIndex().get(style.foreground), bold: style.bold, underline: style.underline, - italic: style.italic + strikethrough: style.strikethrough, + italic: style.italic, }; } @@ -332,7 +335,7 @@ export class ColorThemeData implements IWorkbenchColorTheme { if (foreground !== undefined || fontStyle !== undefined) { if (definitions) { definitions.foreground = foregroundThemingRule; - definitions.bold = definitions.italic = definitions.underline = fontStyleThemingRule; + definitions.bold = definitions.italic = definitions.underline = definitions.strikethrough = fontStyleThemingRule; definitions.scope = scope; } @@ -858,7 +861,7 @@ function readSemanticTokenRule(selectorString: string, settings: ISemanticTokenC if (typeof settings === 'string') { style = TokenStyle.fromSettings(settings, undefined); } else if (isSemanticTokenColorizationSetting(settings)) { - style = TokenStyle.fromSettings(settings.foreground, settings.fontStyle, settings.bold, settings.underline, settings.italic); + style = TokenStyle.fromSettings(settings.foreground, settings.fontStyle, settings.bold, settings.underline, settings.strikethrough, settings.italic); } if (style) { return { selector, style }; @@ -868,7 +871,7 @@ function readSemanticTokenRule(selectorString: string, settings: ISemanticTokenC function isSemanticTokenColorizationSetting(style: any): style is ISemanticTokenColorizationSetting { return style && (types.isString(style.foreground) || types.isString(style.fontStyle) || types.isBoolean(style.italic) - || types.isBoolean(style.underline) || types.isBoolean(style.bold)); + || types.isBoolean(style.underline) || types.isBoolean(style.strikethrough) || types.isBoolean(style.bold)); } diff --git a/src/vs/workbench/services/themes/common/colorThemeSchema.ts b/src/vs/workbench/services/themes/common/colorThemeSchema.ts index 0b797a38eb6..ca201c73c95 100644 --- a/src/vs/workbench/services/themes/common/colorThemeSchema.ts +++ b/src/vs/workbench/services/themes/common/colorThemeSchema.ts @@ -149,10 +149,27 @@ const textmateColorSchema: IJSONSchema = { }, fontStyle: { type: 'string', - description: nls.localize('schema.token.fontStyle', 'Font style of the rule: \'italic\', \'bold\' or \'underline\' or a combination. The empty string unsets inherited settings.'), - pattern: '^(\\s*\\b(italic|bold|underline))*\\s*$', - patternErrorMessage: nls.localize('schema.fontStyle.error', 'Font style must be \'italic\', \'bold\' or \'underline\' or a combination or the empty string.'), - defaultSnippets: [{ label: nls.localize('schema.token.fontStyle.none', 'None (clear inherited style)'), bodyText: '""' }, { body: 'italic' }, { body: 'bold' }, { body: 'underline' }, { body: 'italic bold' }, { body: 'italic underline' }, { body: 'bold underline' }, { body: 'italic bold underline' }] + description: nls.localize('schema.token.fontStyle', 'Font style of the rule: \'italic\', \'bold\', \'underline\', \'strikethrough\' or a combination. The empty string unsets inherited settings.'), + pattern: '^(\\s*\\b(italic|bold|underline|strikethrough))*\\s*$', + patternErrorMessage: nls.localize('schema.fontStyle.error', 'Font style must be \'italic\', \'bold\', \'underline\', \'strikethrough\' or a combination or the empty string.'), + defaultSnippets: [ + { label: nls.localize('schema.token.fontStyle.none', 'None (clear inherited style)'), bodyText: '""' }, + { body: 'italic' }, + { body: 'bold' }, + { body: 'underline' }, + { body: 'strikethrough' }, + { body: 'italic bold' }, + { body: 'italic underline' }, + { body: 'italic strikethrough' }, + { body: 'bold underline' }, + { body: 'bold strikethrough' }, + { body: 'underline strikethrough' }, + { body: 'italic bold underline' }, + { body: 'italic bold strikethrough' }, + { body: 'italic underline strikethrough' }, + { body: 'bold underline strikethrough' }, + { body: 'italic bold underline strikethrough' } + ] } }, additionalProperties: false, @@ -243,4 +260,3 @@ export function registerColorThemeSchemas() { schemaRegistry.registerSchema(colorThemeSchemaId, colorThemeSchema); schemaRegistry.registerSchema(textmateColorsSchemaId, textmateColorSchema); } - diff --git a/src/vs/workbench/services/themes/common/workbenchThemeService.ts b/src/vs/workbench/services/themes/common/workbenchThemeService.ts index 6c3e472e41e..69cc4d515cc 100644 --- a/src/vs/workbench/services/themes/common/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/common/workbenchThemeService.ts @@ -169,14 +169,15 @@ export interface ITextMateThemingRule { export interface ITokenColorizationSetting { foreground?: string; background?: string; - fontStyle?: string; /* [italic|underline|bold] */ + fontStyle?: string; /* [italic|bold|underline|strikethrough] */ } export interface ISemanticTokenColorizationSetting { foreground?: string; - fontStyle?: string; /* [italic|underline|bold] */ + fontStyle?: string; /* [italic|bold|underline|strikethrough] */ bold?: boolean; underline?: boolean; + strikethrough?: boolean; italic?: boolean; } diff --git a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts index 8a3acdfc4d2..95d73c79422 100644 --- a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts +++ b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts @@ -24,9 +24,9 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur const undefinedStyle = { bold: undefined, underline: undefined, italic: undefined }; const unsetStyle = { bold: false, underline: false, italic: false }; -function ts(foreground: string | undefined, styleFlags: { bold?: boolean; underline?: boolean; italic?: boolean; } | undefined): TokenStyle { +function ts(foreground: string | undefined, styleFlags: { bold?: boolean; underline?: boolean; strikethrough?: boolean; italic?: boolean; } | undefined): TokenStyle { const foregroundColor = isString(foreground) ? Color.fromHex(foreground) : undefined; - return new TokenStyle(foregroundColor, styleFlags && styleFlags.bold, styleFlags && styleFlags.underline, styleFlags && styleFlags.italic); + return new TokenStyle(foregroundColor, styleFlags?.bold, styleFlags?.underline, styleFlags?.strikethrough, styleFlags?.italic); } function tokenStyleAsString(ts: TokenStyle | undefined | null) {