diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterConnection.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterConnection.java
index aa11d0e5ce..236d039d62 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterConnection.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterConnection.java
@@ -21,7 +21,16 @@ import javax.swing.ImageIcon;
import ghidra.app.plugin.core.console.CodeCompletion;
+/**
+ * A connection between an implementation of an interpreter and its generic GUI components.
+ */
public interface InterpreterConnection {
+
+ /**
+ * Gets the title of the interpreter.
+ *
+ * @return The title of the interpreter
+ */
public String getTitle();
/**
@@ -31,15 +40,11 @@ public interface InterpreterConnection {
*/
public ImageIcon getIcon();
+ /**
+ * Gets a {@link List} of {@link CodeCompletion code completions} for the given command.
+ *
+ * @param cmd The command to get code completions for
+ * @return A {@link List} of {@link CodeCompletion code completions} for the given command
+ */
public List
++ ++ This command clears the interpreter's display. Its effect is purely visual. + It does not affect the state of the interpreter in any way. +
+
++ ++ This command issues a keyboard interrupt to the interpreter, which can be used to interrupt + long running commands or loops. +
+
+++ This command resets the interpreter, which clears the display and resets all state. +
+
-- The Ghidra Python Interpreter supports the following keybindings: + The Ghidra Python Interpreter supports the following hard-coded keybindings:
-
- CTRL+D: Clear the console and reset the interpreter
-- CTRL+I: Interrupt the interpreter
- (up): Move backward in command stack
- (down): Move forward in command stack
- TAB: Show code completion window
@@ -142,14 +163,6 @@
--- This command clears the interpreter's display. Its effect is purely visual. - It does not affect the state of the interpreter in any way. -
-
Provided by: PythonPlugin
diff --git a/Ghidra/Features/Python/src/main/java/ghidra/python/PythonPlugin.java b/Ghidra/Features/Python/src/main/java/ghidra/python/PythonPlugin.java index a1f5fd692b..f2c24b4e05 100644 --- a/Ghidra/Features/Python/src/main/java/ghidra/python/PythonPlugin.java +++ b/Ghidra/Features/Python/src/main/java/ghidra/python/PythonPlugin.java @@ -15,6 +15,7 @@ */ package ghidra.python; +import java.awt.event.KeyEvent; import java.io.*; import java.util.List; @@ -22,6 +23,9 @@ import javax.swing.ImageIcon; import org.python.core.PySystemState; +import docking.ActionContext; +import docking.DockingUtils; +import docking.action.*; import generic.jar.ResourceFile; import ghidra.app.CorePluginPackage; import ghidra.app.plugin.PluginCategoryNames; @@ -34,6 +38,7 @@ import ghidra.framework.options.ToolOptions; import ghidra.framework.plugintool.PluginInfo; import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.util.PluginStatus; +import ghidra.util.HelpLocation; import ghidra.util.task.*; import resources.ResourceManager; @@ -120,6 +125,45 @@ public class PythonPlugin extends ProgramPlugin getTool().getService(InterpreterPanelService.class).createInterpreterPanel(this, false); welcome(); console.addFirstActivationCallback(() -> resetInterpreter()); + createActions(); + } + + /** + * Creates various actions for the plugin. + */ + private void createActions() { + + // Interrupt Interpreter + DockingAction interruptAction = new DockingAction("Interrupt Interpreter", getName()) { + @Override + public void actionPerformed(ActionContext context) { + interrupt(); + } + }; + interruptAction.setDescription("Interrupt Interpreter"); + interruptAction.setToolBarData( + new ToolBarData(ResourceManager.loadImage("images/dialog-cancel.png"), null)); + interruptAction.setEnabled(true); + interruptAction.setKeyBindingData( + new KeyBindingData(KeyEvent.VK_I, DockingUtils.CONTROL_KEY_MODIFIER_MASK)); + interruptAction.setHelpLocation(new HelpLocation(getTitle(), "Interrupt_Interpreter")); + console.addAction(interruptAction); + + // Reset Interpreter + DockingAction resetAction = new DockingAction("Reset Interpreter", getName()) { + @Override + public void actionPerformed(ActionContext context) { + reset(); + } + }; + resetAction.setDescription("Reset Interpreter"); + resetAction.setToolBarData( + new ToolBarData(ResourceManager.loadImage("images/reload3.png"), null)); + resetAction.setEnabled(true); + resetAction.setKeyBindingData( + new KeyBindingData(KeyEvent.VK_D, DockingUtils.CONTROL_KEY_MODIFIER_MASK)); + resetAction.setHelpLocation(new HelpLocation(getTitle(), "Reset_Interpreter")); + console.addAction(resetAction); } /** @@ -253,7 +297,9 @@ public class PythonPlugin extends ProgramPlugin super.dispose(); } - @Override + /** + * Interrupts what the interpreter is currently doing. + */ public void interrupt() { if (interpreter == null) { return; @@ -262,7 +308,9 @@ public class PythonPlugin extends ProgramPlugin console.setPrompt(interpreter.getPrimaryPrompt()); } - @Override + /** + * Resets the interpreter's state. + */ public void reset() { // Do an interrupt in case there is a loop or something running