Skip to content

Commit a0be535

Browse files
committed
feat: provide snippets for attribute
1 parent f18b5ac commit a0be535

File tree

11 files changed

+95
-10
lines changed

11 files changed

+95
-10
lines changed

client/src/client.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,12 @@ function constructArgs(ctx: vscode.ExtensionContext): string[] {
454454
args.push('--includeAutomaticOptionalChainCompletions');
455455
}
456456

457+
const includeCompletionsWithSnippetText =
458+
config.get<boolean>('angular.suggest.includeCompletionsWithSnippetText');
459+
if (includeCompletionsWithSnippetText) {
460+
args.push('--includeCompletionsWithSnippetText');
461+
}
462+
457463
const tsdk: string|null = config.get('typescript.tsdk', null);
458464
const tsProbeLocations = getProbeLocations(tsdk, ctx.extensionPath);
459465
args.push('--tsProbeLocations', tsProbeLocations.join(','));

integration/lsp/ivy_spec.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,62 @@ describe('auto-apply optional chaining', () => {
572572
});
573573
});
574574

575+
describe('insert snippet text', () => {
576+
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; /* 10 seconds */
577+
578+
let client: MessageConnection;
579+
beforeEach(async () => {
580+
client = createConnection({
581+
ivy: true,
582+
includeCompletionsWithSnippetText: true,
583+
});
584+
// If debugging, set to
585+
// - lsp.Trace.Messages to inspect request/response/notification, or
586+
// - lsp.Trace.Verbose to inspect payload
587+
client.trace(lsp.Trace.Off, createTracer());
588+
client.listen();
589+
await initializeServer(client);
590+
});
591+
592+
afterEach(() => {
593+
client.dispose();
594+
});
595+
596+
it('should be able to complete for an attribute with the value is empty', async () => {
597+
openTextDocument(client, FOO_TEMPLATE, `<my-app appOut></my-app>`);
598+
const languageServiceEnabled = await waitForNgcc(client);
599+
expect(languageServiceEnabled).toBeTrue();
600+
const response = await client.sendRequest(lsp.CompletionRequest.type, {
601+
textDocument: {
602+
uri: FOO_TEMPLATE_URI,
603+
},
604+
position: {line: 0, character: 14},
605+
}) as lsp.CompletionItem[];
606+
const completion = response.find(i => i.label === '(appOutput)')!;
607+
expect(completion.kind).toEqual(lsp.CompletionItemKind.Event);
608+
expect(completion.insertText).toEqual('(appOutput)="$1"');
609+
expect(completion.insertTextFormat).toEqual(lsp.InsertTextFormat.Snippet);
610+
expect((completion.textEdit as lsp.TextEdit).newText).toEqual('appOut');
611+
});
612+
613+
it('should not be included in the completion for an attribute with a value', async () => {
614+
openTextDocument(client, FOO_TEMPLATE, `<my-app [appInput]="1"></my-app>`);
615+
const languageServiceEnabled = await waitForNgcc(client);
616+
expect(languageServiceEnabled).toBeTrue();
617+
const response = await client.sendRequest(lsp.CompletionRequest.type, {
618+
textDocument: {
619+
uri: FOO_TEMPLATE_URI,
620+
},
621+
position: {line: 0, character: 17},
622+
}) as lsp.CompletionItem[];
623+
const completion = response.find(i => i.label === '[appInput]')!;
624+
expect(completion.kind).toEqual(lsp.CompletionItemKind.Property);
625+
expect(completion.insertText).toBeUndefined;
626+
expect(completion.insertTextFormat).toBeUndefined;
627+
expect((completion.textEdit as lsp.TextEdit).newText).toEqual('appInput');
628+
});
629+
});
630+
575631
function onNgccProgress(client: MessageConnection): Promise<string> {
576632
return new Promise(resolve => {
577633
client.onProgress(NgccProgressType, NgccProgressToken, (params: NgccProgress) => {

integration/lsp/test_utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {PROJECT_PATH, SERVER_PATH} from '../test_constants';
1616
export interface ServerOptions {
1717
ivy: boolean;
1818
includeAutomaticOptionalChainCompletions?: boolean;
19+
includeCompletionsWithSnippetText?: boolean;
1920
}
2021

2122
export function createConnection(serverOptions: ServerOptions): MessageConnection {

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@
118118
"type": "boolean",
119119
"default": true,
120120
"description": "Enable/disable showing completions on potentially undefined values that insert an optional chain call. Requires TS 3.7+ and strict null checks to be enabled."
121+
},
122+
"angular.suggest.includeCompletionsWithSnippetText": {
123+
"type": "boolean",
124+
"default": true,
125+
"description": "Enable/disable snippet completions from angular language Server. Requires using TypeScript 4.3+ in the workspace."
121126
}
122127
}
123128
},
@@ -183,7 +188,7 @@
183188
"test:syntaxes": "yarn compile:syntaxes-test && yarn build:syntaxes && jasmine dist/syntaxes/test/driver.js"
184189
},
185190
"dependencies": {
186-
"@angular/language-service": "13.0.0-next.3",
191+
"@angular/language-service": "13.0.0-next.12",
187192
"typescript": "4.4.3",
188193
"vscode-jsonrpc": "6.0.0",
189194
"vscode-languageclient": "7.0.0",

server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"ngserver": "./bin/ngserver"
1616
},
1717
"dependencies": {
18-
"@angular/language-service": "13.0.0-next.3",
18+
"@angular/language-service": "13.0.0-next.12",
1919
"vscode-jsonrpc": "6.0.0",
2020
"vscode-languageserver": "7.0.0",
2121
"vscode-uri": "3.0.2"

server/src/cmdline_utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ interface CommandLineOptions {
3838
ngProbeLocations: string[];
3939
tsProbeLocations: string[];
4040
includeAutomaticOptionalChainCompletions: boolean;
41+
includeCompletionsWithSnippetText: boolean;
4142
}
4243

4344
export function parseCommandLine(argv: string[]): CommandLineOptions {
@@ -51,6 +52,7 @@ export function parseCommandLine(argv: string[]): CommandLineOptions {
5152
tsProbeLocations: parseStringArray(argv, '--tsProbeLocations'),
5253
includeAutomaticOptionalChainCompletions:
5354
hasArgument(argv, '--includeAutomaticOptionalChainCompletions'),
55+
includeCompletionsWithSnippetText: hasArgument(argv, '--includeCompletionsWithSnippetText'),
5456
};
5557
}
5658

server/src/completion.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ export function tsCompletionEntryToLspCompletionItem(
125125
// range will include the dot. the `insertText` should be assigned to the `filterText` to filter
126126
// the completion items.
127127
item.filterText = entry.insertText;
128+
if (entry.isSnippet) {
129+
item.insertTextFormat = lsp.InsertTextFormat.Snippet;
130+
}
128131
}
129132

130133
item.data = {

server/src/server.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ function main() {
4444
resolvedNgLsPath: ng.resolvedPath,
4545
ivy: isG3 ? true : options.ivy,
4646
logToConsole: options.logToConsole,
47-
includeAutomaticOptionalChainCompletions: options.includeAutomaticOptionalChainCompletions
47+
includeAutomaticOptionalChainCompletions: options.includeAutomaticOptionalChainCompletions,
48+
includeCompletionsWithSnippetText: options.includeCompletionsWithSnippetText,
4849
});
4950

5051
// Log initialization info

server/src/session.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export interface SessionOptions {
3131
ivy: boolean;
3232
logToConsole: boolean;
3333
includeAutomaticOptionalChainCompletions: boolean;
34+
includeCompletionsWithSnippetText: boolean;
3435
}
3536

3637
enum LanguageId {
@@ -55,6 +56,8 @@ export class Session {
5556
private readonly logToConsole: boolean;
5657
private readonly openFiles = new MruTracker();
5758
private readonly includeAutomaticOptionalChainCompletions: boolean;
59+
private readonly includeCompletionsWithSnippetText: boolean;
60+
private snippetSupport: boolean|undefined;
5861
// Tracks the spawn order and status of the `ngcc` processes. This allows us to ensure we enable
5962
// the LS in the same order the projects were created in.
6063
private projectNgccQueue: Array<{project: ts.server.Project, done: boolean}> = [];
@@ -72,6 +75,7 @@ export class Session {
7275
constructor(options: SessionOptions) {
7376
this.includeAutomaticOptionalChainCompletions =
7477
options.includeAutomaticOptionalChainCompletions;
78+
this.includeCompletionsWithSnippetText = options.includeCompletionsWithSnippetText;
7579
this.logger = options.logger;
7680
this.ivy = options.ivy;
7781
this.logToConsole = options.logToConsole;
@@ -605,6 +609,8 @@ export class Session {
605609
}
606610

607611
private onInitialize(params: lsp.InitializeParams): lsp.InitializeResult {
612+
this.snippetSupport =
613+
params.capabilities.textDocument?.completion?.completionItem?.snippetSupport;
608614
const serverOptions: ServerOptions = {
609615
logFile: this.logger.getLogFileName(),
610616
};
@@ -1007,10 +1013,14 @@ export class Session {
10071013
const offset = lspPositionToTsPosition(scriptInfo, params.position);
10081014

10091015
let options: ts.GetCompletionsAtPositionOptions = {};
1010-
if (this.includeAutomaticOptionalChainCompletions) {
1016+
const includeCompletionsWithSnippetText =
1017+
this.includeCompletionsWithSnippetText && this.snippetSupport;
1018+
if (this.includeAutomaticOptionalChainCompletions || includeCompletionsWithSnippetText) {
10111019
options = {
10121020
includeAutomaticOptionalChainCompletions: this.includeAutomaticOptionalChainCompletions,
1013-
includeCompletionsWithInsertText: this.includeAutomaticOptionalChainCompletions,
1021+
includeCompletionsWithSnippetText: includeCompletionsWithSnippetText,
1022+
includeCompletionsWithInsertText:
1023+
this.includeAutomaticOptionalChainCompletions || includeCompletionsWithSnippetText,
10141024
};
10151025
}
10161026

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"module": "commonjs",
55
"moduleResolution": "node",
66
"sourceMap": true,
7-
"strict": true
7+
"strict": true,
8+
"esModuleInterop": true
89
},
910
"files": [],
1011
"references": [

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@
5252
yaml "^1.10.0"
5353
yargs "^17.0.0"
5454

55-
"@angular/[email protected].3":
56-
version "13.0.0-next.3"
57-
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-13.0.0-next.3.tgz#80aa3c0f0c1bfeabb04b11ba1a889461f0979cfc"
58-
integrity sha512-etqLlMX0twVI2lZZhS4Kt3gEOmqq4FiAXEMSmpklJaXqKa4qVUrOqjgkNeAXr3vw/d/Knb4DVn7AQiIUoNNLgg==
55+
"@angular/[email protected].12":
56+
version "13.0.0-next.12"
57+
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-13.0.0-next.12.tgz#e080fc9e58af9267d9c97abad15dbef4b8c0ea18"
58+
integrity sha512-YUF/XsQ192tycaOzhYuTWwMx299zIGxENqQ1AVf8rp1TNnfr6csh+7LJ42j60MN44FmYXnIrVRV2+fp3jfhyBA==
5959

6060
"@babel/code-frame@^7.0.0":
6161
version "7.12.13"

0 commit comments

Comments
 (0)