void (@NotNull Editor editor, @Nullable Caret caret, DataContext dataContext) { if (caret == null) caret = editor.getCaretModel().getPrimaryCaret(); Document document = editor.getDocument(); Couple<Integer> lineRange = getTargetLineRange(caret); if (lineRange == null) { return; } int startLine = lineRange.first; int endLine = lineRange.second; int lineCount = endLine - startLine + 1; String[] lines = new String[lineCount]; for (int i = 0; i < lineCount; i++) { int line = i + startLine; lines[i] = document.getText(new TextRange(document.getLineStartOffset(line), document.getLineEndOffset(line))); } boolean hasSelection = caret.hasSelection(); String caretLineContent = null; int caretOffsetInLine = 0; if (!hasSelection) { int caretLine = caret.getLogicalPosition().line; if (caretLine <= endLine) { caretLineContent = lines[caretLine - startLine]; caretOffsetInLine = caret.getOffset() - document.getLineStartOffset(caretLine); } } permute(lines); String newContent = String.join("\n", lines); int toReplaceStart = document.getLineStartOffset(startLine); int toReplaceEnd = document.getLineEndOffset(endLine); document.replaceString(toReplaceStart, toReplaceEnd, newContent); if (hasSelection) { int selectionEnd = endLine < document.getLineCount() - 1 ? document.getLineStartOffset(endLine + 1) : document.getTextLength(); caret.moveToOffset(selectionEnd); caret.setSelection(toReplaceStart, selectionEnd); } else if (caretLineContent != null) { for (int i = 0; i < lineCount; i++) { if (Strings.areSameInstance(lines[i], caretLineContent)) { caret.moveToOffset(document.getLineStartOffset(startLine + i) + caretOffsetInLine); break; } } } editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); }