Skip to content

Commit 4a1614f

Browse files
committed
match score
1 parent fa99aa5 commit 4a1614f

2 files changed

Lines changed: 90 additions & 46 deletions

File tree

src/vs/workbench/services/themes/common/colorThemeData.ts

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -138,44 +138,41 @@ export class ColorThemeData implements IColorTheme {
138138
/** Public for testing reasons */
139139
public findTokenStyleForScope(scope: ProbeScope): TokenStyle | undefined {
140140

141+
let foreground: string | null = null;
142+
let fontStyle: string | null = null;
143+
let foregroundScore = -1;
144+
let fontStyleScore = -1;
145+
141146
function findTokenStyleForScopeInScopes(scopeMatchers: Matcher<ProbeScope>[], tokenColors: ITokenColorizationRule[]) {
142-
for (let i = scopeMatchers.length - 1; i >= 0; i--) {
147+
for (let i = 0; i < scopeMatchers.length; i++) {
148+
const settings = tokenColors[i].settings;
149+
if (!settings) {
150+
continue;
151+
}
143152
let matcher = scopeMatchers[i];
144153
if (!matcher) {
145154
scopeMatchers[i] = matcher = getScopeMatcher(tokenColors[i]);
146155
}
147-
if (matcher(scope)) {
148-
const settings = tokenColors[i].settings;
149-
if (settings) {
150-
if (foreground === null && settings.foreground) {
151-
foreground = settings.foreground;
152-
}
153-
if (fontStyle === null && types.isString(settings.fontStyle)) {
154-
fontStyle = settings.fontStyle;
155-
}
156-
if (foreground !== null && fontStyle !== null) {
157-
break;
158-
}
159-
}
156+
const score = matcher(scope);
157+
if (score > foregroundScore && settings.foreground) {
158+
foreground = settings.foreground;
159+
}
160+
if (score > fontStyleScore && types.isString(settings.fontStyle)) {
161+
fontStyle = settings.fontStyle;
160162
}
161163
}
162164
}
163165

164-
let foreground: string | null = null;
165-
let fontStyle: string | null = null;
166+
if (!this.themeTokenScopeMatchers) {
167+
this.themeTokenScopeMatchers = new Array(this.themeTokenColors.length);
168+
}
169+
findTokenStyleForScopeInScopes(this.themeTokenScopeMatchers, this.themeTokenColors);
166170

167171
if (!this.customTokenScopeMatchers) {
168172
this.customTokenScopeMatchers = new Array(this.customTokenColors.length);
169173
}
170174
findTokenStyleForScopeInScopes(this.customTokenScopeMatchers, this.customTokenColors);
171175

172-
if (foreground === null || fontStyle === null) {
173-
if (!this.themeTokenScopeMatchers) {
174-
this.themeTokenScopeMatchers = new Array(this.themeTokenColors.length);
175-
}
176-
findTokenStyleForScopeInScopes(this.themeTokenScopeMatchers, this.themeTokenColors);
177-
}
178-
179176
if (foreground !== null || fontStyle !== null) {
180177
return getTokenStyle(foreground, fontStyle);
181178
}
@@ -462,27 +459,43 @@ let defaultThemeColors: { [baseTheme: string]: ITokenColorizationRule[] } = {
462459
],
463460
};
464461

465-
const noMatch = (_scope: ProbeScope) => false;
462+
const noMatch = (_scope: ProbeScope) => -1;
466463

467-
function nameMatcher(identifers: string[], scope: ProbeScope) {
464+
function nameMatcher(identifers: string[], scope: ProbeScope): number {
465+
function findInIdents(s: string, lastIndent: number): number {
466+
for (let i = lastIndent - 1; i >= 0; i--) {
467+
if (scopesAreMatching(identifers[i], s)) {
468+
return i;
469+
}
470+
}
471+
return -1;
472+
}
468473
if (!Array.isArray(scope)) {
469-
scope = [scope];
474+
const idx = findInIdents(scope, identifers.length);
475+
if (idx >= 0) {
476+
return idx * 0x10000 + scope.length;
477+
}
478+
return -1;
470479
}
471480
if (scope.length < identifers.length) {
472-
return false;
473-
}
474-
let lastIndex = 0;
475-
return identifers.every(identifier => {
476-
for (let i = lastIndex; i < scope.length; i++) {
477-
if (scopesAreMatching(scope[i], identifier)) {
478-
lastIndex = i + 1;
479-
return true;
481+
return -1;
482+
}
483+
let lastScopeIndex = scope.length - 1;
484+
let lastIdentifierIndex = findInIdents(scope[lastScopeIndex--], identifers.length);
485+
if (lastIdentifierIndex >= 0) {
486+
const score = lastIdentifierIndex * 0x10000 + scope.length;
487+
while (lastScopeIndex >= 0) {
488+
lastIdentifierIndex = findInIdents(scope[lastScopeIndex--], lastIdentifierIndex);
489+
if (lastIdentifierIndex === -1) {
490+
return -1;
480491
}
481492
}
482-
return false;
483-
});
493+
return score;
494+
}
495+
return -1;
484496
}
485497

498+
486499
function scopesAreMatching(thisScopeName: string, scopeName: string): boolean {
487500
if (!thisScopeName) {
488501
return false;
@@ -507,7 +520,13 @@ function getScopeMatcher(rule: ITokenColorizationRule): Matcher<ProbeScope> {
507520
} else {
508521
matchers.push(...createMatchers(ruleScope, nameMatcher));
509522
}
510-
return (scope: ProbeScope) => matchers.some(m => m.matcher(scope));
523+
return (scope: ProbeScope) => {
524+
let max = 0;
525+
for (const m of matchers) {
526+
max = Math.max(max, m.matcher(scope));
527+
}
528+
return max;
529+
};
511530
}
512531

513532
function getTokenStyle(foreground: string | null, fontStyle: string | null): TokenStyle | undefined {

src/vs/workbench/services/themes/common/textMateScopeMatcher.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ export interface MatcherWithPriority<T> {
1111
}
1212

1313
export interface Matcher<T> {
14-
(matcherInput: T): boolean;
14+
(matcherInput: T): number;
1515
}
1616

17-
export function createMatchers<T>(selector: string, matchesName: (names: string[], matcherInput: T) => boolean): MatcherWithPriority<T>[] {
17+
export function createMatchers<T>(selector: string, matchesName: (names: string[], matcherInput: T) => number): MatcherWithPriority<T>[] {
1818
const results = <MatcherWithPriority<T>[]>[];
1919
const tokenizer = newTokenizer(selector);
2020
let token = tokenizer.next();
@@ -44,7 +44,13 @@ export function createMatchers<T>(selector: string, matchesName: (names: string[
4444
if (token === '-') {
4545
token = tokenizer.next();
4646
const expressionToNegate = parseOperand();
47-
return matcherInput => !!expressionToNegate && !expressionToNegate(matcherInput);
47+
if (!expressionToNegate) {
48+
return null;
49+
}
50+
return matcherInput => {
51+
const score = expressionToNegate(matcherInput);
52+
return score < 0 ? 0 : -1;
53+
};
4854
}
4955
if (token === '(') {
5056
token = tokenizer.next();
@@ -64,18 +70,31 @@ export function createMatchers<T>(selector: string, matchesName: (names: string[
6470
}
6571
return null;
6672
}
67-
function parseConjunction(): Matcher<T> {
68-
const matchers: Matcher<T>[] = [];
73+
function parseConjunction(): Matcher<T> | null {
6974
let matcher = parseOperand();
75+
if (!matcher) {
76+
return null;
77+
}
78+
79+
const matchers: Matcher<T>[] = [];
7080
while (matcher) {
7181
matchers.push(matcher);
7282
matcher = parseOperand();
7383
}
74-
return matcherInput => matchers.every(matcher => matcher(matcherInput)); // and
84+
return matcherInput => { // and
85+
let min = matchers[0](matcherInput);
86+
for (let i = 1; min >= 0 && i < matchers.length; i++) {
87+
min = Math.min(min, matchers[i](matcherInput));
88+
}
89+
return min;
90+
};
7591
}
76-
function parseInnerExpression(): Matcher<T> {
77-
const matchers: Matcher<T>[] = [];
92+
function parseInnerExpression(): Matcher<T> | null {
7893
let matcher = parseConjunction();
94+
if (!matcher) {
95+
return null;
96+
}
97+
const matchers: Matcher<T>[] = [];
7998
while (matcher) {
8099
matchers.push(matcher);
81100
if (token === '|' || token === ',') {
@@ -87,7 +106,13 @@ export function createMatchers<T>(selector: string, matchesName: (names: string[
87106
}
88107
matcher = parseConjunction();
89108
}
90-
return matcherInput => matchers.some(matcher => matcher(matcherInput)); // or
109+
return matcherInput => { // or
110+
let max = matchers[0](matcherInput);
111+
for (let i = 1; i < matchers.length; i++) {
112+
max = Math.max(max, matchers[i](matcherInput));
113+
}
114+
return max;
115+
};
91116
}
92117
}
93118

0 commit comments

Comments
 (0)