1- import { NodeTypes } from '@shopify/liquid-html-parser' ;
1+ import { LiquidHtmlNode , LiquidTag , NodeTypes } from '@shopify/liquid-html-parser' ;
22import { CompletionItem , CompletionItemKind } from 'vscode-languageserver' ;
33import { LiquidCompletionParams } from '../params' ;
44import { Provider } from './common' ;
5+ import { SourceCodeType , visit , isError } from '@shopify/theme-check-common' ;
6+ import { findInlineSnippetAncestor } from '@shopify/theme-check-common/dist/checks/utils' ;
57
68export type GetSnippetNamesForURI = ( uri : string ) => Promise < string [ ] > ;
79
@@ -14,21 +16,13 @@ export class RenderSnippetCompletionProvider implements Provider {
1416 const { node, ancestors } = params . completionContext ;
1517 const parentNode = ancestors . at ( - 1 ) ;
1618
17- if (
18- ! node ||
19- ! parentNode ||
20- node . type !== NodeTypes . String ||
21- parentNode . type !== NodeTypes . RenderMarkup
22- ) {
19+ if ( ! node || ! parentNode || parentNode . type !== NodeTypes . RenderMarkup ) {
2320 return [ ] ;
2421 }
2522
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 (
23+ if ( node . type === NodeTypes . String ) {
24+ const fileSnippets = await this . getSnippetNamesForURI ( params . textDocument . uri ) ;
25+ const fileCompletionItems = fileSnippets . map (
3226 ( option : string ) : CompletionItem => ( {
3327 label : option ,
3428 kind : CompletionItemKind . Snippet ,
@@ -38,5 +32,44 @@ export class RenderSnippetCompletionProvider implements Provider {
3832 } ,
3933 } ) ,
4034 ) ;
35+ return fileCompletionItems ;
36+ } else if ( node . type === NodeTypes . VariableLookup ) {
37+ const containingSnippet = findInlineSnippetAncestor ( ancestors ) ;
38+ const containingSnippetName =
39+ containingSnippet && typeof containingSnippet . markup !== 'string'
40+ ? containingSnippet . markup . name
41+ : null ;
42+
43+ const fullAst = params . document . ast ;
44+ const allInlineSnippets = isError ( fullAst ) ? [ ] : getInlineSnippetsNames ( fullAst ) ;
45+
46+ const inlineSnippets = allInlineSnippets . filter (
47+ ( name ) => name !== containingSnippetName ,
48+ ) ;
49+
50+ const inlineCompletionItems = inlineSnippets . map (
51+ ( option : string ) : CompletionItem => ( {
52+ label : option ,
53+ kind : CompletionItemKind . Snippet ,
54+ documentation : {
55+ kind : 'markdown' ,
56+ value : `Inline snippet "${ option } "` ,
57+ } ,
58+ } ) ,
59+ ) ;
60+ return inlineCompletionItems ;
61+ } else {
62+ return [ ] ;
63+ }
4164 }
4265}
66+
67+ function getInlineSnippetsNames ( ast : LiquidHtmlNode ) : string [ ] {
68+ return visit < SourceCodeType . LiquidHtml , string > ( ast , {
69+ LiquidTag ( node : LiquidTag ) {
70+ if ( node . name === 'snippet' && typeof node . markup !== 'string' && node . markup . name ) {
71+ return node . markup . name ;
72+ }
73+ } ,
74+ } ) ;
75+ }
0 commit comments