#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "binaryninjaapi.h" #include "action.h" #include "globalarea.h" #include "uitypes.h" #define SCRIPT_OUTPUT_UPDATE_INTERVAL 100 class ScriptingConsole; /*! \defgroup scriptingconsole ScriptingConsole \ingroup uiapi */ /*! \ingroup scriptingconsole */ class BINARYNINJAUIAPI ScriptingCompletionModel : public QAbstractListModel { Q_OBJECT std::vector m_completions; bool m_searching; public: ScriptingCompletionModel(QWidget* parent); virtual QModelIndex index(int row, int col, const QModelIndex& parent = QModelIndex()) const override; virtual QModelIndex parent(const QModelIndex& i) const override; virtual bool hasChildren(const QModelIndex& parent) const override; virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override; virtual int columnCount(const QModelIndex& parent) const override; virtual QVariant data(const QModelIndex& i, int role) const override; void setModelData(const std::vector& completions, bool searching); }; /*! \ingroup scriptingconsole */ class BINARYNINJAUIAPI ScriptingCompletionPopup : public QDialog { Q_OBJECT QListView* m_list; ScriptingCompletionModel* m_model; protected: virtual bool eventFilter(QObject* obj, QEvent* event) override; public: ScriptingCompletionPopup(QWidget* parent); void showWithData(QPoint pt, int cursorSize, const std::vector& completions, bool searching = false); bool handleKeyEvent(QKeyEvent* event); virtual ~ScriptingCompletionPopup(); private Q_SLOTS: void clickRow(const QModelIndex& index); Q_SIGNALS: void complete(QString text); }; /*! \ingroup scriptingconsole */ class BINARYNINJAUIAPI ScriptingConsoleEdit : public QTextEdit { Q_OBJECT public: typedef std::function(const std::string&)> CompletionCallback; private: ScriptingConsole* m_console; int m_charHeight; bool m_continuation; bool m_searching; bool m_searchError; CompletionCallback m_completionCallback; ScriptingCompletionPopup* m_popup; uint64_t m_completionRegionStart; uint64_t m_completionRegionInitialStop; uint64_t m_completionRegionStop; public: ScriptingConsoleEdit(ScriptingConsole* parent); void setCharHeight(int height); void setContinuation(bool cont); void setCompletionCallback(CompletionCallback callback) { m_completionCallback = callback; } void insertFromMimeData(const QMimeData* source) override; private Q_SLOTS: void complete(QString text); protected: virtual void keyPressEvent(QKeyEvent* event) override; }; /*! \ingroup scriptingconsole */ class BINARYNINJAUIAPI ScriptingConsoleOutput : public QPlainTextEdit { Q_OBJECT ScriptingConsole* m_console; UIActionHandler* m_handler; UIActionHandler m_actionHandler; ContextMenuManager* m_contextMenuManager; BinaryViewRef m_data; Menu* m_menu; public: ScriptingConsoleOutput(ScriptingConsole* parent, Menu* menu); bool IsNavigable(const QString& str, const std::pair& offsetLen, uint64_t& value, bool highlight) const; protected: void contextMenuEvent(QContextMenuEvent* event) override; public Q_SLOTS: virtual void mouseReleaseEvent(QMouseEvent* event) override; void viewChanged(QWidget* frame); }; class ScriptingConsoleWidget; /*! \ingroup scriptingconsole */ class BINARYNINJAUIAPI ScriptingConsole : public SidebarWidget, BinaryNinja::ScriptingOutputListener { Q_OBJECT struct ScriptOutput { std::string text; bool isError; bool isWarning; }; QString m_providerName; QString m_instanceName; ScriptingInstanceRef m_instance; ScriptingConsoleOutput* m_output; ScriptingConsoleEdit* m_input; Splitter* m_splitter; QLabel* m_prompt; QPushButton* m_button; QTimer* m_runTimer; bool m_scriptActive; BinaryNinja::Ref m_logger; std::mutex m_mutex; std::vector m_pendingOutput; QTimer* m_updateTimer; BNScriptingProviderInputReadyState m_currentState; QStringList m_history; QString m_inputOutsideHistory; int m_currentHistoryEntry; static int m_stateUpdatedEventType; private Q_SLOTS: void updateTimerEvent(); void consoleTextChanged(); void cancel(); void showCancelButton(); Q_SIGNALS: void viewChanged(QWidget* frame); void onScriptExecution(); void onScriptCompletion(); protected: void customEvent(QEvent* event) override; public: ScriptingConsole( QWidget* parent, const QString& providerName, const QString& instanceName, ScriptingInstanceRef instance); virtual ~ScriptingConsole(); QString getProviderName() const { return m_providerName; } QString getInstanceName() const { return m_instanceName; } ScriptingInstanceRef getInstance() { return m_instance; } bool getScriptIsActive() const { return m_scriptActive; } void clearConsole(); void addInput(const std::string& text); virtual void NotifyOutput(const std::string& text) override; virtual void NotifyWarning(const std::string& text) override; virtual void NotifyError(const std::string& text) override; virtual void NotifyInputReadyStateChanged(BNScriptingProviderInputReadyState state) override; virtual void notifyViewChanged(ViewFrame* frame) override; virtual void notifyFontChanged() override; virtual void focus() override; void moveUpInHistory(); void moveDownInHistory(); std::vector reverseSearch(const QString& text); void closing() override; void runScriptFromFile(const std::string& filename); }; /*! \ingroup scriptingconsole */ class BINARYNINJAUIAPI ScriptingConsoleSidebarWidgetType : public SidebarWidgetType { public: ScriptingConsoleSidebarWidgetType(); SidebarWidgetLocation defaultLocation() const override { return SidebarWidgetLocation::LeftBottom; } SidebarContextSensitivity contextSensitivity() const override { return GlobalSidebarContext; } bool alwaysShowTabs() const override { return true; } #ifdef DEMO_EDITION virtual QString noWidgetMessage() const override; #endif };