Autocompletion with custom language error
I'm creating a new language but i'm trying to reuse some components from the XML and HTML languages. So i have a simple FileType that extends XmlLikeFileType and that in the constructor creates the instance of my Language. My language class now looks like this:
public class MyTemplateLanguage extends XMLLanguage {
public MyTemplateLanguage() {
super("MyTemplateLanguage", "text/html");
}
@NotNull
public SyntaxHighlighter getSyntaxHighlighter(Project project, VirtualFile virtualFile) {
return new HtmlFileHighlighter();
}
public XmlPsiPolicy getPsiPolicy() {
return ENCODE_EACH_SYMBOL_POLICY;
}
public ParserDefinition getParserDefinition() {
return new HTMLParserDefinition();
}
@Nullable
public Annotator getAnnotator() {
return null;
}
}
Everything seems to work acording to plan except auto-completion. If i try to auto-complete any html attribute i get an exception:
java.lang.NullPointerException
at com.intellij.psi.impl.source.PsiFileImpl.clone(PsiFileImpl.java:7)
at com.intellij.psi.impl.source.PsiFileImpl.clone(PsiFileImpl.java:134)
at com.intellij.psi.impl.source.TreeWrapperPsiElement.copy(TreeWrapperPsiElement.java:14)
at com.intellij.codeInsight.completion.CodeCompletionHandlerBase.createFileCopy(CodeCompletionHandlerBase.java:78)
at com.intellij.codeInsight.completion.CodeCompletionHandlerBase.a(CodeCompletionHandlerBase.java:121)
at com.intellij.codeInsight.completion.CodeCompletionHandlerBase.access$100(CodeCompletionHandlerBase.java:82)
at com.intellij.codeInsight.completion.CodeCompletionHandlerBase$2.compute(CodeCompletionHandlerBase.java:1)
at com.intellij.codeInsight.completion.CodeCompletionHandlerBase$2.compute(CodeCompletionHandlerBase.java:2)
at com.intellij.openapi.application.impl.ApplicationImpl$10.run(ApplicationImpl.java:1)
at com.intellij.openapi.application.impl.ApplicationImpl$9.compute(ApplicationImpl.java:1)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.postponeFormattingInside(PostprocessReformattingAspect.java:167)
at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:71)
at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:295)
at com.intellij.codeInsight.completion.CodeCompletionHandlerBase.getLookupData(CodeCompletionHandlerBase.java:162)
at com.intellij.codeInsight.completion.CodeCompletionHandlerBase.invoke(CodeCompletionHandlerBase.java:144)
at com.intellij.codeInsight.actions.CodeInsightAction$1$1.run(CodeInsightAction.java:41)
at com.intellij.openapi.application.impl.ApplicationImpl$9.compute(ApplicationImpl.java:1)
at com.intellij.psi.impl.source.PostprocessReformattingAspect.postponeFormattingInside(PostprocessReformattingAspect.java:167)
at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:71)
at com.intellij.codeInsight.actions.CodeInsightAction$1.run(CodeInsightAction.java:45)
at com.intellij.openapi.command.impl.CommandProcessorImpl.executeCommand(CommandProcessorImpl.java:111)
at com.intellij.openapi.command.impl.CommandProcessorImpl.executeCommand(CommandProcessorImpl.java:2)
at com.intellij.codeInsight.actions.CodeInsightAction.actionPerformedImpl(CodeInsightAction.java:36)
at com.intellij.codeInsight.completion.actions.CodeCompletionAction.actionPerformedImpl(CodeCompletionAction.java:4)
at com.intellij.codeInsight.actions.CodeInsightAction.actionPerformed(CodeInsightAction.java:25)
at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.a(IdeKeyEventDispatcher.java:211)
at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.b(IdeKeyEventDispatcher.java:55)
at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.dispatchKeyEvent(IdeKeyEventDispatcher.java:67)
at com.intellij.ide.IdeEventQueue.a(IdeEventQueue.java:37)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:83)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)
Any ideas ?
Please sign in to leave a comment.
I'm not sure how any of the suggested solutions would work. Maybe because i haven't explained the problem very well. I'm going to provide two examples that i think should explain my problem better.
A Tapestry component template without a doctype declaration:
+<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<t:loop source="blocks" value="currentBlock">
</t:loop>
</t:container>+
IntelliJ annotates the http://tapestry.apache.org/schema/tapestry_5_0_0.xsd in red and when i pass the cursor over it it show the tooltip "Cannot resolve symbol null". The rest of the template is validated just fine.
If i add a doctype declaration into the mix:
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<t:loop source="blocks" value="currentBlock">
</t:loop>
</t:container>+
Now things really go wrong. Besides the same error as before, all the tag in the t namespace are marked as error and the root element (t:container) is marked with the error "Wrong root element".
Also, keep in mind that the Tapestry xsd doesn't actually define any elements. It's really just a place holder.
What i would need is for these errors to not happen.
Can you please help figure out the the cause of the initial exception ?
If i could just figure that out i think i could take it from there....
I can't even get to work a Language implementation like this:
public class TapestryTemplateLanguage extends Language {
public TapestryTemplateLanguage() {
super("TML");
}
}
I immediately start getting the exception:
java.lang.NullPointerException
at com.intellij.psi.impl.source.PsiFileImpl.clone(PsiFileImpl.java:7)
when i try to auto-complete in the file.
You need to register your classes that provides xml schema to IDEA like
following:
MetaRegistry.addMetadataBinding(
new AndFilter(
new
NamespaceFilter("http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"),
new ClassFilter(XmlDocument.class)
),
MyTapestrySchemaNSDescriptor.class
);
MetaRegistry.addMetadataBinding(
new AndFilter(
new
NamespaceFilter("http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"),
new ClassFilter(XmlTag.class)
),
MyTapestrySchemaNSDescriptor.class
);
class MyTapestrySchemaNSDescriptor should be public and have public no
arg constructor and implement XmlNSDescriptor interface
Hugo Palma wrote:
--
Best regards,
Maxim Mossienko
IntelliJ Labs / JetBrains Inc.
http://www.intellij.com
"Develop with pleasure!"
The thing is, when you create your own language, you should provide
full-blown support for it. Including ParserDefinition, file instance
creation, parsing itself and so on. So it should be easier for you to
plug in some other areas
Ok, i've done that.
I still have problems when the document declares a doctype. If it doesn't declare a doctype it works just fine.
If there's a doctype declaration it still tries to match the document root node to the one defined in the doctype. I'm not seeing how i can prevent this in my TapestryNamespaceDescriptor.
Also, every single Tapestry tag is also marked as error except the one that are immediatly below another Tapestry tag. Example:
+<t:loop source="blocks" value="currentBlock">
<t:delegate to="currentBlock"/>
</t:loop>+
The t:loop is marked as error but the t:delegate isn't.
Any ideas ?
Again, i really appreciate your help on this....
The validation should be completely in your hands (null returned from
getElementDescriptor will cause error highlighting to appear)
As to doctype declaration, valid xml requires to match root node and
name defined in doctype (IDEA supports only one type of exclusion,
namely when doctype descriptor has no element references).
Hugo Palma wrote:
--
Best regards,
Maxim Mossienko
IntelliJ Labs / JetBrains Inc.
http://www.intellij.com
"Develop with pleasure!"
My getElementDescriptor method is always returning an instance of XmlElementDescriptorImpl. I know it's working because it resolves the element declaration correctly. But still, the tag is still marked as error. So there must be another place where it's getting set as an error.
Regarding the root tag. So you're telling me there's not way to bypass the validation that matches the root document tag with the doctype ?
Does getElementDescriptor of your XmlElementDescriptor also return
something not null? As to doctype validation, you can switch it off in
Selena, there is also some hacky way to put
XmlHighlightVisitor.DO_NOT_VALIDATE key to user data of xmldoctype element
Hugo Palma wrote:
--
Best regards,
Maxim Mossienko
IntelliJ Labs / JetBrains Inc.
http://www.intellij.com
"Develop with pleasure!"
Yes, it returns a new instance of the same XmlElementDescriptor class.
Thanks for the tip, but how do i put the user data in there before the XmlHighlighVisitor is executed ?
Also, if i get this working, if i place that key in every tag in Tapestry namespace won't that solve the first problem too ?
Thanks Peter,
i thought it would be easier to reuse all the components from another language while creating my own. As a side note, i think JetBrains should look into making this easier as it would make new languages development much easier.
I tried doing:
tag.getParent().putUserData(XmlHighlightVisitor.DO_NOT_VALIDATE_KEY, "true");
or
tag.putUserData(XmlHighlightVisitor.DO_NOT_VALIDATE_KEY, "true");
if the getElementDescriptor method of my NamespaceDescriptor class but i don't see any change.
We try to do this. Unfortunately the language tree is not very reusable
since its IElementType's contain their languages in themselves. And that
is a part of your problem: you have file of your own language, but the
tree is from another one.
Any hints on how i could accomplish this ? Please....
Got it, finally :o)
Thanks again for all your help...