void (@NotNull InputMethodEvent e) { if (myNeedToSelectPreviousChar && SystemInfo.isMac && (Registry.is("ide.mac.pressAndHold.brute.workaround") || Registry.is("ide.mac.pressAndHold.workaround") && (hasRelevantCommittedText(e) || e.getCaret() == null))) { // This is required to support input of accented characters using press-and-hold method (http://support.apple.com/kb/PH11264). // JDK currently properly supports this functionality only for TextComponent/JTextComponent descendants. // For our editor component, we need this workaround. // After https://bugs.openjdk.org/browse/JDK-8074882 is fixed, this workaround should be replaced with a proper solution. myNeedToSelectPreviousChar = false; getCaretModel().runForEachCaret(caret -> { int caretOffset = caret.getOffset(); if (caretOffset > 0) { caret.setSelection(caretOffset - 1, caretOffset); } }); } boolean isCaretMoved = false; int caretPositionToRestore = 0; int composedStartIndex = -1; int commitCount = e.getCommittedCharacterCount(); AttributedCharacterIterator text = e.getText(); // old composed text deletion Document doc = getDocument(); if (inlayLeft != null || inlayRight != null) { composedStartIndex = inlayLeft != null ? inlayLeft.getOffset() : inlayRight.getOffset(); if (inlayLeft != null) { Disposer.dispose(inlayLeft); inlayLeft = null; } if (inlayRight != null) { Disposer.dispose(inlayRight); inlayRight = null; } } if (composedRangeMarker != null) { if (!isViewer() && doc.isWritable()) { composedStartIndex = composedRangeMarker.getStartOffset(); runUndoTransparent(() -> { if (composedRangeMarker.isValid()) { doc.deleteString(composedRangeMarker.getStartOffset(), composedRangeMarker.getEndOffset()); } }); } composedRangeMarker.dispose(); composedRangeMarker = null; } if (composedStartIndex >= 0) { isCaretMoved = getCaretModel().getOffset() != composedStartIndex; if (isCaretMoved) { caretPositionToRestore = getCaretModel().getCurrentCaret().getOffset(); // if caret set further in the doc, we should add commitCount if (caretPositionToRestore > composedStartIndex) { caretPositionToRestore += commitCount; } getCaretModel().moveToOffset(composedStartIndex); } } if (text != null) { text.first(); // committed text insertion if (commitCount > 0) { for (char c = text.current(); c != CharacterIterator.DONE && commitCount > 0; c = text.next(), commitCount--) { if (c >= 0x20 && c != 0x7F) { // Hack just like in javax.swing.text.DefaultEditorKit.DefaultKeyTypedAction processKeyTyped(c); } } } // new composed text insertion if (!isViewer() && doc.isWritable()) { int composedTextIndex = text.getIndex(); if (composedTextIndex < text.getEndIndex()) { String composedString = createComposedString(composedTextIndex, text); if (Registry.is("editor.input.method.inlay")) { runUndoTransparent(() -> EditorModificationUtil.deleteSelectedTextForAllCarets(EditorImpl.this)); var offset = getCaretModel().getCurrentCaret().getOffset(); var caret = e.getCaret(); var leftLength = caret != null ? caret.getInsertionIndex() : 0; if (leftLength > 0) { inlayLeft = getInlayModel().addInlineElement(offset, false, -IME_INLAY_PRIORITY, new InputMethodInlayRenderer(composedString.substring(0, leftLength))); } if (leftLength < composedString.length()) { inlayRight = getInlayModel().addInlineElement(offset, true, IME_INLAY_PRIORITY, new InputMethodInlayRenderer(composedString.substring(leftLength))); } } else { runUndoTransparent(() -> EditorModificationUtilEx.insertStringAtCaret(EditorImpl.this, composedString, false, false)); composedRangeMarker = myDocument.createRangeMarker(getCaretModel().getOffset(), getCaretModel().getOffset() + composedString.length(), true); } } } } if (isCaretMoved) { getCaretModel().moveToOffset(caretPositionToRestore); } }