diff --git a/client/src/client.ts b/client/src/client.ts index e65aafa377..7db50bdc34 100644 --- a/client/src/client.ts +++ b/client/src/client.ts @@ -13,7 +13,7 @@ import * as lsp from 'vscode-languageclient/node'; import {ProjectLoadingFinish, ProjectLoadingStart, SuggestStrictMode, SuggestStrictModeParams} from '../common/notifications'; import {NgccProgress, NgccProgressToken, NgccProgressType} from '../common/progress'; -import {GetComponentsWithTemplateFile, GetTcbRequest, IsInAngularProject} from '../common/requests'; +import {GetComponentsWithTemplateFile, GetTcbRequest, GetTemplateLocationForComponent, IsInAngularProject} from '../common/requests'; import {resolve, Version} from '../common/resolver'; import {isInsideComponentDecorator, isInsideInlineTemplateRegion, isInsideStringLiteral} from './embedded_support'; @@ -290,6 +290,26 @@ export class AngularLanguageClient implements vscode.Disposable { v => new vscode.Location(p2cConverter.asUri(v.uri), p2cConverter.asRange(v.range))); } + async getTemplateLocationForComponent(textEditor: vscode.TextEditor): + Promise { + if (this.client === null) { + return undefined; + } + const c2pConverter = this.client.code2ProtocolConverter; + // Craft a request by converting vscode params to LSP. The corresponding + // response is in LSP. + const response = await this.client.sendRequest(GetTemplateLocationForComponent, { + textDocument: c2pConverter.asTextDocumentIdentifier(textEditor.document), + position: c2pConverter.asPosition(textEditor.selection.active), + }); + if (response === null) { + return undefined; + } + const p2cConverter = this.client.protocol2CodeConverter; + return new vscode.Location( + p2cConverter.asUri(response.uri), p2cConverter.asRange(response.range)); + } + dispose() { for (let d = this.disposables.pop(); d !== undefined; d = this.disposables.pop()) { d.dispose(); diff --git a/client/src/commands.ts b/client/src/commands.ts index 8c815b3d4b..1dc634cbac 100644 --- a/client/src/commands.ts +++ b/client/src/commands.ts @@ -141,6 +141,32 @@ function goToComponentWithTemplateFile(ngClient: AngularLanguageClient): Command }; } +/** + * Command goToTemplateForComponent finds the template for a component. + * + * @param ngClient LSP client for the active session + */ +function goToTemplateForComponent(ngClient: AngularLanguageClient): Command { + return { + id: 'angular.goToTemplateForComponent', + isTextEditorCommand: true, + async execute(textEditor: vscode.TextEditor) { + const location = await ngClient.getTemplateLocationForComponent(textEditor); + if (location === undefined) { + return; + } + + vscode.commands.executeCommand( + 'editor.action.goToLocations', + textEditor.document.uri, + textEditor.selection.active, + [location], + 'goto', /** What to do when there are multiple results (there can't be) */ + ); + }, + }; +} + /** * Register all supported vscode commands for the Angular extension. * @param client language client @@ -153,6 +179,7 @@ export function registerCommands( openLogFile(client), getTemplateTcb(client, context), goToComponentWithTemplateFile(client), + goToTemplateForComponent(client), ]; for (const command of commands) { diff --git a/package.json b/package.json index f14ad50533..689e121cff 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,11 @@ "command": "angular.goToComponentWithTemplateFile", "title": "Go to component", "category": "Angular" + }, + { + "command": "angular.goToTemplateForComponent", + "title": "Go to template", + "category": "Angular" } ], "menus": { @@ -50,6 +55,10 @@ { "command": "angular.goToComponentWithTemplateFile", "when": "editorLangId == html" + }, + { + "command": "angular.goToTemplateForComponent", + "when": "editorLangId == typescript" } ], "editor/context": [ @@ -62,6 +71,11 @@ "when": "resourceLangId == html", "command": "angular.goToComponentWithTemplateFile", "group": "angular" + }, + { + "when": "resourceLangId == typescript", + "command": "angular.goToTemplateForComponent", + "group": "angular" } ] }, @@ -169,7 +183,7 @@ "test:syntaxes": "yarn compile:syntaxes-test && yarn build:syntaxes && jasmine dist/syntaxes/test/driver.js" }, "dependencies": { - "@angular/language-service": "13.0.0-next.2", + "@angular/language-service": "13.0.0-next.3", "typescript": "4.3.4", "vscode-jsonrpc": "6.0.0", "vscode-languageclient": "7.0.0", @@ -197,4 +211,4 @@ "type": "git", "url": "https://github.com/angular/vscode-ng-language-service" } -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index e2ecdafd4b..6e40c69d9a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -52,10 +52,10 @@ yaml "^1.10.0" yargs "^17.0.0" -"@angular/language-service@13.0.0-next.2": - version "13.0.0-next.2" - resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-13.0.0-next.2.tgz#4027291ea734195f8518e2ea022c306b9127f49a" - integrity sha512-zgzUrpQFzxRH9YFV0Fk21zu7bYpKn5lgeGtUyqgL23fi7BdjuXXyKiB7cnT+xxT4U5yNRlIq4mDQGJRscDvOMg== +"@angular/language-service@13.0.0-next.3": + version "13.0.0-next.3" + resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-13.0.0-next.3.tgz#80aa3c0f0c1bfeabb04b11ba1a889461f0979cfc" + integrity sha512-etqLlMX0twVI2lZZhS4Kt3gEOmqq4FiAXEMSmpklJaXqKa4qVUrOqjgkNeAXr3vw/d/Knb4DVn7AQiIUoNNLgg== "@babel/code-frame@^7.0.0": version "7.12.13"