void (@NotNull Editor editor, @NotNull SelectionListener listener, @NotNull Disposable disposable) { Ref<Pair<int[], int[]>> selectionBeforeBulkChange = new Ref<>(); Ref<Boolean> selectionChangedDuringBulkChange = new Ref<>(); editor.getSelectionModel().addSelectionListener(new SelectionListener() { @Override public void selectionChanged(@NotNull SelectionEvent e) { if (selectionBeforeBulkChange.isNull()) { listener.selectionChanged(e); } else { selectionChangedDuringBulkChange.set(Boolean.TRUE); } } }, disposable); editor.getCaretModel().addCaretActionListener(new CaretActionListener() { @Override public void beforeAllCaretsAction() { selectionBeforeBulkChange.set(getSelectionOffsets()); selectionChangedDuringBulkChange.set(null); } @Override public void afterAllCaretsAction() { if (!selectionChangedDuringBulkChange.isNull()) { Pair<int[], int[]> beforeBulk = selectionBeforeBulkChange.get(); Pair<int[], int[]> afterBulk = getSelectionOffsets(); listener.selectionChanged(new SelectionEvent(editor, beforeBulk.first, beforeBulk.second, afterBulk.first, afterBulk.second)); } selectionBeforeBulkChange.set(null); } private Pair<int[], int[]> getSelectionOffsets() { return Pair.create(editor.getSelectionModel().getBlockSelectionStarts(), editor.getSelectionModel().getBlockSelectionEnds()); } }, disposable); }