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,42 @@ 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 ( ( name ) => name !== containingSnippetName ) ;
47+
48+ const inlineCompletionItems = inlineSnippets . map (
49+ ( option : string ) : CompletionItem => ( {
50+ label : option ,
51+ kind : CompletionItemKind . Snippet ,
52+ documentation : {
53+ kind : 'markdown' ,
54+ value : `Inline snippet "${ option } "` ,
55+ } ,
56+ } ) ,
57+ ) ;
58+ return inlineCompletionItems ;
59+ } else {
60+ return [ ] ;
61+ }
4162 }
4263}
64+
65+ function getInlineSnippetsNames ( ast : LiquidHtmlNode ) : string [ ] {
66+ return visit < SourceCodeType . LiquidHtml , string > ( ast , {
67+ LiquidTag ( node : LiquidTag ) {
68+ if ( node . name === 'snippet' && typeof node . markup !== 'string' && node . markup . name ) {
69+ return node . markup . name ;
70+ }
71+ } ,
72+ } ) ;
73+ }
0 commit comments