Autocompletion inserting at a wrong position

I'm writing a custom language plugin where you can invoke autocompletion. But when I choose an item from the pop up, it doesn't insert where my caret is but goes to start of the line and inserts it from there. To give you guys a better idea, I have attached two screen shots.
I invoke the popup after the token * but when I choose the item it removes it and places it on the start of the line. Should I do something to handle proper insertion of the auto completed item. Since it is inserted without a * , it changes the token type also.



Attachment(s):
2.png
1.png
15 comments
Comment actions Permalink

The default matching prefix starts for some reason from the beginning of the line. By debugging in com.intellij.codeInsight.completion.impl.CompletionServiceImpl#createResultSet, you can check why. com.intellij.codeInsight.completion.CompletionResultSet#withPrefixMatcher gives you a possibility to change that prefix.

0
Comment actions Permalink

I debugged and saw that the prefix matcher is working fine. It sets the prefix to "* ". I even changed the prefix matcher from CamelHumpMatcher which is by default to PlainPrefixMatcher. But still it inserts before *

resultSet.withPrefixMatcher(new PlainPrefixMatcher(resultSet.getPrefixMatcher().getPrefix()));

It is not because of the prefix being the start of the line. If I try to give some spaces before * and auto complete in the middle of the file, then it gets added just before the *, it doesn't go to the start of the line. I have attached the screenshots


Furthermore, I have attached the psi structure also. If they are not parsed fine (i.e) some error is present in the above lines. The identifier(*) and the Step text won't get created as children to a Step. Then when I auto complete, it gets inserted correcltly. Is it something to do with the psi structure ?



Attachment(s):
prefix working fine.png
insert in the middle.png
autocomplete in the middle.png
psistructure.jpg
0
Comment actions Permalink

Thanks! So the asterisk is the part of prefix, and it's replaced. Is this the desired behavior? If not, you should probably change the prefix so that it doesn't include the asterisk.

0
Comment actions Permalink

I tried removing the * from the prefix matcher,

resultSet.withPrefixMatcher(new PlainPrefixMatcher(""));

still doesn't seem to work. I have edited the above post to give further info.

0
Comment actions Permalink

Do you have a custom insert handler in your items? It could be removing the spaces, or invoking reformat which does this.

I'd suggest to put a breakpoint to DocumentImpl.changedUpdate, then you'll see all document changes made during completion and you'll surely understand what's happening and why.

0
Comment actions Permalink

I haven't added the custom insert handler yet. I debugged the DocumentImpl.changedUpdate after the autocompletion and saw that the event has

myOldString='*', myNewString='task1' if there is no parse error above
myOldString='', myNewString='task1' if there is a parse error above

I'm just so confused why this is happening. It should just insert the text that I want at the cursor position by default. I don't do any sort of manipulation after the insertion.

0
Comment actions Permalink

When debugging, you can also see the stack trace of the event. Please provide it. "Get Thread Dump" debugger action might be useful for that purpose.

0
Comment actions Permalink

This is the thread dump I got just before the insertion. If you guys want, i can zip the plugin project and send it to you guys.

"AWT-EventQueue-0 13.1.3#IU-135.909, eap:false [WriteAccessToken]@2391" prio=6 tid=0x1a nid=NA runnable
  java.lang.Thread.State: RUNNABLE
   at com.intellij.openapi.editor.impl.DocumentImpl.a(DocumentImpl.java:764)
   at com.intellij.openapi.editor.impl.DocumentImpl.a(DocumentImpl.java:716)
   at com.intellij.openapi.editor.impl.DocumentImpl.a(DocumentImpl.java:596)
   at com.intellij.openapi.editor.impl.DocumentImpl.replaceString(DocumentImpl.java:551)
   at com.intellij.codeInsight.lookup.impl.LookupImpl$8.perform(LookupImpl.java:725)
   at com.intellij.openapi.editor.impl.CaretModelImpl$3.run(CaretModelImpl.java:355)
   at com.intellij.openapi.editor.impl.CaretModelImpl.doWithCaretMerging(CaretModelImpl.java:426)
   at com.intellij.openapi.editor.impl.CaretModelImpl.runForEachCaret(CaretModelImpl.java:349)
   at com.intellij.codeInsight.lookup.impl.LookupImpl.a(LookupImpl.java:713)
   at com.intellij.codeInsight.lookup.impl.LookupImpl.access$800(LookupImpl.java:93)
   at com.intellij.codeInsight.lookup.impl.LookupImpl$7.run(LookupImpl.java:659)
   at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:984)
   at com.intellij.codeInsight.lookup.impl.LookupImpl.finishLookup(LookupImpl.java:655)
   at com.intellij.codeInsight.lookup.impl.LookupImpl.finishLookup(LookupImpl.java:612)
   at com.intellij.codeInsight.lookup.impl.actions.ChooseItemAction$Handler.execute(ChooseItemAction.java:73)
   at com.intellij.openapi.editor.actionSystem.EditorActionHandler.doExecute(EditorActionHandler.java:93)
   at com.intellij.openapi.editor.actionSystem.EditorActionHandler.execute(EditorActionHandler.java:125)
   at com.intellij.openapi.editor.actionSystem.EditorAction$1.run(EditorAction.java:83)
   at com.intellij.openapi.command.impl.CommandProcessorImpl.executeCommand(CommandProcessorImpl.java:124)
   at com.intellij.openapi.editor.actionSystem.EditorAction.actionPerformed(EditorAction.java:94)
   at com.intellij.openapi.editor.actionSystem.EditorAction.actionPerformed(EditorAction.java:68)
   at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher$3.performAction(IdeKeyEventDispatcher.java:564)
   at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.processAction(IdeKeyEventDispatcher.java:611)
   at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.d(IdeKeyEventDispatcher.java:463)
   at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.dispatchKeyEvent(IdeKeyEventDispatcher.java:206)
   at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:493)
   at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:335)
   at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
   at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
   at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
   at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
   at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
   at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

0
Comment actions Permalink

It still looks like "* " is included into the prefix that a particular lookup item was matched against.
Yes, if you share your plugin project, it'll definitely make the investigation easier.

0
Comment actions Permalink

I have included both plugin as well as a sample project.
In that sample project I have two .spec files in which one with parse error handles the autocompletion properly and the other doesn't.

This might be helpful for http://devnet.jetbrains.com/thread/455962 also. I have explicilty mentioned empty prefix matcher for all the completion providers.

Just run the plugin and open the sample project.



Attachment(s):
project.tar.gz
plugin.tar.gz
0
Comment actions Permalink

withPrefixMatcher creates a new CompletionResultSet and doesn't change the old one. You should use it like this:

 
resultSet = resultSet.withPrefixMatcher(new PlainPrefixMatcher(""));
0
Comment actions Permalink

Ah!! I thought resultSet was a mutable object. Many thanks Peter.

0
Comment actions Permalink

I'll make IDEA highlight unused return values of withPrefixMatcher to avoid such confusion.

0
Comment actions Permalink

How can I remove the templates surround/B and surround/P? It seems like they are getting added to the resultSet before it reaches my completionProvider, so doing a resultSet.stopHere() is of no help.

0
Comment actions Permalink

It's an IDE-wide feature that live templates are suggested so please think again whether to interfere with it. But your contributor can register itself before the live template one add call resultSet.stopHere. To do that, you should add order="first,before liveTemplates" to the completion contributor extension tag in plugin.xml

0

Please sign in to leave a comment.