From 44137b76eca3dc3a68d23edc3dff99abc45125f1 Mon Sep 17 00:00:00 2001 From: Cameron Dubas Date: Wed, 4 Oct 2023 10:44:40 +0100 Subject: [PATCH 1/2] fix: remove multi-character triggerCharacters VSCode ignores these as they should be single characters only --- src/server.ts | 2 +- test/__snapshots__/integration-test.ts.snap | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/server.ts b/src/server.ts index 83f8d84f..a01a4e6c 100644 --- a/src/server.ts +++ b/src/server.ts @@ -576,7 +576,7 @@ export default class Server { }, completionProvider: { resolveProvider: true, - triggerCharacters: ['.', '::', '$', '=', '/', '{{', '(', '<', '@', 'this.', '<:', '"', "'"], + triggerCharacters: ['.', ':', '$', '=', '/', '{', '(', '<', '@', '"', "'", '#'], }, }, }; diff --git a/test/__snapshots__/integration-test.ts.snap b/test/__snapshots__/integration-test.ts.snap index 5ffba10a..7b6aa050 100644 --- a/test/__snapshots__/integration-test.ts.snap +++ b/test/__snapshots__/integration-test.ts.snap @@ -3471,18 +3471,17 @@ Object { "resolveProvider": true, "triggerCharacters": Array [ ".", - "::", + ":", "$", "=", "/", - "{{", + "{", "(", "<", "@", - "this.", - "<:", "\\"", "'", + "#", ], }, "definitionProvider": true, @@ -7306,18 +7305,17 @@ Object { "resolveProvider": true, "triggerCharacters": Array [ ".", - "::", + ":", "$", "=", "/", - "{{", + "{", "(", "<", "@", - "this.", - "<:", "\\"", "'", + "#", ], }, "definitionProvider": true, From 15d327bcb07a7e0161ded261ecac50023e0f0ca3 Mon Sep 17 00:00:00 2001 From: Cameron Dubas Date: Wed, 4 Oct 2023 10:59:52 +0100 Subject: [PATCH 2/2] fix: include yielded blocks in angle bracket completion Due to trigger characters being limited to a single character the completion request is triggered when `<` is typed. At that point both AngleBracketComponents and yielded blocks are relevant. --- .../core/template-completion-provider.ts | 5 +- test/__snapshots__/integration-test.ts.snap | 192 +++++++++++++++++- test/integration-test.ts | 24 ++- 3 files changed, 213 insertions(+), 8 deletions(-) diff --git a/src/builtin-addons/core/template-completion-provider.ts b/src/builtin-addons/core/template-completion-provider.ts index 7bb84ec0..9231078a 100644 --- a/src/builtin-addons/core/template-completion-provider.ts +++ b/src/builtin-addons/core/template-completion-provider.ts @@ -576,14 +576,15 @@ export default class TemplateCompletionProvider { const yields = await this.getParentComponentYields(focusPath.parent); completions.push(...yields); - } else if (isAngleComponentPath(focusPath) && !isNamedBlockName(focusPath)) { + } else if (isAngleComponentPath(focusPath)) { logDebugInfo('isAngleComponentPath'); // const candidates = await this.getAllAngleBracketComponents(root); const scopedValues = this.getExtendedScopedValues(focusPath); + const yields = await this.getParentComponentYields(focusPath.parent); logDebugInfo(candidates, scopedValues); - completions.push(...uniqBy([...candidates, ...scopedValues], 'label')); + completions.push(...uniqBy([...yields, ...candidates, ...scopedValues], 'label')); } else if (isScopedAngleTagName(focusPath)) { // {{#let foo as |bar|}} ", + "kind": 6, + "label": ":main", + "textEdit": Object { + "newText": ":main", + "range": Object { + "end": Object { + "character": 10, + "line": 0, + }, + "start": Object { + "character": 10, + "line": 0, + }, + }, + }, + }, + Object { + "data": Object { + "files": Array [ + "app/components/hello.hbs", + ], + }, + "detail": "component", + "kind": 7, + "label": "Hello", + "textEdit": Object { + "newText": "Hello", + "range": Object { + "end": Object { + "character": 10, + "line": 0, + }, + "start": Object { + "character": 10, + "line": 0, + }, + }, + }, + }, + Object { + "data": Object { + "files": Array [ + "app/components/darling.hbs", + ], + }, + "detail": "component", + "kind": 7, + "label": "Darling", + "textEdit": Object { + "newText": "Darling", + "range": Object { + "end": Object { + "character": 10, + "line": 0, + }, + "start": Object { + "character": 10, + "line": 0, + }, + }, + }, + }, + Object { + "data": Object { + "files": Array [ + "app/components/world.hbs", + ], + }, + "detail": "component", + "kind": 7, + "label": "World", + "textEdit": Object { + "newText": "World", + "range": Object { + "end": Object { + "character": 10, + "line": 0, + }, + "start": Object { + "character": 10, + "line": 0, + }, + }, + }, + }, +] +`; + +exports[`integration async fs enabled: false autocomplete works for angle component yielded blocks 1`] = ` Array [ Object { "detail": "Named block (Slot) for ", @@ -3775,7 +3867,7 @@ Array [ ] `; -exports[`integration async fs enabled: false autocomplete works for multiple angle component slots 1`] = ` +exports[`integration async fs enabled: false autocomplete works for multiple angle component yielded blocks 1`] = ` Array [ Object { "detail": "Named block (Slot) for ", @@ -7586,7 +7678,99 @@ Array [ ] `; -exports[`integration async fs enabled: true autocomplete works for angle component slots 1`] = ` +exports[`integration async fs enabled: true autocomplete includes yielded blocks in angle component completions 1`] = ` +Array [ + Object { + "detail": "Named block (Slot) for ", + "kind": 6, + "label": ":main", + "textEdit": Object { + "newText": ":main", + "range": Object { + "end": Object { + "character": 10, + "line": 0, + }, + "start": Object { + "character": 10, + "line": 0, + }, + }, + }, + }, + Object { + "data": Object { + "files": Array [ + "app/components/hello.hbs", + ], + }, + "detail": "component", + "kind": 7, + "label": "Hello", + "textEdit": Object { + "newText": "Hello", + "range": Object { + "end": Object { + "character": 10, + "line": 0, + }, + "start": Object { + "character": 10, + "line": 0, + }, + }, + }, + }, + Object { + "data": Object { + "files": Array [ + "app/components/darling.hbs", + ], + }, + "detail": "component", + "kind": 7, + "label": "Darling", + "textEdit": Object { + "newText": "Darling", + "range": Object { + "end": Object { + "character": 10, + "line": 0, + }, + "start": Object { + "character": 10, + "line": 0, + }, + }, + }, + }, + Object { + "data": Object { + "files": Array [ + "app/components/world.hbs", + ], + }, + "detail": "component", + "kind": 7, + "label": "World", + "textEdit": Object { + "newText": "World", + "range": Object { + "end": Object { + "character": 10, + "line": 0, + }, + "start": Object { + "character": 10, + "line": 0, + }, + }, + }, + }, +] +`; + +exports[`integration async fs enabled: true autocomplete works for angle component yielded blocks 1`] = ` Array [ Object { "detail": "Named block (Slot) for ", @@ -7609,7 +7793,7 @@ Array [ ] `; -exports[`integration async fs enabled: true autocomplete works for multiple angle component slots 1`] = ` +exports[`integration async fs enabled: true autocomplete works for multiple angle component yielded blocks 1`] = ` Array [ Object { "detail": "Named block (Slot) for ", diff --git a/test/integration-test.ts b/test/integration-test.ts index 7296a9e4..321778d6 100644 --- a/test/integration-test.ts +++ b/test/integration-test.ts @@ -1811,7 +1811,7 @@ describe('integration', function () { }); }); - it('autocomplete works for angle component slots', async () => { + it('autocomplete works for angle component yielded blocks', async () => { const result = await getResult( CompletionRequest.method, connection, @@ -1830,7 +1830,7 @@ describe('integration', function () { expect(result.response).toMatchSnapshot(); }); - it('autocomplete works for multiple angle component slots', async () => { + it('autocomplete works for multiple angle component yielded blocks', async () => { const result = await getResult( CompletionRequest.method, connection, @@ -1849,6 +1849,26 @@ describe('integration', function () { expect(result.response).toMatchSnapshot(); }); + it('autocomplete includes yielded blocks in angle component completions', async () => { + const result = await getResult( + CompletionRequest.method, + connection, + { + app: { + components: { + 'hello.hbs': '<', + 'world.hbs': 'Hello World', + 'darling.hbs': '{{yield to="main"}}', + }, + }, + }, + 'app/components/hello.hbs', + { line: 0, character: 10 } + ); + + expect(result.response).toMatchSnapshot(); + }); + describe('Project class resolution, based on fs path and file structure', () => { it('able to resolve main project if top-level addon is registered', async () => { const files = {