提交 517e4391 编写于 作者: M Martin Aeschlimann

readonly semantic highlighting

上级 0fde639a
......@@ -20,9 +20,10 @@ export function getSemanticTokens(jsLanguageService: ts.LanguageService, current
if (node.kind === ts.SyntaxKind.Identifier) {
const symbol = typeChecker.getSymbolAtLocation(node);
if (symbol) {
const decl = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0];
if (decl) {
let typeIdx = tokenFromDeclarationMapping[decl.kind];
let typeIdx = classifySymbol(symbol);
if (typeIdx !== undefined) {
let modifierSet = 0;
if (node.parent) {
const parentTypeIdx = tokenFromDeclarationMapping[node.parent.kind];
......@@ -30,16 +31,19 @@ export function getSemanticTokens(jsLanguageService: ts.LanguageService, current
modifierSet = TokenModifier.declaration;
}
}
const modifiers = ts.getCombinedModifierFlags(decl);
const decl = symbol.valueDeclaration;
const modifiers = decl ? ts.getCombinedModifierFlags(decl) : 0;
const nodeFlags = decl ? ts.getCombinedNodeFlags(decl) : 0;
if (modifiers & ts.ModifierFlags.Static) {
modifierSet |= TokenModifier.static;
}
if (modifiers & ts.ModifierFlags.Async) {
modifierSet |= TokenModifier.async;
}
if (typeIdx !== undefined) {
resultTokens.push({ start: currentTextDocument.positionAt(node.getStart()), length: node.getWidth(), typeIdx, modifierSet });
if ((modifiers & ts.ModifierFlags.Readonly) || (nodeFlags & ts.NodeFlags.Const)) {
modifierSet |= TokenModifier.readonly;
}
resultTokens.push({ start: currentTextDocument.positionAt(node.getStart()), length: node.getWidth(), typeIdx, modifierSet });
}
}
}
......@@ -55,6 +59,27 @@ export function getSemanticTokens(jsLanguageService: ts.LanguageService, current
return resultTokens;
}
function classifySymbol(symbol: ts.Symbol) {
const flags = symbol.getFlags();
if (flags & ts.SymbolFlags.Class) {
return TokenType.class;
} else if (flags & ts.SymbolFlags.Enum) {
return TokenType.enum;
} else if (flags & ts.SymbolFlags.TypeAlias) {
return TokenType.type;
} else if (flags & ts.SymbolFlags.Type) {
if (flags & ts.SymbolFlags.Interface) {
return TokenType.interface;
} if (flags & ts.SymbolFlags.TypeParameter) {
return TokenType.typeParameter;
}
}
const decl = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0];
return tokenFromDeclarationMapping[decl.kind];
}
export function getSemanticTokenLegend() {
return { types: tokenTypes, modifiers: tokenModifiers };
......@@ -62,7 +87,7 @@ export function getSemanticTokenLegend() {
const tokenTypes: string[] = ['class', 'enum', 'interface', 'namespace', 'typeParameter', 'type', 'parameter', 'variable', 'property', 'constant', 'function', 'member'];
const tokenModifiers: string[] = ['declaration', 'static', 'async'];
const tokenModifiers: string[] = ['declaration', 'static', 'async', 'readonly'];
const enum TokenType {
'class' = 0,
......@@ -84,6 +109,7 @@ const enum TokenModifier {
'declaration' = 0x01,
'static' = 0x02,
'async' = 0x04,
'readonly' = 0x08,
}
const tokenFromDeclarationMapping: { [name: string]: TokenType } = {
......
......@@ -55,7 +55,7 @@ suite('HTML Semantic Tokens', () => {
/*2*/'<script>',
/*3*/' var x = 9, y1 = [x];',
/*4*/' try {',
/*5*/' for (const s of y1) { }',
/*5*/' for (const s of y1) { x = s }',
/*6*/' } catch (e) {',
/*7*/' throw y1;',
/*8*/' }',
......@@ -65,7 +65,7 @@ suite('HTML Semantic Tokens', () => {
];
assertTokens(input, [
t(3, 6, 1, 'variable.declaration'), t(3, 13, 2, 'variable.declaration'), t(3, 19, 1, 'variable'),
t(5, 15, 1, 'variable.declaration'), t(5, 20, 2, 'variable'),
t(5, 15, 1, 'variable.declaration.readonly'), t(5, 20, 2, 'variable'), t(5, 26, 1, 'variable'), t(5, 30, 1, 'variable.readonly'),
t(6, 11, 1, 'variable.declaration'),
t(7, 10, 2, 'variable')
]);
......@@ -86,7 +86,7 @@ suite('HTML Semantic Tokens', () => {
];
assertTokens(input, [
t(3, 11, 3, 'function.declaration'), t(3, 15, 2, 'parameter.declaration'),
t(4, 11, 3, 'function'), t(4, 15, 4, 'variable'), t(4, 20, 3, 'member'), t(4, 24, 2, 'parameter'),
t(4, 11, 3, 'function'), t(4, 15, 4, 'interface'), t(4, 20, 3, 'member'), t(4, 24, 2, 'parameter'),
t(6, 6, 6, 'variable'), t(6, 13, 8, 'property'), t(6, 24, 5, 'member'), t(6, 35, 7, 'member'), t(6, 43, 1, 'parameter.declaration'), t(6, 48, 3, 'function'), t(6, 52, 1, 'parameter')
]);
});
......@@ -134,8 +134,28 @@ suite('HTML Semantic Tokens', () => {
];
assertTokens(input, [
t(3, 12, 8, 'interface.declaration'), t(3, 23, 1, 'property.declaration'), t(3, 34, 1, 'property.declaration'),
t(4, 8, 1, 'variable.declaration'), t(4, 30, 8, 'interface'),
t(5, 8, 3, 'variable.declaration'), t(5, 15, 1, 'parameter.declaration'), t(5, 18, 8, 'interface'), t(5, 31, 1, 'parameter'), t(5, 33, 1, 'property'), t(5, 37, 1, 'parameter'), t(5, 39, 1, 'property')
t(4, 8, 1, 'variable.declaration.readonly'), t(4, 30, 8, 'interface'),
t(5, 8, 3, 'variable.declaration.readonly'), t(5, 15, 1, 'parameter.declaration'), t(5, 18, 8, 'interface'), t(5, 31, 1, 'parameter'), t(5, 33, 1, 'property'), t(5, 37, 1, 'parameter'), t(5, 39, 1, 'property')
]);
});
test('Readonly', () => {
const input = [
/*0*/'<html>',
/*1*/'<head>',
/*2*/'<script type="text/typescript">',
/*3*/' const f = 9;',
/*4*/' class A { static readonly t = 9; static url: URL; }',
/*5*/' const enum E { A = 9, B = A + 1 }',
/*6*/' const x = f + A.t + A.url.origin;',
/*7*/'</script>',
/*8*/'</head>',
/*9*/'</html>',
];
assertTokens(input, [
t(3, 8, 1, 'variable.declaration.readonly'),
t(4, 8, 1, 'class.declaration'), t(4, 28, 1, 'property.declaration.static.readonly'), t(4, 42, 3, 'property.declaration.static'), t(4, 47, 3, 'interface'),
t(6, 8, 1, 'variable.declaration.readonly'), t(6, 12, 1, 'variable.readonly'), t(6, 16, 1, 'class'), t(6, 18, 1, 'property.static.readonly'), t(6, 22, 1, 'class'), t(6, 24, 3, 'property.static'), t(6, 28, 6, 'property.readonly'),
]);
});
......@@ -154,9 +174,9 @@ suite('HTML Semantic Tokens', () => {
/*9*/'</html>',
];
assertTokens(input, [
t(3, 7, 5, 'type.declaration'), t(3, 15, 3, 'variable') /* to investiagte */,
t(3, 7, 5, 'type.declaration'), t(3, 15, 3, 'interface') /* to investiagte */,
t(4, 11, 1, 'function.declaration'), t(4, 13, 1, 'typeParameter.declaration'), t(4, 23, 5, 'type'), t(4, 30, 1, 'parameter.declaration'), t(4, 33, 1, 'typeParameter'), t(4, 47, 1, 'typeParameter'),
t(5, 12, 1, 'typeParameter'), t(5, 29, 3, 'variable'), t(5, 41, 5, 'type'),
t(5, 12, 1, 'typeParameter'), t(5, 29, 3, 'interface'), t(5, 41, 5, 'type'),
]);
});
......
......@@ -400,6 +400,7 @@ function registerDefaultClassifications(): void {
tokenClassificationRegistry.registerTokenModifier('deprecated', nls.localize('deprecated', "Style to use for symbols that are deprecated."), undefined);
tokenClassificationRegistry.registerTokenModifier('modification', nls.localize('modification', "Style to use for write accesses."), undefined);
tokenClassificationRegistry.registerTokenModifier('async', nls.localize('async', "Style to use for symbols that are async."), undefined);
tokenClassificationRegistry.registerTokenModifier('readonly', nls.localize('readonly', "Style to use for symbols that are readonly."), undefined);
}
export function getTokenClassificationRegistry(): ITokenClassificationRegistry {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册