custom intention to import class in injected language

Hi!

My EXML plugin (sources in this git repo) uses a special XML format (much like MXML) that contains inline ActionScript code. I managed to set up language injection to do syntax highlighting and completion correctly, but I would like the "import class" intention to be handled differently. Currently, the import statement is inserted directly at the start of the code fragment, but in EXML, imports are supposed to be top-level XML elements.
I'm a bit lost where to start. The Flex plugin must handle MXML in a similar way, so there must be a way to do this.
Any hint / pointer would be appreciated!

Greetings,
-Frank-

9 comments
Comment actions Permalink

Okay, so please does anyone have any general hints where to start if I want to implement a custom "intention" action, i.e. influence what happens when you press Alt+Return? Especially example code would be very helpful!

0
Comment actions Permalink

In your initComponent:

IntentionManager.getInstance().addAction(new MyIntentionAction());


...where MyIntentionAction is an instance of IntentionAction (see its javadoc for more information).

0
Comment actions Permalink

Hello Ronnie,

Please do not do this in initComponent(). Use the  extension
point instead.

In your initComponent:

IntentionManager.getInstance().addAction(new
> MyIntentionAction());


..where MyIntentionAction is an instance of IntentionAction (see its
javadoc for more information).


--
Dmitry Jemerov
Development Lead
JetBrains, Inc.
http://www.jetbrains.com/
"Develop with Pleasure!"


0
Comment actions Permalink

yole wrote:

Hello Ronnie,

Please do not do this in initComponent(). Use the  extension
point instead.

--
Dmitry Jemerov
Development Lead
JetBrains, Inc.
http://www.jetbrains.com/
"Develop with Pleasure!"


You are of course right about this :) I sometines use initComponent and often projectOpened (for easily hot-swapping the sandbox) when prototyping various things.

The correct way is to register the intention action by using the extension point com.intellij.intentionAction in your plugin.xml.

0
Comment actions Permalink

I just checked the Flex plugin, and instead of intentionAction, it uses the extension point com.intellij.referenceImporter, which in turn instantiates and executes an IntentionAction.
I tried to implement a custom referenceImporter, but it seems my class is not even loaded (no debugging possible, no check mark in red dot).

<extensions defaultExtensionNs="com.intellij">
  <referenceImporter implementation="net.jangaroo.ide.idea.exml.ExmlReferenceImporter"/>
</extensions>


...where ExmlReferenceImporter implements com.intellij.codeInsight.daemon.ReferenceImporter. The only method, autoImportReferenceAtCursor, is never called.
I could not find any documentation of this feature, can anyone help out?

Like several others in this forum who develop plugins with IDEA 10.0.2, I also see the following exception (not sure if it has anything to do with my problem):

ERROR: gnu/trove/THashSet
java.lang.NoClassDefFoundError: gnu/trove/THashSet
    at com.intellij.openapi.util.Disposer.<clinit>(Disposer.java:33)
    at com.intellij.util.Timed.disposeTimed(Timed.java:96)
    at com.intellij.util.Timed$1.run(Timed.java:81)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
    at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317)
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:98)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(ScheduledThreadPoolExecutor.java:181)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:205)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.ClassNotFoundException: gnu.trove.THashSet
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
    ... 12 more

0
Comment actions Permalink

Hello Frank,

This is not "instead". The referenceImporter is used in very specific cases,
such as trying to invoke completion when the reference before the caret is
unresolved. The actual auto-import is implemented by registering a quickfix
for the unresolved reference inspection. I don't think this is pluggable
for Flex, however, you still can use IntentionAction to perform auto-import
in your case.

Note that you can find complete information on how the referenceImporter
is used in the CE source code.

I just checked the Flex plugin, and instead of intentionAction, it
uses the extension point com.intellij.referenceImporter, which in turn
instantiates and executes an IntentionAction.

I tried to implement a custom referenceImporter, but it seems my class
is not even loaded (no debugging possible, no check mark in red dot).

 defaultExtensionNs="com.intellij">
