jvikstrom updated this revision to Diff 214779.
jvikstrom added a comment.

Updated patch description.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D65856/new/

https://reviews.llvm.org/D65856

Files:
  clang-tools-extra/clangd/clients/clangd-vscode/src/semantic-highlighting.ts
  
clang-tools-extra/clangd/clients/clangd-vscode/test/semantic-highlighting.test.ts

Index: clang-tools-extra/clangd/clients/clangd-vscode/test/semantic-highlighting.test.ts
===================================================================
--- clang-tools-extra/clangd/clients/clangd-vscode/test/semantic-highlighting.test.ts
+++ clang-tools-extra/clangd/clients/clangd-vscode/test/semantic-highlighting.test.ts
@@ -1,13 +1,13 @@
 import * as assert from 'assert';
 import * as path from 'path';
 
-import * as TM from '../src/semantic-highlighting';
+import * as SM from '../src/semantic-highlighting';
 
 suite('SemanticHighlighting Tests', () => {
   test('Parses arrays of textmate themes.', async () => {
     const themePath =
         path.join(__dirname, '../../test/assets/includeTheme.jsonc');
-    const scopeColorRules = await TM.parseThemeFile(themePath);
+    const scopeColorRules = await SM.parseThemeFile(themePath);
     const getScopeRule = (scope: string) =>
         scopeColorRules.find((v) => v.scope === scope);
     assert.equal(scopeColorRules.length, 3);
@@ -33,6 +33,21 @@
       ]
     ];
     testCases.forEach((testCase, i) => assert.deepEqual(
-                          TM.decodeTokens(testCase), expected[i]));
+                          SM.decodeTokens(testCase), expected[i]));
+  });
+  test('ScopeRules overrides for more specific themes', () => {
+    const scopes = [ [ 'a.b', 'a.b' ], [ 'a', 'a.b', 'c.b.a' ], [ 'c.b.a' ] ];
+    const rules = [
+      {scope : 'c.b', foreground : '1'},
+      {scope : 'a', foreground : '2'},
+      {scope : 'a.b', foreground : '3'},
+      {scope : 'a', foreground : '4'},
+      {scope : 'c.b.a', foreground : '5'},
+    ];
+    const tm = new SM.ScopeRules(scopes);
+    rules.forEach((r) => tm.addRule(r));
+    assert.deepEqual(tm.getRule(0), rules[2]);
+    assert.deepEqual(tm.getRule(1), rules[1]);
+    assert.deepEqual(tm.getRule(2), rules[4]);
   });
 });
Index: clang-tools-extra/clangd/clients/clangd-vscode/src/semantic-highlighting.ts
===================================================================
--- clang-tools-extra/clangd/clients/clangd-vscode/src/semantic-highlighting.ts
+++ clang-tools-extra/clangd/clients/clangd-vscode/src/semantic-highlighting.ts
@@ -47,6 +47,8 @@
   // The TextMate scope lookup table. A token with scope index i has the scopes
   // on index i in the lookup table.
   scopeLookupTable: string[][];
+  // The rules for the scopes given the current theme.
+  scopeRules: ScopeRules;
   fillClientCapabilities(capabilities: vscodelc.ClientCapabilities) {
     // Extend the ClientCapabilities type and add semantic highlighting
     // capability to the object.
@@ -58,6 +60,18 @@
     };
   }
 
+  async loadCurrentTheme() {
+    const name =
+        vscode.workspace.getConfiguration('workbench').get('colorTheme');
+    if (typeof name != 'string') {
+      console.warn('The current theme name is not a string, is:' +
+                       (typeof name) + ', value: ',
+                   name);
+      return;
+    }
+    this.scopeRules = await loadTheme(name, this.scopeLookupTable);
+  }
+
   initialize(capabilities: vscodelc.ServerCapabilities,
              documentSelector: vscodelc.DocumentSelector|undefined) {
     // The semantic highlighting capability information is in the capabilities
@@ -68,6 +82,7 @@
     if (!serverCapabilities.semanticHighlighting)
       return;
     this.scopeLookupTable = serverCapabilities.semanticHighlighting.scopes;
+    this.loadCurrentTheme();
   }
 
   handleNotification(params: SemanticHighlightingParams) {}
@@ -101,8 +116,55 @@
   foreground: string;
 }
 
+export class ScopeRules {
+  // The TextMate scopes that should be mapped to a color.
+  private scopeLookupTable: string[][];
+  // Contains the current best matching scope for the scope at the corresponding
+  // index.
+  private scopeRules: TokenColorRule[];
+  // Each list of scopes can only have one rule matching. The actual scope that
+  // matches for each index should be as close to zero as possible.
+  private currentScopeRuleIdx: number[];
+  constructor(scopeLookupTable: string[][]) {
+    this.scopeLookupTable = scopeLookupTable;
+    this.currentScopeRuleIdx =
+        this.scopeLookupTable.map(() => Number.POSITIVE_INFINITY);
+    this.scopeRules =
+        this.scopeLookupTable.map(() => ({scope : '', foreground : '#000'}));
+  }
+
+  // Associates rule to the scopeLookupTable if possible. For a rule to be
+  // associated to an array of scopes it must be a prefix of any of the scopes.
+  // Be the earliest match in the array of scopes and be the most specific
+  // match.
+  addRule(rule: TokenColorRule) {
+    this.scopeLookupTable.forEach((scopes, i) => {
+      const lookupIdx = scopes.findIndex(
+          (scope) => scope.substr(0, rule.scope.length) == rule.scope);
+      if (lookupIdx == -1)
+        // Could not find a match for this rule.
+        return;
+      if (lookupIdx > this.currentScopeRuleIdx[i])
+        // There is already a rule for this scope that has a higher precedence
+        // than this match.
+        return;
+      if (rule.scope.length > this.scopeRules[i].scope.length ||
+          lookupIdx < this.currentScopeRuleIdx[i]) {
+        // This rule is more specific than the last rule or has a higher
+        // precedence.
+        this.scopeRules[i] = rule;
+        this.currentScopeRuleIdx[i] = lookupIdx;
+      }
+    });
+  }
+
+  // Get the rule at idx.
+  getRule(idx: number) { return this.scopeRules[idx]; }
+}
+
 // Get all token color rules provided by the theme.
-function loadTheme(themeName: string): Promise<TokenColorRule[]> {
+async function loadTheme(themeName: string,
+                         scopes: string[][]): Promise<ScopeRules> {
   const extension =
       vscode.extensions.all.find((extension: vscode.Extension<any>) => {
         const contribs = extension.packageJSON.contributes;
@@ -118,7 +180,11 @@
 
   const themeInfo = extension.packageJSON.contributes.themes.find(
       (theme: any) => theme.id === themeName || theme.label === themeName);
-  return parseThemeFile(path.join(extension.extensionPath, themeInfo.path));
+  const tokenScopeRules =
+      await parseThemeFile(path.join(extension.extensionPath, themeInfo.path));
+  const scopeRules = new ScopeRules(scopes);
+  tokenScopeRules.forEach((rule) => scopeRules.addRule(rule));
+  return scopeRules;
 }
 
 /**
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to