Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add completion support for filter parameters #522

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

graygilmore
Copy link
Contributor

@graygilmore graygilmore commented Oct 7, 2024

What are you adding in this PR?

Adds support for completion options for filter parameters. E.g.

{{ product | image_url: █ }}

Will show completion options for image_url parameters!

image

I've split the PR into two commits:

  • Add liquid parser support in placeholder modes for "incomplete" liquid statements when a filter would otherwise be invalid liquid
  • Add a new completion provider for filter parameters

Before you deploy

  • I ran yarn build and committed the updated configuration files
  • My feature is backward compatible
  • I included a patch bump changeset

@@ -489,16 +494,19 @@ StrictLiquidHTML <: LiquidHTML {
}

WithPlaceholderLiquid <: Liquid {
liquidFilter<delim> := space* "|" space* identifier (space* ":" space* filterArguments<delim>)?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only want this behavior for the placeholder modes to assist with autocompletion.

const currentContext = params.completionContext.ancestors.at(-1);
// We don't want to show generic variable completions when we're inside a
// filter. This case will be handled by FilterNamedParameterCompletionProvider.
if (currentContext?.type === NodeTypes.LiquidFilter) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the incomplete filter statement ends with LiquidVariableOutput we need to skip the lookup here if we're inside a filter or else we'll show all possible autocomplete values.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine for positional arguments, but isn't fine for when there were NamedArguments in the args array of the filter ancestor?

in other words:

  • We do want completion of variables if the variable lookup could be a positional argument
  • We don't want completion of variables if there were named arguments before the lookup being completed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably could use some kind of sortText CompletionItem stuff to make sure that the properties are shown before the variables?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯 let me make that change.

@graygilmore graygilmore marked this pull request as ready for review October 7, 2024 18:13
@graygilmore graygilmore requested a review from a team October 7, 2024 18:13
Comment on lines 405 to 408
for (const { toCST, expectPath } of testCases) {
cst = toCST(`{{ a[1].foo | filtername: 10, myvar.foo, a1: 2, a2 }}`);
expectPath(cst, '0.type').to.equal('LiquidVariableOutput');
}
Copy link
Contributor

@charlespwd charlespwd Oct 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this only pass in placeholder mode? 🤔

I think you do that with toCST(..., { mode: 'completion' })

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I think we're just not going deep enough on the expectPath here.

});

return options.map(({ entry, types }) =>
createCompletionItem(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that when you have you cursor in the middle of the partial, you don't replace the entire word. I got around it by finding the existing length and doing a TextEdit.replace (example). Should we consider that here too @charlespwd ?

E.g.

{{ 'base.css' | image_tag: he█ight }} ===> {{ 'base.css' | image_tag: heightight }}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting! Good call out. That's annoying to have to handle but makes sense in terms of total completeness of this (and matching other behavior).


return options.map(({ entry, types }) =>
createCompletionItem(
entry,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any limitations today that prevent us from putting a ":" after the param? It would be great if we can do something like ${param}: $0.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is! Not all params are named and will require a :. I'm working on updating the source of the docs to include this so that we can do that!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect ❤️ In this PR or a follow-up one? 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll be in a totally separate repo to build out support for this. I'll switch this one back to draft in the mean time!

@graygilmore graygilmore marked this pull request as draft October 9, 2024 17:14
@graygilmore graygilmore force-pushed the gg-complete-filter-arguments branch 2 times, most recently from 8cc9093 to 67cf286 Compare October 9, 2024 23:51
We want to add autocomplete behavior for the case where a developer is
typing out a liquid statement but isn't finished yet:

```liquid
{{ product | image_url: █
```

The scenario above works without any extra code but if we were to do:

```liquid
{{ product | image_url: width: 100, h█
```

Our parser would blow up because this isn't valid liquid anymore. It
interprets the `h` as a positional argument which cannot come after a
named argument. To support this we need to override how the grammar for
liquid filters is defined in the Placeholder scenario to support this.
The changes will treat the `h` as a `LiquidVariableOutput` and include
proper hierarchy.
The theme doc generator has been updated to include this attribute so
that we can add better support for providing completions for filters.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ObjectCompletionProvider and filter arguments
3 participants