simplify decoration rules and add trace assertion for when things go south...

This commit is contained in:
Johannes Rieken 2019-11-08 15:18:44 +01:00
parent 75b075962a
commit dca100feaa
2 changed files with 22 additions and 29 deletions

View file

@ -795,7 +795,7 @@ function getSharedStyleSheet(): HTMLStyleElement {
return _sharedStyleSheet; return _sharedStyleSheet;
} }
function getDynamicStyleSheetRules(style: any) { export function getDynamicStyleSheetRules(style: any): CSSStyleRule[] {
if (style && style.sheet && style.sheet.rules) { if (style && style.sheet && style.sheet.rules) {
// Chrome, IE // Chrome, IE
return style.sheet.rules; return style.sheet.rules;

View file

@ -10,7 +10,7 @@ import { TernarySearchTree } from 'vs/base/common/map';
import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { isThenable } from 'vs/base/common/async'; import { isThenable } from 'vs/base/common/async';
import { LinkedList } from 'vs/base/common/linkedList'; import { LinkedList } from 'vs/base/common/linkedList';
import { createStyleSheet, createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom'; import { createStyleSheet, createCSSRule, removeCSSRulesContainingSelector, getDynamicStyleSheetRules } from 'vs/base/browser/dom';
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
import { IdGenerator } from 'vs/base/common/idGenerator'; import { IdGenerator } from 'vs/base/common/idGenerator';
import { isFalsyOrWhitespace } from 'vs/base/common/strings'; import { isFalsyOrWhitespace } from 'vs/base/common/strings';
@ -22,25 +22,25 @@ import { ILogService } from 'vs/platform/log/common/log';
class DecorationRule { class DecorationRule {
static keyOf(data: IDecorationData | IDecorationData[]): string { static keyOf(data: IDecorationData[]): string {
if (Array.isArray(data)) { let result = '';
return data.map(DecorationRule.keyOf).join(','); for (const d of data) {
} else { const { color, letter } = d;
const { color, letter } = data; result += `${color}/${letter}`;
return `${color}/${letter}`;
} }
return result;
} }
private static readonly _classNames = new IdGenerator('monaco-decorations-style-'); private static readonly _classNames = new IdGenerator('monaco-decorations-style-');
readonly data: IDecorationData | IDecorationData[]; readonly data: IDecorationData[];
readonly itemColorClassName: string; readonly itemColorClassName: string;
readonly itemBadgeClassName: string; readonly itemBadgeClassName: string;
readonly bubbleBadgeClassName: string; readonly bubbleBadgeClassName: string;
private _refCounter: number = 0; private _refCounter: number = 0;
constructor(data: IDecorationData | IDecorationData[]) { constructor(data: IDecorationData[]) {
this.data = data; this.data = data;
this.itemColorClassName = DecorationRule._classNames.nextId(); this.itemColorClassName = DecorationRule._classNames.nextId();
this.itemBadgeClassName = DecorationRule._classNames.nextId(); this.itemBadgeClassName = DecorationRule._classNames.nextId();
@ -56,30 +56,13 @@ class DecorationRule {
} }
appendCSSRules(element: HTMLStyleElement, theme: ITheme): void { appendCSSRules(element: HTMLStyleElement, theme: ITheme): void {
if (!Array.isArray(this.data)) {
this._appendForOne(this.data, element, theme);
} else {
this._appendForMany(this.data, element, theme);
}
}
private _appendForOne(data: IDecorationData, element: HTMLStyleElement, theme: ITheme): void {
const { color, letter } = data;
// label // label
createCSSRule(`.${this.itemColorClassName}`, `color: ${getColor(theme, color)};`, element); const { color } = this.data[0];
// letter
if (letter) {
createCSSRule(`.${this.itemBadgeClassName}::after`, `content: "${letter}"; color: ${getColor(theme, color)};`, element);
}
}
private _appendForMany(data: IDecorationData[], element: HTMLStyleElement, theme: ITheme): void {
// label
const { color } = data[0];
createCSSRule(`.${this.itemColorClassName}`, `color: ${getColor(theme, color)};`, element); createCSSRule(`.${this.itemColorClassName}`, `color: ${getColor(theme, color)};`, element);
// badge // badge
const letters = data.filter(d => !isFalsyOrWhitespace(d.letter)).map(d => d.letter); const letters = this.data.filter(d => !isFalsyOrWhitespace(d.letter)).map(d => d.letter);
if (letters.length) { if (letters.length) {
createCSSRule(`.${this.itemBadgeClassName}::after`, `content: "${letters.join(', ')}"; color: ${getColor(theme, color)};`, element); createCSSRule(`.${this.itemBadgeClassName}::after`, `content: "${letters.join(', ')}"; color: ${getColor(theme, color)};`, element);
} }
@ -134,6 +117,8 @@ class DecorationStyles {
rule.acquire(); rule.acquire();
this._validate();
let labelClassName = rule.itemColorClassName; let labelClassName = rule.itemColorClassName;
let badgeClassName = rule.itemBadgeClassName; let badgeClassName = rule.itemBadgeClassName;
let tooltip = data.filter(d => !isFalsyOrWhitespace(d.tooltip)).map(d => d.tooltip).join(' • '); let tooltip = data.filter(d => !isFalsyOrWhitespace(d.tooltip)).map(d => d.tooltip).join(' • ');
@ -153,6 +138,7 @@ class DecorationStyles {
this._decorationRules.delete(key); this._decorationRules.delete(key);
rule.removeCSSRules(this._styleElement); rule.removeCSSRules(this._styleElement);
rule = undefined; rule = undefined;
this._validate();
} }
} }
}; };
@ -164,6 +150,13 @@ class DecorationStyles {
rule.appendCSSRules(this._styleElement, this._themeService.getTheme()); rule.appendCSSRules(this._styleElement, this._themeService.getTheme());
}); });
} }
private _validate(): void {
const ruleCount = getDynamicStyleSheetRules(this._styleElement).length;
if (this._decorationRules.size * 3 !== ruleCount) {
console.trace('THIS IS BAD - CHECK YOUR DECORATIONS SOMETHING IS OUT OF SYNC');
}
}
} }
class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { class FileDecorationChangeEvent implements IResourceDecorationChangeEvent {