Skip to content
This repository was archived by the owner on Nov 21, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Input hashes for repository rule npm_translate_lock(name = "npm", pnpm_lock = "//:pnpm-lock.yaml").
# This file should be checked into version control along with the pnpm-lock.yaml file.
.npmrc=974837034
pnpm-lock.yaml=1493175183
yarn.lock=485928896
package.json=-100959756
pnpm-lock.yaml=1752070694
yarn.lock=1122184668
package.json=991750528
pnpm-workspace.yaml=1711114604
10 changes: 10 additions & 0 deletions client/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ export class AngularLanguageClient implements vscode.Disposable {
}
return next(document, context, token);
},
provideDocumentSemanticTokens: async (document, token, next) => {
if (await this.isInAngularProject(document)) {
return next(document, token);
}
},
provideDocumentRangeSemanticTokens: async (document, range, token, next) => {
if (await this.isInAngularProject(document)) {
return next(document, range, token);
}
},
}
};
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@
"test:legacy-syntaxes": "yarn compile:syntaxes-test && yarn build:syntaxes && jasmine dist/syntaxes/test/driver.js"
},
"dependencies": {
"@angular/language-service": "^20.1.0-next.0",
"@angular/language-service": "20.1.0-rc.0",
"typescript": "^5.8.1",
"vscode-html-languageservice": "^4.2.5",
"vscode-jsonrpc": "6.0.0",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"ngserver": "./bin/ngserver"
},
"dependencies": {
"@angular/language-service": "20.1.0-next.0",
"@angular/language-service": "20.1.0-rc.0",
"vscode-html-languageservice": "^4.2.5",
"vscode-jsonrpc": "6.0.0",
"vscode-languageserver": "7.0.0",
Expand Down
47 changes: 47 additions & 0 deletions server/src/semantic_tokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import { NgLanguageService } from '@angular/language-service/api';
import * as ts from 'typescript/lib/tsserverlibrary';
import * as lsp from 'vscode-languageserver/node';

export function getSemanticTokens(
languageService: NgLanguageService, classifications: ts.Classifications, script: ts.server.ScriptInfo): lsp.SemanticTokens {
const spans = classifications.spans;
const builder = new lsp.SemanticTokensBuilder();

for (let i = 0; i < spans.length;) {
const offset = spans[i++];
const length = spans[i++];
const classification = spans[i++];

const tokenType = languageService.getTokenTypeFromClassification(classification);
if (tokenType === undefined) {
continue;
}

const tokenModifiers = languageService.getTokenModifierFromClassification(classification);

const startPos = script.positionToLineOffset(offset);
startPos.line -= 1;
startPos.offset -= 1;

const endPos = script.positionToLineOffset(offset + length);
endPos.line -= 1;
endPos.offset -= 1;

for (let line = startPos.line; line <= endPos.line; line++) {
const startCharacter = line === startPos.line ? startPos.offset : 0;
const endCharacter =
line === endPos.line ? endPos.offset : script.lineToTextSpan(line - 1).length;
builder.push(line, startCharacter, endCharacter - startCharacter, tokenType, tokenModifiers);
}
}

return builder.build();
}
42 changes: 42 additions & 0 deletions server/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {GetComponentsWithTemplateFile, GetTcbParams, GetTcbRequest, GetTcbRespon
import {readNgCompletionData, tsCompletionEntryToLspCompletionItem} from './completion';
import {tsDiagnosticToLspDiagnostic} from './diagnostic';
import {getHTMLVirtualContent} from './embedded_support';
import {getSemanticTokens} from './semantic_tokens';
import {ServerHost} from './server_host';
import {documentationToMarkdown} from './text_render';
import {filePathToUri, getMappedDefinitionInfo, isConfiguredProject, isDebugMode, lspPositionToTsPosition, lspRangeToTsPositions, MruTracker, tsDisplayPartsToText, tsFileTextChangesToLspWorkspaceEdit, tsTextSpanToLspRange, uriToFilePath} from './utils';
Expand Down Expand Up @@ -217,8 +218,38 @@ export class Session {
conn.onSignatureHelp(p => this.onSignatureHelp(p));
conn.onCodeAction(p => this.onCodeAction(p));
conn.onCodeActionResolve(async p => await this.onCodeActionResolve(p));
conn.onRequest(lsp.SemanticTokensRequest.type, p => this.onSemanticTokensRequest(p));
conn.onRequest(lsp.SemanticTokensRangeRequest.type, p => this.onSemanticTokensRangeRequest(p));
}

private onSemanticTokensRequest(params: lsp.SemanticTokensParams): lsp.SemanticTokens|null {
const lsInfo = this.getLSAndScriptInfo(params.textDocument);
if (lsInfo === null) {
return null;
}
const {languageService, scriptInfo} = lsInfo;
const span = {start: 0, length: scriptInfo.getSnapshot().getLength()};
const classifications = languageService.getEncodedSemanticClassifications(
scriptInfo.fileName, span, ts.SemanticClassificationFormat.TwentyTwenty);
return getSemanticTokens(languageService, classifications, scriptInfo);
}

private onSemanticTokensRangeRequest(params: lsp.SemanticTokensRangeParams): lsp.SemanticTokens
|null {
const lsInfo = this.getLSAndScriptInfo(params.textDocument);
if (lsInfo === null) {
return null;
}
const {languageService, scriptInfo} = lsInfo;
const start = lspPositionToTsPosition(lsInfo.scriptInfo, params.range.start);
const end = lspPositionToTsPosition(lsInfo.scriptInfo, params.range.end);
const span = {start, length: end - start};
const classifications = languageService.getEncodedSemanticClassifications(
scriptInfo.fileName, span, ts.SemanticClassificationFormat.TwentyTwenty);
return getSemanticTokens(languageService, classifications, scriptInfo);
}


private onCodeAction(params: lsp.CodeActionParams): lsp.CodeAction[]|null {
const filePath = uriToFilePath(params.textDocument.uri);
const lsInfo = this.getLSAndScriptInfo(params.textDocument);
Expand Down Expand Up @@ -809,6 +840,17 @@ export class Session {
// [here](https://github.com/angular/vscode-ng-language-service/issues/1828)
codeActionKinds: [lsp.CodeActionKind.QuickFix],
},
semanticTokensProvider: {
documentSelector: null,
legend: {
tokenTypes: [
'class',
],
tokenModifiers: [],
},
full: true,
range: true
}
},
serverOptions,
};
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,10 @@
uuid "^8.3.2"
yargs "^17.0.0"

"@angular/language-service@^20.1.0-next.0":
version "20.1.0-next.0"
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-20.1.0-next.0.tgz#d294576dee2c2be966020a8dc8ef0bc073e71487"
integrity sha512-CH2Oj7ytaEXl/4W0CzCgO3gC71uzU+gHOnM8NdAnM0ccEjzOeq1ty0PaQzQbf2psKed7V0KRfpWT+0xOO38V4A==
"@angular/[email protected]rc.0":
version "20.1.0-rc.0"
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-20.1.0-rc.0.tgz#6d4e8a45e6716410778f42ce8c0d54e3e7912d02"
integrity sha512-8iXIiBGOD4fUulzhH1yEZIQhlwTsY3Kbj1N8wpS1uV1sH2DSgHNq4WR5k3fQYUx7VYbF3VyTCjdBzjh7s2Xcsg==

"@assemblyscript/loader@^0.10.1":
version "0.10.1"
Expand Down
Loading