Multicaret problems

Hi ! I wanted to know id there is some list of common problems or things to take into account due the new multicaret system in PhpStorm 8.
For example I can see this error is thrown very often:

if (myCurrentCaret != null) {
      throw new IllegalStateException("Current caret is defined, cannot operate on other ones");

Normally is silent for the user (only visible when debugging if you put a breakpoint there for example).

But in some cases it's breaking some functionalities.
For example when I'm saving a Document:


is there any check that we should do before that?
is there any other recommendation to take into account with the new multicaret?

Comment actions Permalink

That exception is thrown when you try to invoke CaretModel.runForEachCaret method recursively. So the piece of your code must be already executing in the context of on runForEachCaret invocation (for some particular caret) and it tries to invoke another piece of code that performs some action for each caret. Usually this doesn't make sense, and code should be reorganized to avoid the exception. The solution depends on what your code is supposed to do and the context it is executing in - is it an action, editor action handler, typed handler, some other extension point implementation? I'll need more details to suggest something specific.

In your case saveDocument seems to be invoked for each caret in a multicaret action. Is it something you really need?

(The fact that saveDocument now uses runForEachCaret internally might not be very convenient, and potentially can be changed if supporting use cases will be found).

Comment actions Permalink

Hi Dimitry, you can see the full code here:

is a function to reformat code, I've opened a new thread on that because that code doesn't smell well t me so I wanted to know if there is a better and safer way to do that, on any context.
(that reformat code is executed for example inside the InsertHandler of the lookupElement, for XML CompletionContributor)

Anyway, I'm not so sure about your explanation, because when I put a breakpoint on that line: CaretModelImpl::338

throw new IllegalStateException("Current caret is defined, cannot operate on other ones");

I can see is executed a lot of times, almost for any action I do on the Editor, not only for my "custom" actions.
For example, if I edit some XML, and remove character (just press delete key), before it is removed that exception is thrown, but is silent for the user, because it is catched for some part of the code in the IDE and not logged. That sounds a bit weird.
The stacktrace for that case for example is:

     at com.intellij.openapi.editor.impl.CaretModelImpl.runForEachCaret(
     at com.intellij.openapi.editor.actionSystem.EditorActionHandler.execute(
     at com.intellij.codeInsight.lookup.impl.BackspaceHandler.doExecute(
     at com.intellij.openapi.editor.actionSystem.EditorActionHandler$4.perform(
     at com.intellij.openapi.editor.actionSystem.EditorActionHandler.doIfEnabled(
     at com.intellij.openapi.editor.actionSystem.EditorActionHandler.execute(
     at com.intellij.openapi.editor.actionSystem.EditorAction$
     at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(
     at com.intellij.openapi.editor.actionSystem.EditorAction.actionPerformed(
     at com.intellij.openapi.editor.actionSystem.EditorAction.actionPerformed(
     at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher$3.performAction(
     at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.processAction(
     at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.d(
     at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.dispatchKeyEvent(
     at com.intellij.ide.IdeEventQueue._dispatchEvent(
     at com.intellij.ide.IdeEventQueue.dispatchEvent(
     at java.awt.EventDispatchThread.pumpOneEventForFilters(
     at java.awt.EventDispatchThread.pumpEventsForFilter(
     at java.awt.EventDispatchThread.pumpEventsForHierarchy(
     at java.awt.EventDispatchThread.pumpEvents(
     at java.awt.EventDispatchThread.pumpEvents(

How you can see there isn't any code from my plugin executed there, but the exception is thrown anyway (again, silently, but is thrown...)

The problem is that with my code the save document is not working because is not silent in that case (there is a catch, not mine, so I can't change it, and that catch has a LOG inside...)

Comment actions Permalink

Are you sure that exception is thrown each time? I'm not aware of any cases where it is thrown at normal operation (and being silently catched). I can hardly imagine the case when the exception with stack trace you've provided can happen. Maybe your breakpoint in debugger is not set at line with 'throw' statement actually - please check that version of the platform binaries you are developing for matches the version of the sources you've attached to you platform SDK.

As for the problem with saveDocument, may I ask why do you need to invoke it inside InsertHandler implementation?

Comment actions Permalink

Actually that was my solution, I've done the "save document" conditional, and I'm not saving the document inside the Insert Handler.

But I thought it was a very common task to save the document after the reformat, just to have everything in sync...
I think it could be useful to understand why we should not do that (I'm afraid I could find this problem in other parts of my code too...), before the multicaret that was working fine.

Comment actions Permalink

In general, you don't need to save a document to disk explicitly unless your code need to invoke some external programs. For editor actions, like code completion, this doesn't seem to be the case.

That said, we'll fix saveDocument so that it won't lead to such exceptions in future.

Comment actions Permalink

OK, thanks Dimitry !!


Please sign in to leave a comment.