>  implementation="net.jangaroo.ide.idea.exml.ExmlReferenceImporter"/>
> ]]>

..where ExmlReferenceImporter implements
com.intellij.codeInsight.daemon.ReferenceImporter. The only method,
autoImportReferenceAtCursor, is never called.

I could not find any documentation of this feature, can anyone help
out?

Like several others in this forum who develop plugins with IDEA
10.0.2, I also see the following exception (not sure if it has
anything to do with my problem):

ERROR: gnu/trove/THashSet
java.lang.NoClassDefFoundError: gnu/trove/THashSet
at com.intellij.openapi.util.Disposer.<clinit>(Disposer.java:33)
at com.intellij.util.Timed.disposeTimed(Timed.java:96)
at com.intellij.util.Timed$1.run(Timed.java:81)
at
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441
)
at
java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:
317)
at
java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150)
at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.a
ccess$101(ScheduledThreadPoolExecutor.java:98)
at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.r
unPeriodic(ScheduledThreadPoolExecutor.java:181)
at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.r
un(ScheduledThreadPoolExecutor.java:205)
at
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecu
tor.java:886)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.
java:908)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.ClassNotFoundException: gnu.trove.THashSet
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
... 12 more
---
Original message URL:
http://devnet.jetbrains.net/message/5298765#5298765


--
Dmitry Jemerov
Development Lead
JetBrains, Inc.
http://www.jetbrains.com/
"Develop with Pleasure!"


0
Comment actions Permalink

Thanks Dmitry,

okay, I think I'm beginning to understand. I managed to implement a custom IntentionAction that actually gets called.

However, what I want to achieve is very similar to com.intellij.lang.javascript.flex.AddImportECMAScriptClassOrFunctionAction. I managed to identify this class to provide the (in case of EXML) wrong QuickFix.
EXML consists of XML containing ActionScript code fragments. Similar to MXML, classes used in these code fragments should be imported at the top of the containing XML file (using special XML elements). But AddImportECMAScriptClassOrFunctionAction inserts the import declaration directly at the beginning of the code fragment.
When looking at the method signature of AddImportECMAScriptClassOrFunctionAction's constructor, it receives two arguments (Editor and PsiPolyVariantReference). It seems this class is not registered through an extension point, as you describe, but constructed from code. So how can I tweak the behavior? How can my custom IntentionAction receive the same "context" to work on? I would like to reuse as much as possible, because only the actual manipulation of the code is different, everything else (show the hint, find and display suggestions, let the user select one) is the same!

One more thing: what about the com.intellij.codeInsight.unresolvedReferenceQuickFixProvider? Is this where you register custom com.intellij.codeInspection.QuickFix classes? Sounds like it could help in my use case, too...

-Frank-

0
Comment actions Permalink

I'm still stuck at this point, anyone who could help?

0
Comment actions Permalink

Hello Frank,

When looking at the method signature of
AddImportECMAScriptClassOrFunctionAction's constructor, it receives
two arguments (Editor and PsiPolyVariantReference). It seems this
class is not registered through an extension point, as you describe,
but constructed from code. So how can I tweak the behavior? How can my
custom IntentionAction receive the same "context" to work on? I would
like to reuse as much as possible, because only the actual
manipulation of the code is different, everything else (show the hint,
find and display suggestions, let the user select one) is the same!


Your IntentionAction receives an Editor and a PsiFile as context. You can
use editor.getCaretModel().getCaretOffset() to find where the cart is, then
file.findReferenceAt() to find the reference.

One more thing: what about the
com.intellij.codeInsight.unresolvedReferenceQuickFixProvider? Is this
where you register custom com.intellij.codeInspection.QuickFix
classes? Sounds like it could help in my use case, too...


At the moment this extension point is used only for unresolved references
in Java and XML. It could be used for ActionScript as well, but right now
it's not.

--
Dmitry Jemerov
Development Lead
JetBrains, Inc.
http://www.jetbrains.com/
"Develop with Pleasure!"


0

Please sign in to leave a comment.