diff options
| author | Akshay Nair <phenax5@gmail.com> | 2025-03-10 22:04:24 +0530 |
|---|---|---|
| committer | Akshay Nair <phenax5@gmail.com> | 2025-03-10 22:13:15 +0530 |
| commit | 971854bfefad4c644ac3d5f5d6003f24d551bf1d (patch) | |
| tree | 0f5ee90fd5968d345b157d38964094837315edf0 /src | |
| parent | d400369084107104f51fe217d5781c8d7bd07ff9 (diff) | |
| download | null-browser-971854bfefad4c644ac3d5f5d6003f24d551bf1d.tar.gz null-browser-971854bfefad4c644ac3d5f5d6003f24d551bf1d.zip | |
Add completer + simplify command parsing + class generator
Diffstat (limited to '')
| -rw-r--r-- | src/CommandParser.cpp | 10 | ||||
| -rw-r--r-- | src/LuaRuntime.cpp | 4 | ||||
| -rw-r--r-- | src/completion/CommandsModel.cpp | 42 | ||||
| -rw-r--r-- | src/completion/Completer.cpp | 46 | ||||
| -rw-r--r-- | src/completion/CompleterDelegate.cpp | 40 | ||||
| -rw-r--r-- | src/widgets/CommandInput.cpp | 40 | ||||
| -rw-r--r-- | src/widgets/MainWindow.cpp | 11 |
7 files changed, 180 insertions, 13 deletions
diff --git a/src/CommandParser.cpp b/src/CommandParser.cpp index ccb84bc..7a8eb00 100644 --- a/src/CommandParser.cpp +++ b/src/CommandParser.cpp @@ -9,11 +9,15 @@ Cmd CommandParser::parse(QString input) { auto parts = input.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts); if (parts.isEmpty()) - return Cmd(); + return {.command = Noop, .argsString = "", .rawInput = input}; + + auto cmdStr = parts.first(); + auto cmd = toCommandType(cmdStr); + auto rawArgs = input.slice(cmdStr.length()); - auto cmd = toCommandType(parts.first()); parts.removeFirst(); - return Cmd(cmd, parts); + + return {.command = cmd, .argsString = rawArgs, .rawInput = input}; } CommandType CommandParser::toCommandType(QString cmd) { diff --git a/src/LuaRuntime.cpp b/src/LuaRuntime.cpp index 37845d3..6867b61 100644 --- a/src/LuaRuntime.cpp +++ b/src/LuaRuntime.cpp @@ -15,7 +15,9 @@ LuaRuntime::LuaRuntime() { lua_setglobal(state, "web"); } -void LuaRuntime::evaluate(const char *code) { luaL_dostring(state, code); } +void LuaRuntime::evaluate(QString code) { + luaL_dostring(state, code.toStdString().c_str()); +} int LuaRuntime::lua_onUrlOpen(lua_State *state) { const char *url = luaL_optstring(state, 1, ""); diff --git a/src/completion/CommandsModel.cpp b/src/completion/CommandsModel.cpp new file mode 100644 index 0000000..0f66233 --- /dev/null +++ b/src/completion/CommandsModel.cpp @@ -0,0 +1,42 @@ +#include <QAbstractListModel> +#include <QWidget> +#include <QtCore> + +#include "completion/CommandsModel.hpp" + +CommandsModel::CommandsModel(QObject *parent) : QAbstractListModel(parent) { + items = commands; +} + +QVariant CommandsModel::data(const QModelIndex &index, int role) const { + if (!index.isValid() || index.row() >= items.size()) + return QVariant(); + + const Command &item = items.at(index.row()); + + if (role == Qt::DisplayRole) + return item.name; + else if (role == Qt::ToolTipRole) + return item.description; + else if (role == Qt::UserRole) + return item.description; + + return QVariant(); +} + +QHash<int, QByteArray> CommandsModel::roleNames() const { + QHash<int, QByteArray> roles; + roles[Qt::DisplayRole] = "name"; + roles[Qt::UserRole] = "description"; + return roles; +} + +int CommandsModel::rowCount(const QModelIndex &parent) const { + Q_UNUSED(parent); + return items.size(); +} + +int CommandsModel::columnCount(const QModelIndex &parent) const { + Q_UNUSED(parent); + return 2; // name + description +} diff --git a/src/completion/Completer.cpp b/src/completion/Completer.cpp new file mode 100644 index 0000000..96a363e --- /dev/null +++ b/src/completion/Completer.cpp @@ -0,0 +1,46 @@ +#include <QAbstractItemView> +#include <QHeaderView> +#include <QLineEdit> +#include <QTreeView> +#include <QWidget> +#include <QtCore> + +#include "completion/Completer.hpp" +#include "completion/CompleterDelegate.hpp" + +const char *completerStyles = R"( + background-color: #111; + color: #fff; + border-radius: 0; +)"; + +Completer::Completer(QObject *parent) : QCompleter(parent) { + setFilterMode(Qt::MatchContains); + setCaseSensitivity(Qt::CaseInsensitive); + setCompletionRole(Qt::DisplayRole); + setCompletionMode(QCompleter::PopupCompletion); + + auto treeView = new QTreeView(); + setPopup(treeView); + treeView->setStyleSheet(completerStyles); + treeView->setItemDelegate(new CompleterDelegate(treeView)); + treeView->setRootIsDecorated(false); + treeView->setUniformRowHeights(true); + treeView->header()->hide(); + treeView->setColumnWidth(1, 160); + + complete(); +} + +// bool Completer::eventFilter(QObject *watched, QEvent *event) { +// auto isFocusIn = event->type() == QEvent::FocusIn; +// auto isKeyRelease = event->type() == QEvent::KeyRelease; +// +// QLineEdit *lineEdit = qobject_cast<QLineEdit *>(watched); +// bool isInputEmpty = lineEdit && lineEdit->text().isEmpty(); +// +// if ((isFocusIn || isKeyRelease) && isInputEmpty) +// complete(); +// +// return QCompleter::eventFilter(watched, event); +// } diff --git a/src/completion/CompleterDelegate.cpp b/src/completion/CompleterDelegate.cpp new file mode 100644 index 0000000..a35305f --- /dev/null +++ b/src/completion/CompleterDelegate.cpp @@ -0,0 +1,40 @@ +#include <QPainter> +#include <QWidget> +#include <QtCore/qlogging.h> +#include <QtCore/qnamespace.h> +#include <QtCore> + +#include "completion/CompleterDelegate.hpp" + +CompleterDelegate::CompleterDelegate(QObject *parent) + : QStyledItemDelegate(parent) {} + +void CompleterDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const { + painter->save(); + + // Style + if (option.state & QStyle::State_Selected) { + painter->fillRect(option.rect, QColor("#aaa")); + painter->setPen(Qt::black); + } else { + painter->fillRect(option.rect, QColor("#111")); + painter->setPen(Qt::white); + } + + // Draw text + QString text; + QRect rect; + if (index.column() == 0) { + text = index.data(Qt::DisplayRole).toString(); + rect = option.rect.adjusted(5, 0, 0, 0); + painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, text); + } else if (index.column() == 1) { + text = index.data(Qt::UserRole).toString(); + rect = option.rect.adjusted(0, 0, -5, 0); + painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, text); + } + + painter->restore(); +} diff --git a/src/widgets/CommandInput.cpp b/src/widgets/CommandInput.cpp index 464065a..3ea0f38 100644 --- a/src/widgets/CommandInput.cpp +++ b/src/widgets/CommandInput.cpp @@ -1,23 +1,57 @@ +#include <QCompleter> #include <QHBoxLayout> #include <QKeyEvent> +#include <QLabel> #include <QLineEdit> +#include <QStringListModel> #include <QVBoxLayout> #include <QWidget> +#include <QWidgetAction> #include <QWindow> +#include <QtCore/qnamespace.h> +#include <QtCore/qstringlistmodel.h> +#include <QtWidgets/qboxlayout.h> +#include "completion/CommandsModel.hpp" +#include "completion/Completer.hpp" #include "widgets/CommandInput.hpp" +const char *rootStyles = R"( + background-color: #000; + color: #fff; + border-radius: 0; +)"; + CommandInput::CommandInput(QString defaultInput, QWidget *parentNode) : QWidget(parentNode) { setContentsMargins(0, 0, 0, 0); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - setStyleSheet("background-color: #000; color: #fff; border-radius: 0;"); + setStyleSheet(rootStyles); auto layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); - input = new QLineEdit(defaultInput, this); + + auto listModel = new CommandsModel(); + auto completer = new Completer(this); + completer->setModel(listModel); + + auto cmdLineBox = new QWidget(); + layout->addWidget(cmdLineBox); + auto cmdLineLayout = new QHBoxLayout(); + cmdLineBox->setLayout(cmdLineLayout); + cmdLineBox->layout()->setContentsMargins(0, 0, 0, 0); + cmdLineLayout->setSpacing(0); + + auto promptPrefix = new QLabel(tr(":")); + promptPrefix->setContentsMargins(0, 0, 0, 0); + input = new QLineEdit(defaultInput); input->setFocusPolicy(Qt::StrongFocus); - layout->addWidget(input); + input->setCompleter(completer); + // input->installEventFilter(completer); + + cmdLineLayout->addWidget(promptPrefix); + cmdLineLayout->addWidget(input); + setFixedHeight(input->sizeHint().height()); } diff --git a/src/widgets/MainWindow.cpp b/src/widgets/MainWindow.cpp index 9ac5f12..3191719 100644 --- a/src/widgets/MainWindow.cpp +++ b/src/widgets/MainWindow.cpp @@ -37,7 +37,7 @@ MainWindow::MainWindow() { luaRuntime = LuaRuntime::instance(); connect(luaRuntime, &LuaRuntime::urlOpenned, this, [this](QString url, OpenType openType) { - this->browserManager->openUrl(QUrl(url), openType); + browserManager->openUrl(QUrl(url), openType); }); } @@ -56,19 +56,18 @@ void MainWindow::showURLInput() { void MainWindow::evaluateCommand(QString command) { hideURLInput(); - // TODO: Temporary hack CommandParser parser; auto cmd = parser.parse(command); switch (cmd.command) { case CommandType::LuaEval: - luaRuntime->evaluate(cmd.args.join(" ").toStdString().c_str()); + luaRuntime->evaluate(cmd.argsString); break; case CommandType::Open: - browserManager->openUrl(cmd.args.first(), OpenType::OpenUrl); + browserManager->openUrl(cmd.argsString, OpenType::OpenUrl); break; case CommandType::TabOpen: - browserManager->openUrl(cmd.args.at(1), OpenType::OpenUrlInTab); + browserManager->openUrl(cmd.argsString, OpenType::OpenUrlInTab); break; case CommandType::TabNext: browserManager->nextWebView(); @@ -88,7 +87,7 @@ void MainWindow::keyPressEvent(QKeyEvent *event) { toggleURLInput(); } else if (combo.key() == Qt::Key_T && combo.keyboardModifiers().testFlag(Qt::ControlModifier)) { - browserManager->createNewWebView(QUrl("https://duckduckgo.com"), true); + browserManager->createNewWebView(QUrl("https://lite.duckduckgo.com"), true); } else if (combo.key() == Qt::Key_J && combo.keyboardModifiers().testFlag(Qt::ControlModifier)) { browserManager->nextWebView(); |
