aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAkshay Nair <phenax5@gmail.com>2025-03-10 22:04:24 +0530
committerAkshay Nair <phenax5@gmail.com>2025-03-10 22:13:15 +0530
commit971854bfefad4c644ac3d5f5d6003f24d551bf1d (patch)
tree0f5ee90fd5968d345b157d38964094837315edf0 /src
parentd400369084107104f51fe217d5781c8d7bd07ff9 (diff)
downloadnull-browser-971854bfefad4c644ac3d5f5d6003f24d551bf1d.tar.gz
null-browser-971854bfefad4c644ac3d5f5d6003f24d551bf1d.zip
Add completer + simplify command parsing + class generator
Diffstat (limited to '')
-rw-r--r--src/CommandParser.cpp10
-rw-r--r--src/LuaRuntime.cpp4
-rw-r--r--src/completion/CommandsModel.cpp42
-rw-r--r--src/completion/Completer.cpp46
-rw-r--r--src/completion/CompleterDelegate.cpp40
-rw-r--r--src/widgets/CommandInput.cpp40
-rw-r--r--src/widgets/MainWindow.cpp11
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();