Detect parsing for completion
Hi. I'm wondering what is the best way to detect that IStubFileElementType.parseContents() is being called for code completion. Our parser needs to know and I'd rather not check for "IntellijIdeaRulezzz" in the contents if I can avoid that. Thanks.
Scott
Please sign in to leave a comment.
Hello Scott,
Why exactly do you need to know that?
--
Dmitry Jemerov
Development Lead
JetBrains, Inc.
http://www.jetbrains.com/
"Develop with Pleasure!"
Our plugin utilizes our language's internal parser and transforms our parse tree to IntelliJ's AST. This strategy saves us from having to build a whole new parser for the plugin, which would be rather costly. Our Annotator implementation needs to access the errors and warning corresponding with the most recent change in the editor. But annotators in general, it seems, work off the original PsiFile and not the one passed to IStubFileElementType.parseContents(). Since the incremental changes made to the original PsiFile are not parsed by our parser, the errors and warnings are never updated. Thus, our impl of parseContents() needs to grab the errors and warnings from the latest parse and hang them on the original file. However, we don't want to do that if parseContents() is called for the purposes of generating an error for code completion.
Scott
Hello Scott,
During completion, a copy of the PSI file is created, and the dummy identifier
for completion is inserted into the copy. The copy is also created during
some other operations.
You can check that the reparse is being performed on a copy and not on the
original file using the following check in parseContents():
(PsiFile) chameleon.getPsi == ((PsiFile) chameleon.getPsi()).getOriginalFile()
If the two instances are the same, the parse is performed on the original
file. If they're different, the parse is performed on a copy.
--
Dmitry Jemerov
Development Lead
JetBrains, Inc.
http://www.jetbrains.com/
"Develop with Pleasure!"
Thanks, Dmitry. But from what I can gather changes in the editor are parsed as a *copy* and not on the original file. From my observations the original file is parsed once and never again. It seems incremental changes in the editor are patched into the original file, it is never reparsed. Instead incremental changes are parsed separately via a copy of the file passed to parseContents(). However, this parsed copy is not passed to the annotator, it is always the original, which is why I need to know what operation is going on during parseContents().
Scott
Hello Scott,
Yep, that's actually correct. The copy created for the completion can be
distinguished in the following way:
chameleon.getPsi().getUserData(CodeCompletionHandlerBase.FILE_COPY_KEY) !=
null
This is, however, an implementation detail, and I can't promise that it won't
change in future IDEA versions.
--
Dmitry Jemerov
Development Lead
JetBrains, Inc.
http://www.jetbrains.com/
"Develop with Pleasure!"
Thanks again, Dmitry. Unfortunately, that doesn't quite work. After digging into the code a bit it appears the COMPLETION_CONTEXT_KEY isn't set until after parseContents() is called. Specifically, CodeCompletionHandlerBase.createCompletionParameters() commits the document via insertDummyIdentifier(), this in turn invokes the parser on the content. Ironically, the result of insertDummyIdentifier() is the value of the COMPLETION_CONTEXT_KEY -- sort of a chicken and egg scenario. I'll dig a bit more and see if perhaps there's some other pattern or impl detail I can detect. The bottom line is I'd like to avoid the expensive search for the dummy token in the content if at all possible. Thanks.
Scott
I should clarify. The FILE_COPY_KEY is also not set for similar reasons; the document is committed and parsed before the key is set.
Scott