Overriding ParserDefinition vs looking up in PSI when needed
I'm building a plugin for editing YAML files for Home Assistant. In some points (completion contributor, references contributor, documentation provider) I need to identify some precise YAML elements in order to do the right thing. For example, this is a script definition:
script:
my_super_script:
description: "Some documentation about the script"
[...]
This script definition can be referenced ("called" like a function, if you wish) in other files. To identify that particular piece of YAML as a script, I created an element pattern that finds YAMLKeyValues having a “script” parent mapping key.
That is working well and to reuse that I made utility methods so I don't duplicate code. But I do PSI tree traversals everytime I need those.
Then I found YAMLParserDefinition and I thought: what if I extend that class and override the createElement method, inspect the ASTNode (make the same checks I would make in the PSI tree) and create a custom PSI element that wraps YAMLKeyValueImpl? That way, in my contributors/providers I could just do an “instanceof” check on my custom PSI classes (working example of the ParserDefinition here).
So the question is: do I use (and traverse) PSI everytime I need to identify those particular elements when I need it (in the completion contributor, reference, contributor, and so forth) or do I do that once in the ParserDefinition and use custom PSI elements later with a simple “instanceof” check? In terms of performance, which one is more expensive? And which one is the more “architecturally correct”?
Personally I did test both but I couldn't notice a significant difference in performance (we are talking about relatively small files anyway), anyway I wanted to be sure that I am on the right track and not overengineering stuff.
Thanks!
Please sign in to leave a comment.
I noticed one weird thing using the ParserDefinition: the CPU stays 100% constant. If I restart the IDE without the ParserDefinition, CPU usage goes back to normal. createElement() is not called very often though…
Hi Daniele,
Extending
ParserDefinition
looks hacky to me. The standard approach is to traverse PSI when you need it. If computations are expensive, you can cache the values for later use: https://plugins.jetbrains.com/docs/intellij/psi-performance.html#cache-results-of-heavy-computationsThank you Karol, I'll do PSI traversal when needed.