(feat)Go to definition from class in template to css#1518
(feat)Go to definition from class in template to css#1518Jojoshua wants to merge 8 commits intosveltejs:masterfrom
Conversation
|
@dummdidumm Side-note #83 regarding go to definition from css to template, I don't feel this is a "go to definition" concern but rather a find references because the class can be used many places within the template |
dummdidumm
left a comment
There was a problem hiding this comment.
Thank you for tackling this! The idea is good, I left some comments on the implementation, where code should go in my opinion and what a more robust class lookup might look like
packages/language-server/src/plugins/css/CSSClassDefinitionLocator.ts
Outdated
Show resolved
Hide resolved
packages/language-server/src/plugins/css/CSSClassDefinitionLocator.ts
Outdated
Show resolved
Hide resolved
|
|
||
| public IsExactClassMatch(testRange: Range) { | ||
| //Check nothing before the test position | ||
| if (testRange.start.character > 0) { |
There was a problem hiding this comment.
This would fail for something like .foo.bar { .. } or .foo .bar { .. }. In general it's a little brittle to only use text matching here. The vscode-css-language-service which is used in the CSSPlugin provides an AST I think, but it's private. This puts us at risk of breaking changes but I feel it's more robust to use that one instead and fall back to this text-based matching only if parsing fails (because a different preprocessor is used for example).
There was a problem hiding this comment.
I had a feeling about that one. The case I thought would be the most straightforward turned out, not. I will try to improve it. I was looking for a way to pull the text for an entire line but couldn't find it
There was a problem hiding this comment.
@dummdidumm So this actually did already work for .foo .bar but did not for .foo.bar
Try the latest, it handles all sorts of combinations. I feel this is a good compromise especially since I really don't feel that style's inside a svelte component would/should be very complex. If after testing you still feel like we need more horsepower I can look into the CSS AST(just point me in the right direction for that)
| const { lang, tsDoc } = await this.getLSAndTSDoc(document); | ||
| const mainFragment = tsDoc.getFragment(); | ||
|
|
||
| const cssClassHelper = new CSSClassDefinitionLocator(tsDoc, position, document); |
There was a problem hiding this comment.
The idea of the plugin folders is that they are mostly independent of each other, so it would be better to put this logic into the CSSPlugin or move the class into the TypeScript plugin folder - but I feel like the best place would be SveltePlugin.ts. This brings us to a question to which I don't have a good answer yet: What is the best place for code like this? It's cross-cutting so it's not obvious to me in which plugin this does belong. Maybe this hints at that the plugin system needs a redesign / needs to be replaced with something new, but that's for another day.
There was a problem hiding this comment.
Yeah I was having trouble where to place this. I moved to TypeScript folder for now.
There was a problem hiding this comment.
Feel free to relocate wherever you feel is best
|
Had a chance to look at again @dummdidumm? |
|
Sorry, have some other things on my plate currently, but I'll get back to this in the next weeks! |
|
@dummdidumm Just checking in -- didn't want to lose too much context on this as time passed |
dummdidumm
left a comment
There was a problem hiding this comment.
Sorry for leaving you hanging for so long, my primary focus is on SvelteKit right now. I left two comments from what I think could be improved, hope this helps.
| this.initialNodeAt = this.tsDoc.svelteNodeAt(this.position) as SvelteNode; | ||
| } | ||
|
|
||
| getCSSClassDefinition() { |
There was a problem hiding this comment.
I believe it could be more promising/faster to defer CSS parsing to vscode-css-languageservice which has a parse method. The AST that is returned doesn't have type definitions because it's private, but I'm honestly not worried too much about that since it's unlikely to change for this. That AST could be traversed to more easily find the correct node to link to.
There was a problem hiding this comment.
Looking into this again. Using svelteNodeAt is giving back a lot of good Svelte information that I wouldn't think the vscode-css-languageservice would know about. This method will tell us all the other variations of Svelte css such as whether it is a ConditionalExpression or Class Directive Format.
There was a problem hiding this comment.
I didn't mean the HTML part, I meant the CSS part. The code does string traversal of the CSS to find the matching definition, but it could be more promising to use the CSS AST output of vscode-css-languageservice
There was a problem hiding this comment.
Are you referring to the while loop in getStandardFormatClassName() ? This is actually not traversing css but the class attribute string itself to figure out which classname the position is at
class="test te|st1 bar foo" so in this example the cursor is in the middle of test1 so that's what we're going to look for in the style section
| ); | ||
|
|
||
| if (results) { | ||
| return results; |
There was a problem hiding this comment.
The results should probably be merged with what else comes up. In the case of class:foo both .foo { ... } in <style> and let foo = ... in script are definitons, and we would lose the latter when returning early.
There was a problem hiding this comment.
I'm not sure I follow. In all the tests and variations I've used it seems to work. When you hit F12 to go to definition there can only be 1 result (if a definition can be found).
|
Definitely this function should also take into account the name of the element (tagName) Just referring to classes is not enough. Also the recognition of fixed attributes can be taken into account. |
Done via 6010236 |
| } | ||
| } | ||
|
|
||
| private getDefinitionRangeWithinStyleSection(targetClass: string) { |
There was a problem hiding this comment.
Apologies, the comment on line getCSSClassDefinition was actually meant to appear here. That code does a somewhat unperformant string search. I believe it could be more promising/faster to defer CSS parsing to vscode-css-languageservice which has a parse method. The AST that is returned doesn't have type definitions because it's private, but I'm honestly not worried too much about that since it's unlikely to change for this. That AST could be traversed to more easily find the correct node to link to.

Implementation help for go to css definition from template in #83
Works for many different class formats:
Standard
Conditional Expression
Class Directive
HTML Element Tag