TypedHandlerDelegate not called each character

Answered

I have a problem where `TypedHandlerDelegate` is called only for the first character in a word.

Reading through the other topics in this forum, one person recommended extending `TypedActionHandlerBase` which does work, but the extension point is scheduled for removal. 

The deprecation warning says to use `TypedHandlerDelegate`, but the two are not equivalent. `TypedActionHandlerBase` is called for every character except enter, and TypedHandleDelegate only for the first character

Is there a way to get every character typed in `TypeHandlerDelegate`, or is there another extension point to use?

A minimal Example:

class EndWordIndenter : TypedHandlerDelegate() {

    private val logger = Logger.getLogger(this.className)

    override fun newTypingStarted(c: Char, editor: Editor, context: DataContext) {
        logger.info("newTypingStarted('$c')")
    }

    override fun beforeCharTyped(c: Char, project: Project, editor: Editor, file: PsiFile, fileType: FileType): Result {
        logger.info("beforeCharTyped('$c')")
        return Result.CONTINUE
    }

    override fun charTyped(c: Char, project: Project, editor: Editor, file: PsiFile): Result {
        logger.info("charTyped('$c')")
        return Result.CONTINUE
    }

}

 

Typing kill ownr endm

Logs:

newTypingStarted('k')
beforeCharTyped('k')
charTyped('k')
newTypingStarted(' ')
beforeCharTyped(' ')
charTyped(' ')
newTypingStarted('o')
beforeCharTyped('o')
charTyped('o')
newTypingStarted('e')
beforeCharTyped('e')
charTyped('e')
newTypingStarted('e')
beforeCharTyped('e')
charTyped('e')

With TypedActionHandlerBase

class TypedActionEndWordIndenter(handler: TypedActionHandler) : TypedActionHandlerBase(handler) {

    private val logger = Logger.getLogger(this.className)

    override fun execute(editor: Editor, c: Char, context: DataContext) {
        super.myOriginalHandler?.execute(editor, c, context)
        logger.info("Character '$c' typed")
    }
}

Typing the same code: kill ownr endm

Logs:


Character 'k' typed
Character 'i' typed
Character 'l' typed
Character 'l' typed
Character ' ' typed
Character 'o' typed
Character 'w' typed
Character 'n' typed
Character 'r' typed
Character 'e' typed
Character 'n' typed
Character 'd' typed
Character 'm' typed

Running both extension points at the same time yields:

TypedHandlerDelegate - newTypingStarted('k')
TypedHandlerDelegate - beforeCharTyped('k')
TypedHandlerDelegate - charTyped('k')
TypedActionHandler - Character 'k' typed
TypedActionHandler - Character 'i' typed
TypedActionHandler - Character 'l' typed
TypedActionHandler - Character 'l' typed
TypedHandlerDelegate - newTypingStarted(' ')
TypedHandlerDelegate - beforeCharTyped(' ')
TypedHandlerDelegate - charTyped(' ')
TypedActionHandler - Character ' ' typed
TypedHandlerDelegate - newTypingStarted('o')
TypedHandlerDelegate - beforeCharTyped('o')
TypedHandlerDelegate - charTyped('o')
TypedActionHandler - Character 'o' typed
TypedActionHandler - Character 'w' typed
TypedActionHandler - Character 'n' typed
TypedActionHandler - Character 'r' typed
TypedHandlerDelegate - newTypingStarted('e')
TypedHandlerDelegate - beforeCharTyped('e')
TypedHandlerDelegate - charTyped('e')
TypedActionHandler - Character 'e' typed
TypedActionHandler - Character 'n' typed
TypedActionHandler - Character 'd' typed
TypedActionHandler - Character 'm' typed

 

UPDATE: Added checkAutoPopup  and it still does not work. That method is called even less often, even with a popup.

override fun checkAutoPopup(charTyped: Char, project: Project, editor: Editor, file: PsiFile): Result {
        logger.info("checkAutoPopup('$charTyped')")
        return Result.CONTINUE
    }

 

0
5 comments

Hi Dan,

It should be called for each character. Maybe another handler stops your handler?

Try adding order="first" in your extension registration. If it doesn't help, try to debug to find out if there actually is a stopping handler, and if it is registered as first too and has an ID, you can push yours before it with order="first,before xyz".

0

So I registered my TypedHandlerDelegate as first, but CompletionAutoPopup was called first, so I added order="first, before completionAutoPopup".  But it made no difference.


That had my handler called first, but it still was not receiving every letter when typing. 

It does NOT work when the completion popup window is visible. I have to press escape, to clear autocomplete, and then I can type the final character and then each method is called on the character.

I overwrote checkAutoPopup, but it does not get called when popup is up either.

TypedActionHandler works perfectly, but will be removed in the future according to the docs.

0

Hi,

The completion popup was a missing part to reproduce it.

Could you please describe your use case?

0

The reason I would like to check the character typed is because I want to detect when the final letter of certain commands are typed and reformat the code in between the start and end keywords.
An example would be typing the i in endi

doif 10 < 11
addv va00 11
end[i]

So on typing i, I want the code between doif and endi to indent to become:

doif 10 < 11
    addv va00 1
endi

 

There may be a better extension point all together to support this, but I am not aware of one. I was not able to use words for the brace matching.

0

Hi Dan,

Indeed, this solution seems hacky and there is a better API for this case. You can take a look at the Formatter docs, especially this section: https://plugins.jetbrains.com/docs/intellij/code-formatting.html#building-the-block-tree

The other two more intricate methods that need to be implemented are getChildAttributes() and isIncomplete(). Both are important when determining what indentation to use when Enter is pressed. (…)

Implementing it properly will auto indent your code while pressing enter.

0

Please sign in to leave a comment.