summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
authorGlenn Smith <glenn@vector35.com>2021-02-17 15:46:30 -0500
committerGlenn Smith <glenn@vector35.com>2026-01-13 14:53:21 -0500
commit0328331722401185967591561440651065055658 (patch)
treea4fed674fe645a42d1b5153ad2b00c2e42bd802e /ui
parentc68f8d48afb9b3e6cdac363c8a578a051ad6e21d (diff)
Command Palette enhancements
Diffstat (limited to 'ui')
-rw-r--r--ui/commandpalette.h215
-rw-r--r--ui/flowgraphwidget.h1
-rw-r--r--ui/linearview.h1
-rw-r--r--ui/tokenizedtextview.h1
-rw-r--r--ui/viewframe.h16
5 files changed, 210 insertions, 24 deletions
diff --git a/ui/commandpalette.h b/ui/commandpalette.h
index fcb27b31..8fb20cd6 100644
--- a/ui/commandpalette.h
+++ b/ui/commandpalette.h
@@ -5,6 +5,7 @@
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QFrame>
#include <QtCore/QPointer>
+#include <QtCore/QThread>
#include <QtWidgets/QStyledItemDelegate>
#include <vector>
#include "action.h"
@@ -21,14 +22,132 @@
*/
struct BINARYNINJAUIAPI CommandListItem
{
+ enum CommandListItemType
+ {
+ // Index is serialized so only to add to the end
+ Help,
+ UIAction,
+ OpenTab,
+ NavigationHistory,
+ RecentFile,
+ RecentProject,
+ ProjectFile,
+ Expression,
+ RecentExpression,
+ Function,
+ Symbol,
+ Type,
+ String,
+ DerivedString,
+ LastItemType
+ };
+
+ CommandListItemType type;
QString name;
+ QString secondary;
QString shortcut;
- QString action;
+ QString extraSearchableText;
+ QVariant action;
+ Qt::TextElideMode secondaryElide = Qt::ElideRight;
+ bool addToRecents = true;
+ bool includeUnfiltered = true;
+ int score = 0;
+};
+
+
+/*!
+
+ \ingroup commandpalette
+*/
+struct BINARYNINJAUIAPI CommandListItemSearchInfo
+{
+ std::unordered_set<CommandListItem::CommandListItemType> types;
+ QString name;
+ QString searchName;
+ std::string prefix;
+ QKeySequence shortcut;
+
+ static std::vector<CommandListItemSearchInfo> GetSearchTypes();
};
+
class CommandPalette;
class CommandListFilter;
+class CommandListGenerateWorker : public QObject
+{
+ Q_OBJECT
+
+ BinaryViewRef m_view;
+ bool m_aborted;
+ int m_request;
+ std::shared_ptr<std::atomic_int> m_latestRequest;
+
+ bool m_pending;
+ std::vector<CommandListItem> m_pendingItems;
+ std::mutex m_pendingItemsMutex;
+
+public:
+ explicit CommandListGenerateWorker(QObject* parent, std::shared_ptr<std::atomic_int> request, const UIActionContext& context);
+ virtual ~CommandListGenerateWorker();
+
+Q_SIGNALS:
+ void dataFetched(int request, const std::vector<CommandListItem>& items);
+ void noMoreDataToFetch(int request);
+ void workFinished(int request);
+
+public Q_SLOTS:
+ void fetchMore();
+ void start();
+ void abort();
+};
+
+
+class CommandListScoreWorker : public QObject
+{
+public:
+ enum OrderStrategy
+ {
+ DefaultOrder,
+ ScoreOrder
+ };
+
+private:
+ Q_OBJECT
+
+ bool m_aborted;
+ int m_request;
+ std::shared_ptr<std::atomic_int> m_latestRequest;
+ QString m_filter;
+ std::shared_ptr<std::vector<CommandListItem>> m_items;
+ std::vector<int> m_oldItemScores;
+ OrderStrategy m_strategy;
+
+ bool m_pending;
+ std::vector<std::pair<CommandListItem*, int>> m_pendingItems;
+ std::mutex m_pendingItemsMutex;
+
+public:
+ explicit CommandListScoreWorker(
+ QObject* parent,
+ std::shared_ptr<std::atomic_int> request,
+ QString filter,
+ std::shared_ptr<std::vector<CommandListItem>> items,
+ OrderStrategy orderStrategy
+ );
+ virtual ~CommandListScoreWorker();
+
+Q_SIGNALS:
+ void dataFetched(int request, const std::vector<std::pair<CommandListItem*, int>>& items);
+ void noMoreDataToFetch(int request);
+ void workFinished(int request);
+
+public Q_SLOTS:
+ void fetchMore();
+ void start();
+ void abort();
+};
+
/*!
@@ -54,17 +173,40 @@ class BINARYNINJAUIAPI CommandListModel : public QAbstractItemModel
{
Q_OBJECT
- std::vector<CommandListItem> m_items;
- std::vector<CommandListItem> m_allItems;
+ UIActionHandler* m_handler;
+ UIActionContext m_context;
+
+ std::shared_ptr<std::vector<CommandListItem>> m_allItems;
+ std::vector<CommandListItem*> m_displayItems; // pointers into m_allItems
+ QString m_filterText;
+ bool m_updatesPaused;
- std::vector<QString> m_recentItems;
- size_t m_maxRecentItems;
+ std::vector<CommandListItem> m_recentItems;
- bool isFilterMatch(const QString& name, const QString& filter);
- int getFilterMatchScore(const QString& name, const QString& filter);
+ QThread m_generateWorkerThread;
+ CommandListGenerateWorker* m_generateWorker;
+ std::shared_ptr<std::atomic_int> m_generateWorkerRequest;
+ QTimer m_generateFetchTimer;
+ bool m_generateMoreToFetch;
- public:
- CommandListModel(QWidget* parent, const std::vector<CommandListItem>& items);
+ QTimer m_scoreTimer;
+ QMetaObject::Connection m_scoreTimerConnection;
+
+ QThread m_scoreWorkerThread;
+ CommandListScoreWorker* m_scoreWorker;
+ std::shared_ptr<std::atomic_int> m_scoreWorkerRequest;
+ QTimer m_scoreFetchTimer;
+ bool m_scoreMoreToFetch;
+
+ void loadRecentItems();
+ std::vector<CommandListItem> generateFastCommandList();
+ void sortCommandList(std::vector<CommandListItem>& list);
+ void mergeCommandList(std::vector<CommandListItem>& output, std::vector<CommandListItem>&& input);
+ void startScoreListThread();
+
+public:
+ CommandListModel(QWidget* parent);
+ ~CommandListModel();
virtual QModelIndex index(int row, int col, const QModelIndex& parent) const override;
virtual QModelIndex parent(const QModelIndex& i) const override;
@@ -73,10 +215,33 @@ class BINARYNINJAUIAPI CommandListModel : public QAbstractItemModel
virtual int columnCount(const QModelIndex& parent) const override;
virtual QVariant data(const QModelIndex& i, int role) const override;
- QString getActionForItem(int row);
+ CommandListItem getItem(int row);
void setFilterText(const QString& text);
- size_t getRecentPosition(const QString& name) const;
- void addRecentItem(const QString& name);
+ size_t getRecentPosition(const CommandListItem& item) const;
+ void addRecentItem(const CommandListItem& item);
+
+ void clearCommandList();
+ void generateCommandList(UIActionHandler* handler, const UIActionContext& context);
+ void cancelGenerateCommandList();
+
+ void scoreCommandList(CommandListScoreWorker::OrderStrategy strategy);
+ void cancelScoreCommandList();
+
+ void pauseCommandListUpdates();
+ void unpauseCommandListUpdates();
+
+ void updateDisplayedItems();
+
+private Q_SLOTS:
+ void generateFetch();
+ void itemsGenerated(int request, const std::vector<CommandListItem>& items);
+ void itemsFinishedGenerating(int request);
+ void generateWorkFinished(int request);
+
+ void scoreFetch();
+ void itemsScored(int request, const std::vector<std::pair<CommandListItem*, int>>& items);
+ void itemsFinishedScoring(int request);
+ void scoreWorkFinished(int request);
};
/*!
@@ -92,14 +257,21 @@ class BINARYNINJAUIAPI CommandList : public QListView
CommandListFilter* m_filter;
public:
- CommandList(CommandPalette* parent, const std::vector<CommandListItem>& items);
+ CommandList(CommandPalette* parent);
void setFilter(CommandListFilter* filter) { m_filter = filter; }
void setFilterText(const QString& text);
- QString getActionForItem(int row);
+ CommandListItem getItem(int row);
QModelIndex index(int row, int col, const QModelIndex& parent = QModelIndex()) const;
- void addRecentItem(const QString& name);
+ void addRecentItem(const CommandListItem& item);
+
+ void clearCommandList();
+ void generateCommandList(UIActionHandler* handler, const UIActionContext& context);
+ void cancelGenerateCommandList();
+
+ void pauseCommandListUpdates();
+ void unpauseCommandListUpdates();
protected:
virtual void keyPressEvent(QKeyEvent* event) override;
@@ -126,7 +298,9 @@ class BINARYNINJAUIAPI CommandListFilter : public QLineEdit
protected:
bool event(QEvent* event) override;
virtual void keyPressEvent(QKeyEvent* event) override;
+ virtual void focusInEvent(QFocusEvent* event) override;
virtual void focusOutEvent(QFocusEvent* event) override;
+ virtual void paintEvent(QPaintEvent* event) override;
};
/*!
@@ -139,26 +313,31 @@ class BINARYNINJAUIAPI CommandPalette : public QFrame
UIActionHandler* m_handler;
UIActionContext m_context;
+
QPointer<QWidget> m_previousWidget;
CommandListFilter* m_filter;
CommandList* m_list;
+ std::optional<CommandListItem> m_savedTop;
bool m_executing;
- std::vector<CommandListItem> getCommandList();
void init();
public:
- CommandPalette(QWidget* parent, UIActionHandler* handler);
- CommandPalette(QWidget* parent, UIActionHandler* handler, const UIActionContext& context);
+ CommandPalette(QWidget* parent);
+ void openWithInput(const QString& text);
void focusInput();
+ void clearCommandList();
+ void generateCommandList(UIActionHandler* handler, const UIActionContext& context);
+
//! Activate the focused item, or topmost item if there is no selection.
void activateFocusedItem();
void selectFirstItem();
void close(bool restoreFocus = true);
+ void activateItem(const CommandListItem& item);
private Q_SLOTS:
void itemClicked(const QModelIndex& idx);
diff --git a/ui/flowgraphwidget.h b/ui/flowgraphwidget.h
index 90b86000..056dc7ac 100644
--- a/ui/flowgraphwidget.h
+++ b/ui/flowgraphwidget.h
@@ -63,6 +63,7 @@ class BINARYNINJAUIAPI FlowGraphHistoryEntry : public HistoryEntry
void setCurrentAddress(uint64_t a) { m_addr = a; }
void setHighlightTokenState(const HighlightTokenState& state) { m_highlight = state; }
+ virtual QString getDescription() const override;
virtual Json::Value serialize() const override;
virtual bool deserialize(const Json::Value& value) override;
};
diff --git a/ui/linearview.h b/ui/linearview.h
index 0067a3e1..df01a3b2 100644
--- a/ui/linearview.h
+++ b/ui/linearview.h
@@ -111,6 +111,7 @@ public:
void setInFunction(bool inFunc) { m_inFunc = inFunc; }
void setHighlightTokenState(const HighlightTokenState& state) { m_highlight = state; }
+ virtual QString getDescription() const override;
virtual Json::Value serialize() const override;
virtual bool deserialize(const Json::Value& value) override;
};
diff --git a/ui/tokenizedtextview.h b/ui/tokenizedtextview.h
index 26a96555..708673bb 100644
--- a/ui/tokenizedtextview.h
+++ b/ui/tokenizedtextview.h
@@ -33,6 +33,7 @@ class BINARYNINJAUIAPI TokenizedTextViewHistoryEntry : public HistoryEntry
void setCursorLine(size_t line) { m_cursorLine = line; }
void setHighlightTokenState(const HighlightTokenState& state) { m_highlight = state; }
+ virtual QString getDescription() const override;
virtual Json::Value serialize() const override;
virtual bool deserialize(const Json::Value& value) override;
};
diff --git a/ui/viewframe.h b/ui/viewframe.h
index 055e27c0..08d4add6 100644
--- a/ui/viewframe.h
+++ b/ui/viewframe.h
@@ -85,6 +85,8 @@ class BINARYNINJAUIAPI HistoryEntry : public BinaryNinja::RefCountObject
QString getViewType() const { return m_viewType; }
void setViewType(const QString& type) { m_viewType = type; }
+ virtual QString getDescription() const;
+
/*!
Serialize to json representation
\return Json representation of history entry. In the Python api, this must be a dict.
@@ -392,12 +394,6 @@ class BINARYNINJAUIAPI ViewFrame : public QWidget
bool gestureEvent(QGestureEvent* event);
void setView(QWidget* view);
- /*!
- Load one history entry from json representation
- \param json Json rep of history entry
- \return Entry, if successful, else nullptr
- */
- BinaryNinja::Ref<HistoryEntry> deserializeHistoryEntry(const Json::Value& json);
bool tryMainSymbolsNavigation();
@@ -464,6 +460,14 @@ class BINARYNINJAUIAPI ViewFrame : public QWidget
void updateFonts();
void updateTheme();
+ std::vector<BinaryNinja::Ref<HistoryEntry>> getBackHistory();
+ std::vector<BinaryNinja::Ref<HistoryEntry>> getForwardHistory();
+ /*!
+ Load one history entry from json representation
+ \param json Json rep of history entry
+ \return Entry, if successful, else nullptr
+ */
+ BinaryNinja::Ref<HistoryEntry> deserializeHistoryEntry(const Json::Value& json);
void addHistoryEntry();
/*!
Parse history entries from the raw data associated with a BinaryView, loading them into the back/forward