diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/moveLeftRight/MoveElementLeftRightActionHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/moveLeftRight/MoveElementLeftRightActionHandler.java
index d41efaed0e18..06fac6cef0cc 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/moveLeftRight/MoveElementLeftRightActionHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/moveLeftRight/MoveElementLeftRightActionHandler.java
@@ -33,7 +33,7 @@ public final class MoveElementLeftRightActionHandler extends EditorWriteActionHa
}
@Override
- protected boolean reverseCaretOrder() {
+ public boolean reverseCaretOrder() {
return !myIsLeft;
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/BaseMoveHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/BaseMoveHandler.java
index 6695e52228ab..ba9cbd0d118d 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/BaseMoveHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/BaseMoveHandler.java
@@ -27,7 +27,7 @@ public abstract class BaseMoveHandler extends EditorWriteActionHandler.ForEachCa
}
@Override
- protected boolean reverseCaretOrder() {
+ public boolean reverseCaretOrder() {
return isDown;
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/NamedElementDuplicateHandler.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/NamedElementDuplicateHandler.java
index a7b4848a2aa2..f32bfbbedfe9 100644
--- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/NamedElementDuplicateHandler.java
+++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/NamedElementDuplicateHandler.java
@@ -1,4 +1,4 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.editor.actions;
import com.intellij.openapi.actionSystem.DataContext;
@@ -31,6 +31,14 @@ public final class NamedElementDuplicateHandler extends EditorWriteActionHandler
return myOriginal.isEnabled(editor, caret, dataContext);
}
+ @Override
+ public boolean reverseCaretOrder() {
+ if (myOriginal instanceof EditorWriteActionHandler handler) {
+ return handler.reverseCaretOrder();
+ }
+ return false;
+ }
+
@Override
public void executeWriteAction(@NotNull Editor editor, @NotNull Caret caret, DataContext dataContext) {
Project project = editor.getProject();
@@ -63,8 +71,8 @@ public final class NamedElementDuplicateHandler extends EditorWriteActionHandler
if (range == null || psi instanceof PsiFile || !toDuplicate.contains(psi.getTextRange())) {
break;
}
- if (psi instanceof PsiNameIdentifierOwner) {
- named = ((PsiNameIdentifierOwner)psi).getNameIdentifier();
+ if (psi instanceof PsiNameIdentifierOwner owner) {
+ named = owner.getNameIdentifier();
}
psi = psi.getParent();
}
diff --git a/platform/platform-api/api-dump-unreviewed.txt b/platform/platform-api/api-dump-unreviewed.txt
index 7d8ebca1a0e0..05765f8f0f70 100644
--- a/platform/platform-api/api-dump-unreviewed.txt
+++ b/platform/platform-api/api-dump-unreviewed.txt
@@ -2046,7 +2046,7 @@ a:com.intellij.openapi.editor.actionSystem.EditorActionHandler
- isEnabled(com.intellij.openapi.editor.Editor,com.intellij.openapi.actionSystem.DataContext):Z
- f:isEnabled(com.intellij.openapi.editor.Editor,com.intellij.openapi.editor.Caret,com.intellij.openapi.actionSystem.DataContext):Z
- p:isEnabledForCaret(com.intellij.openapi.editor.Editor,com.intellij.openapi.editor.Caret,com.intellij.openapi.actionSystem.DataContext):Z
-- p:reverseCaretOrder():Z
+- reverseCaretOrder():Z
- runForAllCarets():Z
a:com.intellij.openapi.editor.actionSystem.EditorActionHandler$ForEachCaret
- com.intellij.openapi.editor.actionSystem.EditorActionHandler
diff --git a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/DynamicEditorActionHandler.java b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/DynamicEditorActionHandler.java
index 79111969b7b0..f5b7c1f79f4f 100644
--- a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/DynamicEditorActionHandler.java
+++ b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/DynamicEditorActionHandler.java
@@ -42,7 +42,7 @@ final class DynamicEditorActionHandler extends EditorActionHandler {
}
@Override
- protected boolean reverseCaretOrder() {
+ public boolean reverseCaretOrder() {
return getHandler().reverseCaretOrder();
}
diff --git a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java
index a7c99460d1e7..86406c46416f 100644
--- a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java
+++ b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java
@@ -179,7 +179,7 @@ public abstract class EditorActionHandler {
return myRunForEachCaret;
}
- protected boolean reverseCaretOrder() {
+ public boolean reverseCaretOrder() {
return false;
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/DuplicateAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/DuplicateAction.java
index 9dc9fdb33850..69f3136cb488 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/DuplicateAction.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/DuplicateAction.java
@@ -1,5 +1,4 @@
-// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.editor.actions;
import com.intellij.openapi.actionSystem.DataContext;
@@ -26,6 +25,11 @@ public final class DuplicateAction extends EditorAction {
public boolean isEnabledForCaret(@NotNull Editor editor, @NotNull Caret caret, DataContext dataContext) {
return !editor.isOneLineMode() || editor.getSelectionModel().hasSelection();
}
+
+ @Override
+ public boolean reverseCaretOrder() {
+ return true;
+ }
}
public static void duplicateLineOrSelectedBlockAtCaret(Editor editor) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/DuplicateLinesAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/DuplicateLinesAction.java
index 332fd7edbe1b..a40cd3121d27 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/DuplicateLinesAction.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/DuplicateLinesAction.java
@@ -1,4 +1,4 @@
-// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.editor.actions;
import com.intellij.openapi.actionSystem.DataContext;
@@ -36,5 +36,10 @@ public final class DuplicateLinesAction extends EditorAction {
DuplicateAction.duplicateLinesRange(editor, caretPos, caretPos);
}
}
+
+ @Override
+ public boolean reverseCaretOrder() {
+ return true;
+ }
}
}
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/EditorActionTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/EditorActionTest.java
index 9957426b060c..23cffe89c455 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/EditorActionTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/EditorActionTest.java
@@ -1,6 +1,4 @@
-/*
- * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
- */
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.editor.actions;
import com.intellij.openapi.actionSystem.ActionManager;
@@ -283,6 +281,30 @@ public class EditorActionTest extends AbstractEditorTest {
executeAction(IdeActions.ACTION_EDITOR_DUPLICATE_LINES);
checkResultByText("ab\ncd\nab\ncd");
}
+
+ public void testDuplicateLinesMultiCaretLineStart() {
+ String before = """
+ one
+ two
+ three
+ """;
+ String after = """
+ one
+ one
+ two
+ two
+ three
+ three
+ """;
+
+ initText(before);
+ executeAction(IdeActions.ACTION_EDITOR_DUPLICATE_LINES);
+ checkResultByText(after);
+
+ initText(before);
+ ctrlD();
+ checkResultByText(after);
+ }
public void testDuplicateLineWithGuardedBlock() {
initText("a\n#");