IJPL-207781 Support "Paste From History" in the terminal window

Signed-off-by: Dmitry Batkovich <dmitry.batkovich@jetbrains.com>

GitOrigin-RevId: 1168c885296d8cbd5d56966cc436afa06412d742
This commit is contained in:
Dmitry Batkovich
2026-06-12 07:11:54 +00:00
committed by intellij-monorepo-bot
parent 473992700d
commit a5c09533c6
7 changed files with 82 additions and 20 deletions
@@ -5,6 +5,7 @@ import com.intellij.ide.CopyPasteManagerEx;
import com.intellij.ide.DataManager;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionUiKind;
import com.intellij.openapi.actionSystem.ActionUpdateThread;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
@@ -35,8 +36,9 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.List;
final class PasteFromHistoryAction extends DumbAwareAction {
PasteFromHistoryAction() {
@ApiStatus.Internal
public class PasteFromHistoryAction extends DumbAwareAction {
protected PasteFromHistoryAction() {
setEnabledInModalContext(true);
}
@@ -62,7 +64,7 @@ final class PasteFromHistoryAction extends DumbAwareAction {
List<Transferable> selectedContents = chooser.getSelectedContents();
CopyPasteManagerEx copyPasteManager = CopyPasteManagerEx.getInstanceEx();
if (selectedContents.size() == 1) {
copyPasteManager.moveContentToStackTop(selectedContents.get(0));
copyPasteManager.moveContentToStackTop(selectedContents.getFirst());
}
else {
copyPasteManager.setContents(new StringSelection(chooser.getSelectedText()));
@@ -71,22 +73,25 @@ final class PasteFromHistoryAction extends DumbAwareAction {
if (editor != null) {
if (editor.isViewer()) return;
}
final AnAction pasteAction = ActionManager.getInstance().getAction(chooser.getExitCode() == getPasteSimpleExitCode()
? IdeActions.ACTION_EDITOR_PASTE_SIMPLE : IdeActions.ACTION_PASTE);
var dataContextForEvent = DataManager.getInstance().getDataContext(focusedComponent);
if (pasteAction != null && PlatformDataKeys.PASTE_PROVIDER.getData(dataContextForEvent) != null) {
AnActionEvent newEvent = new AnActionEvent(e.getInputEvent(),
dataContextForEvent,
e.getPlace(), e.getPresentation(),
ActionManager.getInstance(),
e.getModifiers());
pasteAction.actionPerformed(newEvent);
}
else {
final Action defaultPasteAction = ((JComponent)focusedComponent).getActionMap().get(DefaultEditorKit.pasteAction);
if (defaultPasteAction != null) {
defaultPasteAction.actionPerformed(new ActionEvent(focusedComponent, ActionEvent.ACTION_PERFORMED, ""));
}
performPaste(e, (JComponent)focusedComponent, chooser.getExitCode() == getPasteSimpleExitCode());
}
}
@ApiStatus.Internal
protected void performPaste(@NotNull AnActionEvent e, @NotNull JComponent focusedComponent, boolean pasteSimple) {
final AnAction pasteAction = ActionManager.getInstance().getAction(pasteSimple
? IdeActions.ACTION_EDITOR_PASTE_SIMPLE
: IdeActions.ACTION_PASTE);
var dataContextForEvent = DataManager.getInstance().getDataContext(focusedComponent);
if (pasteAction != null && PlatformDataKeys.PASTE_PROVIDER.getData(dataContextForEvent) != null) {
AnActionEvent newEvent = AnActionEvent.createEvent(pasteAction, dataContextForEvent, e.getPresentation(),
e.getPlace(), ActionUiKind.NONE, e.getInputEvent());
pasteAction.actionPerformed(newEvent);
}
else {
final Action defaultPasteAction = focusedComponent.getActionMap().get(DefaultEditorKit.pasteAction);
if (defaultPasteAction != null) {
defaultPasteAction.actionPerformed(new ActionEvent(focusedComponent, ActionEvent.ACTION_PERFORMED, ""));
}
}
}
@@ -152,7 +152,7 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase {
{"shift control T", "GotoTest", "ServiceView.ShowServices", "Terminal.NewTab"},
{"shift control TAB", "Switcher", "Diff.FocusOppositePane"},
{"shift control U", "ShelveChanges.UnshelveWithDialog", "EditorToggleCase", "Markdown.Styling.CreateLink"},
{"shift control V", "PasteMultiple", "JupyterNotebookPasteCellAboveCommandModeAction"},
{"shift control V", "PasteMultiple", "JupyterNotebookPasteCellAboveCommandModeAction", "Terminal.PasteFromHistory"},
{"shift control alt D", "UML.ShowChanges", "Console.TableResult.CloneColumn"},
{"shift control alt ENTER", "Console.Jpa.GenerateDDL", "Console.TableResult.SubmitAndCommit", "Console.Transaction.Commit",
"NotebookRunAllAction", "org.jetbrains.r.actions.RDebugAction"},
@@ -98,6 +98,19 @@
<keyboard-shortcut first-keystroke="control V" keymap="$default"/>
<keyboard-shortcut first-keystroke="shift INSERT" keymap="$default"/>
</action>
<action id="Terminal.PasteFromHistory" class="com.intellij.terminal.frontend.action.TerminalPasteFromHistoryAction"
icon="AllIcons.Actions.MenuPaste">
<keyboard-shortcut first-keystroke="control shift V" keymap="$default"/>
<!-- On XWin Ctrl+Shift+V is owned by Terminal.Paste -->
<keyboard-shortcut first-keystroke="control shift V" keymap="Default for XWin" remove="true"/>
<!-- Sublime Text rebinds Ctrl+Shift+V to $Paste -->
<keyboard-shortcut first-keystroke="control shift V" keymap="Sublime Text" remove="true"/>
<keyboard-shortcut first-keystroke="meta shift V" keymap="Mac OS X" replace-all="true"/>
<keyboard-shortcut first-keystroke="meta shift V" keymap="Mac OS X 10.5+" replace-all="true"/>
<!-- Sublime Text (Mac OS X) rebinds Cmd+Shift+V to $Paste -->
<keyboard-shortcut first-keystroke="meta shift V" keymap="Sublime Text (Mac OS X)" remove="true"/>
<keyboard-shortcut first-keystroke="meta shift V" keymap="VSCode OSX" remove="true"/>
</action>
<action id="Terminal.PasteSelection" class="com.intellij.terminal.frontend.action.TerminalPasteSelectionAction"
use-shortcut-of="EditorPasteFromX11">
<override-text place="GoToAction"/>
@@ -157,6 +170,7 @@
<reference ref="Terminal.CopyBlock"/>
<reference ref="Terminal.CopySelectedText"/>
<reference ref="Terminal.Paste"/>
<reference ref="Terminal.PasteFromHistory"/>
</group>
<group id="Terminal.PromptContextMenu">
@@ -164,6 +178,7 @@
<reference ref="EditorCut"/>
<reference ref="Terminal.CopySelectedText"/>
<reference ref="Terminal.Paste"/>
<reference ref="Terminal.PasteFromHistory"/>
<reference ref="Terminal.PromptStyle"/>
</group>
@@ -196,6 +211,7 @@
<separator/>
<reference ref="Terminal.CopySelectedText"/>
<reference ref="Terminal.Paste"/>
<reference ref="Terminal.PasteFromHistory"/>
<reference ref="Terminal.SelectAll"/>
<separator/>
<reference ref="Terminal.ClearBuffer"/>
@@ -0,0 +1,37 @@
package com.intellij.terminal.frontend.action
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.ActionPromoter
import com.intellij.openapi.actionSystem.ActionUiKind
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.ex.ActionUtil
import com.intellij.openapi.actionSystem.remoting.ActionRemoteBehaviorSpecification
import com.intellij.openapi.editor.actions.PasteFromHistoryAction
import org.jetbrains.plugins.terminal.block.util.TerminalDataContextUtils.isAlternateBufferEditor
import org.jetbrains.plugins.terminal.block.util.TerminalDataContextUtils.isAlternateBufferModelEditor
import org.jetbrains.plugins.terminal.block.util.TerminalDataContextUtils.isOutputEditor
import org.jetbrains.plugins.terminal.block.util.TerminalDataContextUtils.isOutputModelEditor
import org.jetbrains.plugins.terminal.block.util.TerminalDataContextUtils.isPromptEditor
import org.jetbrains.plugins.terminal.block.util.TerminalDataContextUtils.terminalEditor
import javax.swing.JComponent
internal class TerminalPasteFromHistoryAction
: PasteFromHistoryAction(), ActionPromoter, ActionRemoteBehaviorSpecification.Frontend {
override fun update(e: AnActionEvent) {
val editor = e.terminalEditor
e.presentation.isEnabledAndVisible = editor != null && (
editor.isPromptEditor || editor.isOutputEditor || editor.isAlternateBufferEditor || // gen1
editor.isOutputModelEditor || editor.isAlternateBufferModelEditor // gen2
)
}
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.EDT
override fun performPaste(e: AnActionEvent, focusedComponent: JComponent, pasteSimple: Boolean) {
val terminalPaste = ActionManager.getInstance().getAction("Terminal.Paste") ?: return
val newEvent = AnActionEvent.createEvent(terminalPaste, e.dataContext, null, e.place, ActionUiKind.NONE, e.inputEvent)
ActionUtil.performAction(terminalPaste, newEvent)
}
}
@@ -239,6 +239,7 @@ private class TerminalEventDispatcher(
"Terminal.SwitchFocusToEditor",
"Terminal.CopySelectedText",
"Terminal.Paste",
"Terminal.PasteFromHistory",
"Terminal.LineUp",
"Terminal.LineDown",
"Terminal.PageUp",
@@ -17,6 +17,8 @@ action.Terminal.CopySelectedText.text=Copy
action.Terminal.CopySelectedText.description=Copy selected text to clipboard
action.Terminal.Paste.text=Paste
action.Terminal.Paste.description=Paste from clipboard
action.Terminal.PasteFromHistory.text=Past_e from History\u2026
action.Terminal.PasteFromHistory.description=Paste from recent clipboards
action.Terminal.PasteSelection.text=Paste From Selection Clipboard
action.Terminal.PasteSelection.GoToAction.text=Paste From Selection Clipboard (Terminal)
action.Terminal.PasteSelection.description=Paste from selection clipboard if available, or from regular clipboard
@@ -184,6 +184,7 @@ internal abstract class TerminalEventDispatcher(
"TerminalDecreaseFontSize",
"TerminalResetFontSize",
"Terminal.Paste",
"Terminal.PasteFromHistory",
"Terminal.CopySelectedText",
"Terminal.CopyBlock"
)