mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-23 01:58:53 +01:00
only map when necessary
This commit is contained in:
@@ -7,8 +7,8 @@ import { SemanticTokenData, Range, TextDocument, LanguageModes, Position } from
|
||||
import { beforeOrSame } from '../utils/positions';
|
||||
|
||||
interface LegendMapping {
|
||||
types: number[];
|
||||
modifiers: number[];
|
||||
types: number[] | undefined;
|
||||
modifiers: number[] | undefined;
|
||||
}
|
||||
|
||||
export interface SemanticTokenProvider {
|
||||
@@ -19,78 +19,84 @@ export interface SemanticTokenProvider {
|
||||
|
||||
export function newSemanticTokenProvider(languageModes: LanguageModes): SemanticTokenProvider {
|
||||
|
||||
// build legend across language
|
||||
const types: string[] = [];
|
||||
const modifiers: string[] = [];
|
||||
|
||||
// combined legend across modes
|
||||
const legend = { types: [], modifiers: [] };
|
||||
const legendMappings: { [modeId: string]: LegendMapping } = {};
|
||||
|
||||
for (let mode of languageModes.getAllModes()) {
|
||||
if (mode.getSemanticTokenLegend && mode.getSemanticTokens) {
|
||||
const legend = mode.getSemanticTokenLegend();
|
||||
const legendMapping: LegendMapping = { types: [], modifiers: [] };
|
||||
for (let type of legend.types) {
|
||||
let index = types.indexOf(type);
|
||||
if (index === -1) {
|
||||
index = types.length;
|
||||
types.push(type);
|
||||
}
|
||||
legendMapping.types.push(index);
|
||||
}
|
||||
for (let modifier of legend.modifiers) {
|
||||
let index = modifiers.indexOf(modifier);
|
||||
if (index === -1) {
|
||||
index = modifiers.length;
|
||||
modifiers.push(modifier);
|
||||
}
|
||||
legendMapping.modifiers.push(index);
|
||||
}
|
||||
legendMappings[mode.getId()] = legendMapping;
|
||||
const modeLegend = mode.getSemanticTokenLegend();
|
||||
legendMappings[mode.getId()] = { types: createMapping(modeLegend.types, legend.types), modifiers: createMapping(modeLegend.modifiers, legend.modifiers) };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
legend: { types, modifiers },
|
||||
legend,
|
||||
getSemanticTokens(document: TextDocument, ranges?: Range[]): number[] {
|
||||
const allTokens: SemanticTokenData[] = [];
|
||||
for (let mode of languageModes.getAllModesInDocument(document)) {
|
||||
if (mode.getSemanticTokens) {
|
||||
const mapping = legendMappings[mode.getId()];
|
||||
const tokens = mode.getSemanticTokens(document);
|
||||
applyTypesMapping(tokens, mapping.types);
|
||||
applyModifiersMapping(tokens, mapping.modifiers);
|
||||
for (let token of tokens) {
|
||||
allTokens.push(applyMapping(token, mapping));
|
||||
allTokens.push(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
return encodeAndFilterTokens(allTokens, ranges);
|
||||
return encodeTokens(allTokens, ranges);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function applyMapping(token: SemanticTokenData, legendMapping: LegendMapping): SemanticTokenData {
|
||||
token.typeIdx = legendMapping.types[token.typeIdx];
|
||||
|
||||
let modifierSet = token.modifierSet;
|
||||
if (modifierSet) {
|
||||
let index = 0;
|
||||
let result = 0;
|
||||
const mapping = legendMapping.modifiers;
|
||||
while (modifierSet > 0) {
|
||||
if ((modifierSet & 1) !== 0) {
|
||||
result = result + (1 << mapping[index]);
|
||||
}
|
||||
index++;
|
||||
modifierSet = modifierSet >> 1;
|
||||
function createMapping(origLegend: string[], newLegend: string[]): number[] | undefined {
|
||||
const mapping: number[] = [];
|
||||
let needsMapping = false;
|
||||
for (let origIndex = 0; origIndex < origLegend.length; origIndex++) {
|
||||
const entry = origLegend[origIndex];
|
||||
let newIndex = newLegend.indexOf(entry);
|
||||
if (newIndex === -1) {
|
||||
newIndex = newLegend.length;
|
||||
newLegend.push(entry);
|
||||
}
|
||||
mapping.push(newIndex);
|
||||
needsMapping = needsMapping || (newIndex !== origIndex);
|
||||
}
|
||||
return needsMapping ? mapping : undefined;
|
||||
}
|
||||
|
||||
function applyTypesMapping(tokens: SemanticTokenData[], typesMapping: number[] | undefined): void {
|
||||
if (typesMapping) {
|
||||
for (let token of tokens) {
|
||||
token.typeIdx = typesMapping[token.typeIdx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applyModifiersMapping(tokens: SemanticTokenData[], modifiersMapping: number[] | undefined): void {
|
||||
if (modifiersMapping) {
|
||||
for (let token of tokens) {
|
||||
let modifierSet = token.modifierSet;
|
||||
if (modifierSet) {
|
||||
let index = 0;
|
||||
let result = 0;
|
||||
while (modifierSet > 0) {
|
||||
if ((modifierSet & 1) !== 0) {
|
||||
result = result + (1 << modifiersMapping[index]);
|
||||
}
|
||||
index++;
|
||||
modifierSet = modifierSet >> 1;
|
||||
}
|
||||
token.modifierSet = result;
|
||||
}
|
||||
}
|
||||
token.modifierSet = result;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
const fullRange = [Range.create(Position.create(0, 0), Position.create(Number.MAX_VALUE, 0))];
|
||||
|
||||
function encodeAndFilterTokens(tokens: SemanticTokenData[], ranges?: Range[]): number[] {
|
||||
function encodeTokens(tokens: SemanticTokenData[], ranges?: Range[]): number[] {
|
||||
|
||||
const resultTokens = tokens.sort((d1, d2) => d1.start.line - d2.start.line || d1.start.character - d2.start.character);
|
||||
if (ranges) {
|
||||
@@ -131,5 +137,3 @@ function encodeAndFilterTokens(tokens: SemanticTokenData[], ranges?: Range[]): n
|
||||
}
|
||||
return encodedResult;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user