From dff08963a1ef4998eadbf3270ee5c75149fc8ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 26 Apr 2019 17:07:11 +0200 Subject: [PATCH] Add Console Autocompletion from radare2 (#1489) --- radare2 | 2 +- src/core/Cutter.cpp | 23 +++++++++++ src/core/Cutter.h | 2 + src/widgets/ConsoleWidget.cpp | 75 ++++++++++------------------------- src/widgets/ConsoleWidget.h | 12 +++++- 5 files changed, 58 insertions(+), 56 deletions(-) diff --git a/radare2 b/radare2 index da30e593..bf81826e 160000 --- a/radare2 +++ b/radare2 @@ -1 +1 @@ -Subproject commit da30e593718d5149f2a3d520c7f79fe1c7ca46ef +Subproject commit bf81826eff120e690a841f678544228b1cd0cfa1 diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 46dde094..34df2190 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -333,6 +333,29 @@ QJsonDocument CutterCore::parseJson(const char *res, const char *cmd) return doc; } +QStringList CutterCore::autocomplete(const QString &cmd, RLinePromptType promptType, size_t limit) +{ + RLineBuffer buf; + int c = snprintf(buf.data, sizeof(buf.data), "%s", cmd.toUtf8().constData()); + if (c < 0) { + return {}; + } + buf.index = buf.length = std::min((int)(sizeof(buf.data) - 1), c); + + RLineCompletion completion; + r_line_completion_init(&completion, limit); + r_core_autocomplete(core(), &completion, &buf, promptType); + + QStringList r; + r.reserve(r_pvector_len(&completion.args)); + for (size_t i = 0; i< r_pvector_len(&completion.args); i++) { + r.push_back(QString::fromUtf8(reinterpret_cast(r_pvector_at(&completion.args, i)))); + } + + r_line_completion_fini(&completion); + return r; +} + /** * @brief CutterCore::loadFile * Load initial file. TODO Maybe use the "o" commands? diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 4e1fcbd1..96d84edb 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -70,6 +70,8 @@ public: return parseJson(res, cmd.isNull() ? nullptr : cmd.toLocal8Bit().constData()); } + QStringList autocomplete(const QString &cmd, RLinePromptType promptType, size_t limit = 4096); + /* Functions methods */ void renameFunction(const QString &oldName, const QString &newName); void delFunction(RVA addr); diff --git a/src/widgets/ConsoleWidget.cpp b/src/widgets/ConsoleWidget.cpp index 3cd10d46..63d8acd6 100644 --- a/src/widgets/ConsoleWidget.cpp +++ b/src/widgets/ConsoleWidget.cpp @@ -13,59 +13,9 @@ #include "common/SvgIconEngine.h" -// TODO: Find a way to get to this without copying it here -// source: libr/core/core.c:585.. -// remark: u.* is missing -static const QStringList radareArgs( { - "?", "?v", "whereis", "which", "ls", "rm", "mkdir", "pwd", "cat", "less", - "dH", "ds", "dso", "dsl", "dc", "dd", "dm", "db ", "db-", - "dp", "dr", "dcu", "dmd", "dmp", "dml", - "ec", "ecs", "eco", - "S", "S.", "S*", "S-", "S=", "Sa", "Sa-", "Sd", "Sl", "SSj", "Sr", - "s", "s+", "s++", "s-", "s--", "s*", "sa", "sb", "sr", - "!", "!!", - "#sha1", "#crc32", "#pcprint", "#sha256", "#sha512", "#md4", "#md5", - "#!python", "#!perl", "#!vala", - "V", "v", - "aa", "ab", "af", "ar", "ag", "at", "a?", "ax", "ad", - "ae", "aec", "aex", "aep", "aea", "aeA", "aes", "aeso", "aesu", "aesue", "aer", "aei", "aeim", "aef", - "aaa", "aac", "aae", "aai", "aar", "aan", "aas", "aat", "aap", "aav", - "af", "afa", "afan", "afc", "afC", "afi", "afb", "afbb", "afn", "afr", "afs", "af*", "afv", "afvn", - "aga", "agc", "agd", "agl", "agfl", - // see forbbidenArgs - //"e", "et", "e-", "e*", "e!", "e?", "env ", - "i", "ii", "iI", "is", "iS", "iz", - "q", "q!", - "f", "fl", "fr", "f-", "f*", "fs", "fS", "fr", "fo", "f?", - "m", "m*", "ml", "m-", "my", "mg", "md", "mp", "m?", - "o", "o+", "oc", "on", "op", "o-", "x", "wf", "wF", "wta", "wtf", "wp", - "t", "to", "t-", "tf", "td", "td-", "tb", "tn", "te", "tl", "tk", "ts", "tu", - "(", "(*", "(-", "()", ".", ".!", ".(", "./", - "r", "r+", "r-", - "b", "bf", "b?", - "/", "//", "/a", "/c", "/h", "/m", "/x", "/v", "/v2", "/v4", "/v8", "/r", "/re", - "y", "yy", "y?", - "wx", "ww", "w?", "wxf", - "p6d", "p6e", "p8", "pb", "pc", - "pd", "pda", "pdb", "pdc", "pdj", "pdr", "pdf", "pdi", "pdl", "pds", "pdt", - "pD", "px", "pX", "po", "pf", "pf.", "pf*", "pf*.", "pfd", "pfd.", "pv", "p=", "p-", - "pfj", "pfj.", "pfv", "pfv.", - "pm", "pr", "pt", "ptd", "ptn", "pt?", "ps", "pz", "pu", "pU", "p?", - "z", "z*", "zj", "z-", "z-*", - "za", "zaf", "zaF", - "zo", "zoz", "zos", - "zfd", "zfs", "zfz", - "z/", "z/*", - "zc", - "zs", "zs+", "zs-", "zs-*", "zsr", - "#!pipe" -}); - - static const int invalidHistoryPos = -1; - ConsoleWidget::ConsoleWidget(MainWindow *main, QAction *action) : CutterDockWidget(main, action), ui(new Ui::ConsoleWidget), @@ -96,13 +46,15 @@ ConsoleWidget::ConsoleWidget(MainWindow *main, QAction *action) : actions.append(actionWrapLines); // Completion - QCompleter *completer = new QCompleter(radareArgs, this); + completer = new QCompleter(&completionModel, this); completer->setMaxVisibleItems(20); completer->setCaseSensitivity(Qt::CaseInsensitive); completer->setFilterMode(Qt::MatchStartsWith); - ui->inputLineEdit->setCompleter(completer); + connect(ui->inputLineEdit, &QLineEdit::textChanged, this, &ConsoleWidget::updateCompletion); + updateCompletion(); + ui->outputTextEdit->setLineWrapMode(QPlainTextEdit::WidgetWidth); // Set console output context menu @@ -127,7 +79,10 @@ ConsoleWidget::ConsoleWidget(MainWindow *main, QAction *action) : connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(setupFont())); } -ConsoleWidget::~ConsoleWidget() {} +ConsoleWidget::~ConsoleWidget() +{ + delete completer; +} void ConsoleWidget::setupFont() { @@ -262,6 +217,20 @@ void ConsoleWidget::historyPrev() } } +void ConsoleWidget::updateCompletion() +{ + auto current = ui->inputLineEdit->text(); + auto completions = Core()->autocomplete(current, R_LINE_PROMPT_DEFAULT); + int lastSpace = current.lastIndexOf(' '); + if (lastSpace >= 0) { + current = current.left(lastSpace + 1); + for (auto &s : completions) { + s = current + s; + } + } + completionModel.setStringList(completions); +} + void ConsoleWidget::clear() { ui->inputLineEdit->clear(); diff --git a/src/widgets/ConsoleWidget.h b/src/widgets/ConsoleWidget.h index baa19bcb..e91584d7 100644 --- a/src/widgets/ConsoleWidget.h +++ b/src/widgets/ConsoleWidget.h @@ -1,16 +1,20 @@ #ifndef CONSOLEWIDGET_H #define CONSOLEWIDGET_H -#include #include "core/MainWindow.h" #include "CutterDockWidget.h" #include "common/CommandTask.h" +#include + +#include + +class QCompleter; + namespace Ui { class ConsoleWidget; } - class ConsoleWidget : public CutterDockWidget { Q_OBJECT @@ -48,6 +52,8 @@ private slots: void historyNext(); void historyPrev(); + void updateCompletion(); + void clear(); private: @@ -66,6 +72,8 @@ private: int maxHistoryEntries; int lastHistoryPosition; QStringList history; + QStringListModel completionModel; + QCompleter *completer; }; #endif // CONSOLEWIDGET_H