mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-26 03:29:00 +01:00
[html] add semantic highlight
This commit is contained in:
@@ -6,10 +6,10 @@
|
||||
import {
|
||||
createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, RequestType,
|
||||
DocumentRangeFormattingRequest, Disposable, DocumentSelector, TextDocumentPositionParams, ServerCapabilities,
|
||||
Position, ConfigurationRequest, ConfigurationParams, DidChangeWorkspaceFoldersNotification,
|
||||
Position, ConfigurationRequest, ConfigurationParams, DidChangeWorkspaceFoldersNotification, Range,
|
||||
WorkspaceFolder, DocumentColorRequest, ColorInformation, ColorPresentationRequest, TextDocumentSyncKind
|
||||
} from 'vscode-languageserver';
|
||||
import { TextDocument, Diagnostic, DocumentLink, SymbolInformation } from 'vscode-html-languageservice';
|
||||
import { TextDocument, Diagnostic, DocumentLink, SymbolInformation, TextDocumentIdentifier } from 'vscode-html-languageservice';
|
||||
import { getLanguageModes, LanguageModes, Settings } from './modes/languageModes';
|
||||
|
||||
import { format } from './modes/formatting';
|
||||
@@ -29,6 +29,18 @@ namespace MatchingTagPositionRequest {
|
||||
export const type: RequestType<TextDocumentPositionParams, Position | null, any, any> = new RequestType('html/matchingTagPosition');
|
||||
}
|
||||
|
||||
// experimental: semantic tokens
|
||||
interface SemanticTokenParams {
|
||||
textDocument: TextDocumentIdentifier;
|
||||
ranges?: Range[];
|
||||
}
|
||||
namespace SemanticTokenRequest {
|
||||
export const type: RequestType<SemanticTokenParams, number[] | null, any, any> = new RequestType('html/semanticTokens');
|
||||
}
|
||||
namespace SemanticTokenLegendRequest {
|
||||
export const type: RequestType<void, { types: string[]; modifiers: string[] } | null, any, any> = new RequestType('html/semanticTokenLegend');
|
||||
}
|
||||
|
||||
// Create a connection for the server
|
||||
const connection: IConnection = createConnection();
|
||||
|
||||
@@ -500,5 +512,45 @@ connection.onRequest(MatchingTagPositionRequest.type, (params, token) => {
|
||||
}, null, `Error while computing matching tag position for ${params.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
connection.onRequest(MatchingTagPositionRequest.type, (params, token) => {
|
||||
return runSafe(() => {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
const pos = params.position;
|
||||
if (pos.character > 0) {
|
||||
const mode = languageModes.getModeAtPosition(document, Position.create(pos.line, pos.character - 1));
|
||||
if (mode && mode.findMatchingTagPosition) {
|
||||
return mode.findMatchingTagPosition(document, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, null, `Error while computing matching tag position for ${params.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
connection.onRequest(SemanticTokenRequest.type, (params, token) => {
|
||||
return runSafe(() => {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
const jsMode = languageModes.getMode('javascript');
|
||||
if (jsMode && jsMode.getSemanticTokens) {
|
||||
return jsMode.getSemanticTokens(document, params.ranges);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, null, `Error while computing semantic tokens for ${params.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
connection.onRequest(SemanticTokenLegendRequest.type, (_params, token) => {
|
||||
return runSafe(() => {
|
||||
const jsMode = languageModes.getMode('javascript');
|
||||
if (jsMode && jsMode.getSemanticTokenLegend) {
|
||||
return jsMode.getSemanticTokenLegend();
|
||||
}
|
||||
return null;
|
||||
}, null, `Error while computing semantic tokens legend`, token);
|
||||
});
|
||||
|
||||
|
||||
// Listen on the connection
|
||||
connection.listen();
|
||||
|
||||
@@ -314,6 +314,44 @@ export function getJavaScriptMode(documentRegions: LanguageModelCache<HTMLDocume
|
||||
onDocumentRemoved(document: TextDocument) {
|
||||
jsDocuments.onDocumentRemoved(document);
|
||||
},
|
||||
getSemanticTokens(document: TextDocument, ranges: Range[] | undefined): number[] {
|
||||
updateCurrentTextDocument(document);
|
||||
if (!ranges) {
|
||||
ranges = [Range.create(Position.create(0, 0), document.positionAt(document.getText().length))];
|
||||
}
|
||||
const result = [];
|
||||
|
||||
for (let range of ranges) {
|
||||
const start = document.offsetAt(range.start), length = document.offsetAt(range.end) - start;
|
||||
const tokens = jsLanguageService.getSemanticClassifications(FILE_NAME, { start, length });
|
||||
|
||||
let prefLine = 0;
|
||||
let prevChar = 0;
|
||||
|
||||
for (let token of tokens) {
|
||||
const m = tokenMapping[token.classificationType];
|
||||
if (m) {
|
||||
const startPos = document.positionAt(token.textSpan.start);
|
||||
if (prefLine !== startPos.line) {
|
||||
prevChar = 0;
|
||||
}
|
||||
result.push(startPos.line - prefLine); // line delta
|
||||
result.push(startPos.character - prevChar); // line delta
|
||||
result.push(token.textSpan.length); // lemgth
|
||||
result.push(tokenTypes.indexOf(m)); // tokenType
|
||||
result.push(0); // tokenModifier
|
||||
|
||||
prefLine = startPos.line;
|
||||
prevChar = startPos.character;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
getSemanticTokenLegend(): { types: string[], modifiers: string[] } {
|
||||
return { types: tokenTypes, modifiers: tokenModifiers };
|
||||
},
|
||||
dispose() {
|
||||
jsLanguageService.dispose();
|
||||
jsDocuments.dispose();
|
||||
@@ -321,6 +359,20 @@ export function getJavaScriptMode(documentRegions: LanguageModelCache<HTMLDocume
|
||||
};
|
||||
}
|
||||
|
||||
const tokenTypes: string[] = ['classes', 'enums', 'interfaces', 'namespaces', 'parameterTypes', 'types', 'parameters'];
|
||||
const tokenModifiers: string[] = [];
|
||||
const tokenMapping: { [name: string]: string } = {
|
||||
[ts.ClassificationTypeNames.className]: 'classes',
|
||||
[ts.ClassificationTypeNames.enumName]: 'enums',
|
||||
[ts.ClassificationTypeNames.interfaceName]: 'interfaces',
|
||||
[ts.ClassificationTypeNames.moduleName]: 'namespaces',
|
||||
[ts.ClassificationTypeNames.typeParameterName]: 'parameterTypes',
|
||||
[ts.ClassificationTypeNames.typeAliasName]: 'types',
|
||||
[ts.ClassificationTypeNames.parameterName]: 'parameters'
|
||||
};
|
||||
|
||||
|
||||
|
||||
function convertRange(document: TextDocument, span: { start: number | undefined, length: number | undefined }): Range {
|
||||
if (typeof span.start === 'undefined') {
|
||||
const pos = document.positionAt(0);
|
||||
|
||||
@@ -51,6 +51,8 @@ export interface LanguageMode {
|
||||
findMatchingTagPosition?: (document: TextDocument, position: Position) => Position | null;
|
||||
getFoldingRanges?: (document: TextDocument) => FoldingRange[];
|
||||
onDocumentRemoved(document: TextDocument): void;
|
||||
getSemanticTokens?(document: TextDocument, ranges: Range[] | undefined): number[];
|
||||
getSemanticTokenLegend?(): { types: string[], modifiers: string[] };
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user