Skip to content

Commit 622f2eb

Browse files
committed
Added support for render tag completion for inline snippets
1 parent b4049b2 commit 622f2eb

File tree

3 files changed

+52
-15
lines changed

3 files changed

+52
-15
lines changed

.changeset/flat-geckos-breathe.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/theme-language-server-common': minor
3+
---
4+
5+
Added completion support for inline snippets in the `render` tag

packages/theme-language-server-common/src/completions/providers/RenderSnippetCompletionProvider.spec.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,23 @@ describe('Module: RenderSnippetCompletionProvider', async () => {
2424

2525
it('should complete snippets correctly', async () => {
2626
await expect(provider).to.complete('{% render "', ['product-card', 'image']);
27-
await expect(provider).to.complete('{% render "product', [
27+
// VSCode handles filtering
28+
});
29+
30+
it('should complete inline snippets', async () => {
31+
const template = `{% snippet my-inline-snippet %}
32+
{% echo 'hello' %}
33+
{% endsnippet %}
34+
35+
{% render m`;
36+
37+
await expect(provider).to.complete(template, ['my-inline-snippet']);
38+
// VSCode handles filtering
39+
await expect(provider).to.complete(template, [
2840
expect.objectContaining({
2941
documentation: {
3042
kind: 'markdown',
31-
value: 'snippets/product-card.liquid',
43+
value: `Inline snippet "my-inline-snippet"`,
3244
},
3345
}),
3446
]);
Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { NodeTypes } from '@shopify/liquid-html-parser';
1+
import { LiquidHtmlNode, LiquidTag, NodeTypes } from '@shopify/liquid-html-parser';
22
import { CompletionItem, CompletionItemKind } from 'vscode-languageserver';
33
import { LiquidCompletionParams } from '../params';
44
import { Provider } from './common';
5+
import { SourceCodeType, visit } from '@shopify/theme-check-common';
56

67
export type GetSnippetNamesForURI = (uri: string) => Promise<string[]>;
78

@@ -14,21 +15,13 @@ export class RenderSnippetCompletionProvider implements Provider {
1415
const { node, ancestors } = params.completionContext;
1516
const parentNode = ancestors.at(-1);
1617

17-
if (
18-
!node ||
19-
!parentNode ||
20-
node.type !== NodeTypes.String ||
21-
parentNode.type !== NodeTypes.RenderMarkup
22-
) {
18+
if (!node || !parentNode || parentNode.type !== NodeTypes.RenderMarkup) {
2319
return [];
2420
}
2521

26-
const options = await this.getSnippetNamesForURI(params.textDocument.uri);
27-
const partial = node.value;
28-
29-
return options
30-
.filter((option) => option.startsWith(partial))
31-
.map(
22+
if (node.type === NodeTypes.String) {
23+
const fileSnippets = await this.getSnippetNamesForURI(params.textDocument.uri);
24+
const fileCompletionItems = fileSnippets.map(
3225
(option: string): CompletionItem => ({
3326
label: option,
3427
kind: CompletionItemKind.Snippet,
@@ -38,5 +31,32 @@ export class RenderSnippetCompletionProvider implements Provider {
3831
},
3932
}),
4033
);
34+
return fileCompletionItems;
35+
} else if (node.type === NodeTypes.VariableLookup) {
36+
const inlineSnippets = getInlineSnippetsNames(params.completionContext.partialAst);
37+
const inlineCompletionItems = inlineSnippets.map(
38+
(option: string): CompletionItem => ({
39+
label: option,
40+
kind: CompletionItemKind.Snippet,
41+
documentation: {
42+
kind: 'markdown',
43+
value: `Inline snippet "${option}"`,
44+
},
45+
}),
46+
);
47+
return inlineCompletionItems;
48+
} else {
49+
return [];
50+
}
4151
}
4252
}
53+
54+
function getInlineSnippetsNames(ast: LiquidHtmlNode): string[] {
55+
return visit<SourceCodeType.LiquidHtml, string>(ast, {
56+
LiquidTag(node: LiquidTag) {
57+
if (node.name === 'snippet' && typeof node.markup !== 'string' && node.markup.name) {
58+
return node.markup.name;
59+
}
60+
},
61+
});
62+
}

0 commit comments

Comments
 (0)