You can't update the document from the events that are triggered when it's updated. Otherwise you could trigger an infinite loop - updating would cause updating would cause updating. While that makes sense for textual updates, for attributes it may be a bit harsh.
The solution is surprisingly simple: make sure the updating is done at a later time, using EventQueue.invokeLater*:
After slightly modifying that code to get it to compile, I've added some debugging statements, and as soon as the first keyword was entered it entered an infinite loop. I've checked the source of DefaultStyledDocument and it fires a changedUpdate event when you call setCharacterAttributes. That means that you need to disable updates while you call this method.
I can think of two ways to do this:
1) keep a reference to your DocumentListener, remove it from the document before calling the method, then add it again afterwards.
2) keep a boolean, initially set to false, that you set to true before this call and to false after this call. Inside the event listener you check this boolean value and if it's true you don't do anything.
3) Use a DocumentFilter that conditionally calls into the super implementation or the FilterBypass's implementation.
Note: This code is woefully inefficient as it sets the attributes throughout the document at every change. I haven't tested whenther this will cause a performance hit with a longer keyword list and a long document.
edit Rectified an omission in the code
There are no new questions, but there may be new answers.