diff --git a/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java b/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java index 9b202db4a690..517ed431e8aa 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java +++ b/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java @@ -22,6 +22,8 @@ import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; + public class ConsoleExecuteAction extends DumbAwareAction { static final String CONSOLE_EXECUTE_ACTION_ID = "Console.Execute"; @@ -47,7 +49,15 @@ public class ConsoleExecuteAction extends DumbAwareAction { @NotNull ConsoleExecuteActionHandler executeActionHandler, @NotNull String emptyExecuteActionId, @Nullable Condition enabledCondition) { - super(AllIcons.Actions.Execute); + this(consoleView, executeActionHandler, emptyExecuteActionId, enabledCondition, AllIcons.Actions.Execute); + } + + public ConsoleExecuteAction(@NotNull LanguageConsoleView consoleView, + @NotNull ConsoleExecuteActionHandler executeActionHandler, + @NotNull String emptyExecuteActionId, + @Nullable Condition enabledCondition, + @NotNull Icon actionIcon) { + super(actionIcon); myConsoleView = consoleView; myExecuteActionHandler = executeActionHandler; diff --git a/python/pluginResources/messages/PyBundle.properties b/python/pluginResources/messages/PyBundle.properties index 59cc554bc65e..c45dc9e5e69c 100644 --- a/python/pluginResources/messages/PyBundle.properties +++ b/python/pluginResources/messages/PyBundle.properties @@ -868,6 +868,10 @@ debugger.progress.title.stackframe.processing=StackFrame processing python.local.attach.group.name=Python pydev.console.runner.settings=Settings +pydev.console.runner.output.actions=Output Actions +pydev.console.runner.copy.console.output.text=Copy Console Output +pydev.console.runner.copy.console.output.description=Copy to clipboard console output + pydev.console.runner.error.running.console=Error running console pydev.console.runner.python.console.debugger=Python Console Debugger pydev.console.runner.unknown.error=Unknown error diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java b/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java index c7ce24855536..20ea08e4331f 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java @@ -40,9 +40,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkAdditionalData; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.NlsContexts; -import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.registry.RegistryManager; @@ -68,6 +66,8 @@ import com.intellij.xdebugger.XDebuggerManager; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PySdkBundle; import com.jetbrains.python.PythonPluginDisposable; +import com.jetbrains.python.console.actions.ConsoleCopyOutputAction; +import com.jetbrains.python.console.actions.ScrollToTheEndAction; import com.jetbrains.python.console.actions.ShowCommandQueueAction; import com.jetbrains.python.console.actions.ShowVarsAction; import com.jetbrains.python.console.pydev.ConsoleCommunicationListener; @@ -220,10 +220,16 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { // Execute actions.add( new ConsoleExecuteAction(myConsoleView, myConsoleExecuteActionHandler, myConsoleExecuteActionHandler.getEmptyExecuteAction(), - myConsoleExecuteActionHandler)); + myConsoleExecuteActionHandler, PythonIcons.Python.ExecuteCurrentStatement)); toolbarActions.addAll(actions); // Attach Debugger toolbarActions.add(new ConnectDebuggerAction()); + // Show Queue + toolbarActions.add(new ShowCommandQueueAction(myConsoleView)); + // Scroll to the end + toolbarActions.add(new ScrollToTheEndAction(myConsoleView.getEditor())); + // Separator + toolbarActions.add(Separator.create()); // Settings DefaultActionGroup settings = DefaultActionGroup.createPopupGroup(() -> PyBundle.message("pydev.console.runner.settings")); settings.getTemplatePresentation().setIcon(AllIcons.General.GearPlain); @@ -231,9 +237,17 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { settings.add(new PyVariableViewSettings.VariablesPolicyGroup()); settings.add(new PyVariableViewSettings.QuotingPolicyGroup()); toolbarActions.add(settings); - // New console - toolbarActions.add(new NewConsoleAction()); - + // Output actions + DefaultActionGroup outputActions = DefaultActionGroup.createPopupGroup(() -> PyBundle.message("pydev.console.runner.output.actions")); + outputActions.getTemplatePresentation().setIcon(AllIcons.General.InspectionsEye); + outputActions.add(new ShowVarsAction(myConsoleView, myPydevConsoleCommunication)); // Show Variables + outputActions.add(new SoftWrapAction()); // Use soft wraps + outputActions.add(Separator.create()); + outputActions.add(ConsoleHistoryController.getController(myConsoleView).getBrowseHistory()); // Console History + outputActions.add(new ConsoleCopyOutputAction(myConsoleView)); // Copy Console Output + outputActions.add(Separator.create()); + outputActions.add(PyConsoleUtil.createPrintAction(myConsoleView)); // Print + toolbarActions.add(outputActions); // Actions without icons actions.add(PyConsoleUtil.createInterruptAction(myConsoleView)); actions.add(PyConsoleUtil.createTabCompletionAction(myConsoleView)); @@ -242,23 +256,6 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { return actions; } - private List fillOutputActionsToolbar(final DefaultActionGroup toolbarActions) { - List actions = new ArrayList<>(); - // Use soft wraps - actions.add(new SoftWrapAction()); - // Scroll to the end - actions.add(PyConsoleUtil.createScrollToEndAction(myConsoleView.getEditor())); - // Print - actions.add(PyConsoleUtil.createPrintAction(myConsoleView)); - // Show Variables - actions.add(new ShowVarsAction(myConsoleView, myPydevConsoleCommunication)); - // Show Queue - actions.add(new ShowCommandQueueAction(myConsoleView)); - // Console History - actions.add(ConsoleHistoryController.getController(myConsoleView).getBrowseHistory()); - toolbarActions.addAll(actions); - return actions; - } @Override public void open() { @@ -940,15 +937,6 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { // tool bar actions final List actions = fillRunActionsToolbar(runToolbarActions); - final List outputActions; - if (!isHorizontalAndUnitedToolbar) { - outputActions = fillOutputActionsToolbar(outputToolbarActions); - } - else { - runToolbarActions.add(new Separator()); - outputActions = fillOutputActionsToolbar(runToolbarActions); - } - actions.addAll(outputActions); registerActionShortcuts(actions, myConsoleView.getConsoleEditor().getComponent()); registerActionShortcuts(actions, mainPanel); @@ -1233,7 +1221,7 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { ConnectDebuggerAction() { super(PyBundle.messagePointer("console.attach.debugger"), PyBundle.messagePointer("console.attach.debugger.description"), - AllIcons.Actions.StartDebugger); + PythonIcons.Python.AttachDebugger); } @Override @@ -1277,34 +1265,6 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { } } - - private static class NewConsoleAction extends AnAction implements DumbAware { - NewConsoleAction() { - super(PyBundle.messagePointer("console.new.console"), PyBundle.messagePointer("console.new.console.description"), - AllIcons.General.Add); - } - - @Override - public void update(@NotNull AnActionEvent e) { - e.getPresentation().setEnabled(true); - } - - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - final Project project = e.getData(CommonDataKeys.PROJECT); - if (project != null) { - PydevConsoleRunner runner = - PythonConsoleRunnerFactory.getInstance().createConsoleRunner(project, e.getData(PlatformCoreDataKeys.MODULE)); - runner.run(true); - } - } - - @Override - public @NotNull ActionUpdateThread getActionUpdateThread() { - return ActionUpdateThread.BGT; - } - } - private XDebugSession connectToDebugger() throws ExecutionException { final ServerSocket serverSocket = PythonCommandLineState.createServerSocket(); diff --git a/python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java b/python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java index 9fe7e8a99d4e..20dd3ad93ce8 100644 --- a/python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java +++ b/python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java @@ -5,6 +5,9 @@ import com.google.common.base.Function; import com.google.common.base.Predicates; import com.google.common.collect.FluentIterable; import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.util.Disposer; @@ -12,10 +15,12 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.openapi.wm.ex.ToolWindowEx; import com.intellij.openapi.wm.ex.ToolWindowManagerListener; import com.intellij.openapi.wm.impl.content.ToolWindowContentUi; import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentFactory; +import com.jetbrains.python.PyBundle; import icons.PythonIcons; import kotlin.Unit; import org.jetbrains.annotations.NotNull; @@ -55,6 +60,10 @@ public final class PythonConsoleToolWindow { if (!myInitialized) { doInit(toolWindow); } + + if (toolWindow instanceof ToolWindowEx toolWindowEx) { + toolWindowEx.setTabActions(new NewConsoleAction()); + } } public boolean isInitialized() { @@ -147,4 +156,31 @@ public final class PythonConsoleToolWindow { public @Nullable RunContentDescriptor getSelectedContentDescriptor() { return CONTENT_TO_DESCRIPTOR_FUNCTION.apply(getToolWindow(myProject).getContentManager().getSelectedContent()); } + + private static class NewConsoleAction extends AnAction implements DumbAware { + NewConsoleAction() { + super(PyBundle.messagePointer("console.new.console"), PyBundle.messagePointer("console.new.console.description"), + AllIcons.General.Add); + } + + @Override + public void update(@NotNull AnActionEvent e) { + e.getPresentation().setEnabled(true); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + final Project project = e.getData(CommonDataKeys.PROJECT); + if (project != null) { + PydevConsoleRunner runner = + PythonConsoleRunnerFactory.getInstance().createConsoleRunner(project, e.getData(PlatformCoreDataKeys.MODULE)); + runner.run(true); + } + } + + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.BGT; + } + } } \ No newline at end of file diff --git a/python/src/com/jetbrains/python/console/actions/ConsoleCopyOutputAction.kt b/python/src/com/jetbrains/python/console/actions/ConsoleCopyOutputAction.kt new file mode 100644 index 000000000000..760e8abca314 --- /dev/null +++ b/python/src/com/jetbrains/python/console/actions/ConsoleCopyOutputAction.kt @@ -0,0 +1,19 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.console.actions + +import com.intellij.icons.AllIcons +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.ide.CopyPasteManager +import com.jetbrains.python.PyBundle +import com.jetbrains.python.console.PythonConsoleView +import java.awt.datatransfer.StringSelection + +class ConsoleCopyOutputAction(private val consoleView: PythonConsoleView): AnAction(PyBundle.message("pydev.console.runner.copy.console.output.text"), + PyBundle.message("pydev.console.runner.copy.console.output.description"), + AllIcons.Actions.Copy) { + override fun actionPerformed(e: AnActionEvent) { + val content = consoleView.historyViewer.document.charsSequence.toString() + CopyPasteManager.getInstance().setContents(StringSelection(content)) + } +} \ No newline at end of file diff --git a/python/src/com/jetbrains/python/console/actions/ScrollToTheEndAction.kt b/python/src/com/jetbrains/python/console/actions/ScrollToTheEndAction.kt new file mode 100644 index 000000000000..298c6b9f0022 --- /dev/null +++ b/python/src/com/jetbrains/python/console/actions/ScrollToTheEndAction.kt @@ -0,0 +1,20 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.console.actions + +import com.intellij.icons.AllIcons +import com.intellij.idea.ActionsBundle +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.ex.util.EditorUtil + +class ScrollToTheEndAction(private val editor: Editor) : AnAction(ActionsBundle.message("action.EditorConsoleScrollToTheEnd.text"), + ActionsBundle.message("action.EditorConsoleScrollToTheEnd.text"), + AllIcons.RunConfigurations.Scroll_down) { + override fun actionPerformed(e: AnActionEvent) { + EditorUtil.scrollToTheEnd(editor) + } + + override fun getActionUpdateThread() = ActionUpdateThread.EDT +} \ No newline at end of file