Skip to content

Commit 98d5c97

Browse files
committed
fix: only give html provider completions for inline templates (#1369)
Our client-side middleware retrieves html provider completions for inline templates because the template string is not otherwise detected as HTML by the registered HTML providers. We should only create this virtual document and retrieve HTML provider results for typescript files. Fixes #1357 (cherry picked from commit e1a7137)
1 parent eb8d25c commit 98d5c97

File tree

5 files changed

+70
-17
lines changed

5 files changed

+70
-17
lines changed

client/src/client.ts

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,18 @@ export class AngularLanguageClient implements vscode.Disposable {
8888

8989
const angularResultsPromise = next(document, position, token);
9090

91-
const vdocUri = this.createVirtualHtmlDoc(document);
92-
const htmlProviderResultsPromise = vscode.commands.executeCommand<vscode.Hover[]>(
93-
'vscode.executeHoverProvider', vdocUri, position);
91+
// Include results for inline HTML via virtual document and native html providers.
92+
if (document.languageId === 'typescript') {
93+
const vdocUri = this.createVirtualHtmlDoc(document);
94+
const htmlProviderResultsPromise = vscode.commands.executeCommand<vscode.Hover[]>(
95+
'vscode.executeHoverProvider', vdocUri, position);
96+
97+
const [angularResults, htmlProviderResults] =
98+
await Promise.all([angularResultsPromise, htmlProviderResultsPromise]);
99+
return angularResults ?? htmlProviderResults?.[0];
100+
}
94101

95-
const [angularResults, htmlProviderResults] =
96-
await Promise.all([angularResultsPromise, htmlProviderResultsPromise]);
97-
return angularResults ?? htmlProviderResults?.[0];
102+
return angularResultsPromise;
98103
},
99104
provideSignatureHelp: async (
100105
document: vscode.TextDocument, position: vscode.Position,
@@ -117,17 +122,21 @@ export class AngularLanguageClient implements vscode.Disposable {
117122
const angularCompletionsPromise = next(document, position, context, token) as
118123
Promise<vscode.CompletionItem[]|null|undefined>;
119124

120-
const vdocUri = this.createVirtualHtmlDoc(document);
121-
// This will not include angular stuff because the vdoc is not associated with an angular
122-
// component
123-
const htmlProviderCompletionsPromise =
124-
vscode.commands.executeCommand<vscode.CompletionList>(
125-
'vscode.executeCompletionItemProvider', vdocUri, position,
126-
context.triggerCharacter);
127-
const [angularCompletions, htmlProviderCompletions] =
128-
await Promise.all([angularCompletionsPromise, htmlProviderCompletionsPromise]);
129-
130-
return [...(angularCompletions ?? []), ...(htmlProviderCompletions?.items ?? [])];
125+
// Include results for inline HTML via virtual document and native html providers.
126+
if (document.languageId === 'typescript') {
127+
const vdocUri = this.createVirtualHtmlDoc(document);
128+
// This will not include angular stuff because the vdoc is not associated with an
129+
// angular component
130+
const htmlProviderCompletionsPromise =
131+
vscode.commands.executeCommand<vscode.CompletionList>(
132+
'vscode.executeCompletionItemProvider', vdocUri, position,
133+
context.triggerCharacter);
134+
const [angularCompletions, htmlProviderCompletions] =
135+
await Promise.all([angularCompletionsPromise, htmlProviderCompletionsPromise]);
136+
return [...(angularCompletions ?? []), ...(htmlProviderCompletions?.items ?? [])];
137+
}
138+
139+
return angularCompletionsPromise;
131140
}
132141
}
133142
};

integration/e2e/completion_spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
import * as vscode from 'vscode';
3+
4+
import {activate, COMPLETION_COMMAND, FOO_TEMPLATE_URI} from './helper';
5+
6+
describe('Angular Ivy LS completions', () => {
7+
beforeAll(async () => {
8+
await activate(FOO_TEMPLATE_URI);
9+
});
10+
11+
it(`does not duplicate HTML completions in external templates`, async () => {
12+
const position = new vscode.Position(0, 0);
13+
const completionItem = await vscode.commands.executeCommand<vscode.CompletionList>(
14+
COMPLETION_COMMAND, FOO_TEMPLATE_URI, position);
15+
const regionCompletions = (completionItem?.items?.filter(i => i.label === '#region') ?? []);
16+
expect(regionCompletions.length).toBe(1);
17+
});
18+
});

integration/e2e/helper.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
import * as vscode from 'vscode';
2+
import {APP_COMPONENT, FOO_TEMPLATE} from '../test_constants';
3+
4+
export const COMPLETION_COMMAND = 'vscode.executeCompletionItemProvider';
5+
export const HOVER_COMMAND = 'vscode.executeHoverProvider';
6+
export const DEFINITION_COMMAND = 'vscode.executeDefinitionProvider';
7+
export const APP_COMPONENT_URI = vscode.Uri.file(APP_COMPONENT);
8+
export const FOO_TEMPLATE_URI = vscode.Uri.file(FOO_TEMPLATE);
29

310
function sleep(ms: number) {
411
return new Promise(resolve => setTimeout(resolve, ms));

integration/e2e/hover_spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import * as vscode from 'vscode';
2+
3+
import {activate, FOO_TEMPLATE_URI, HOVER_COMMAND} from './helper';
4+
5+
describe('Angular Ivy LS quick info', () => {
6+
beforeAll(async () => {
7+
await activate(FOO_TEMPLATE_URI);
8+
});
9+
10+
it(`returns quick info from built in extension for class in template`, async () => {
11+
const position = new vscode.Position(1, 8);
12+
const quickInfo = await vscode.commands.executeCommand<vscode.Hover[]>(
13+
HOVER_COMMAND, FOO_TEMPLATE_URI, position);
14+
expect(quickInfo?.length).toBe(1);
15+
});
16+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
{{title | uppercase}}
2+
<span class="subtitle">
3+
subtitle
4+
</span>

0 commit comments

Comments
 (0)