diff options
| author | Akshay Nair <phenax5@gmail.com> | 2025-03-11 11:31:14 +0530 |
|---|---|---|
| committer | Akshay Nair <phenax5@gmail.com> | 2025-03-11 11:44:31 +0530 |
| commit | 12d0ce37db7323e8efd56d6a698a98abcb8d680b (patch) | |
| tree | ec2102d40326a332b2ecb976869585f81cba8574 | |
| parent | 971854bfefad4c644ac3d5f5d6003f24d551bf1d (diff) | |
| download | null-browser-12d0ce37db7323e8efd56d6a698a98abcb8d680b.tar.gz null-browser-12d0ce37db7323e8efd56d6a698a98abcb8d680b.zip | |
Add command+url adapter and switching
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | TODO.org | 3 | ||||
| -rw-r--r-- | include/completion/Adapter.hpp | 12 | ||||
| -rw-r--r-- | include/completion/CommandsAdapter.hpp | 19 | ||||
| -rw-r--r-- | include/completion/UrlAdapter.hpp | 19 | ||||
| -rw-r--r-- | include/completion/UrlModel.hpp | 25 | ||||
| -rw-r--r-- | include/widgets/CommandInput.hpp | 29 | ||||
| -rw-r--r-- | include/widgets/InputLine.hpp | 35 | ||||
| -rw-r--r-- | include/widgets/MainWindow.hpp | 11 | ||||
| -rw-r--r-- | spec/CommandInputSpec.cpp | 104 | ||||
| -rw-r--r-- | spec/InputLineSpec.cpp | 104 | ||||
| -rw-r--r-- | src/CommandParser.cpp | 5 | ||||
| -rw-r--r-- | src/completion/CommandsAdapter.cpp | 22 | ||||
| -rw-r--r-- | src/completion/Completer.cpp | 4 | ||||
| -rw-r--r-- | src/completion/UrlAdapter.cpp | 20 | ||||
| -rw-r--r-- | src/completion/UrlModel.cpp | 48 | ||||
| -rw-r--r-- | src/widgets/CommandInput.cpp | 84 | ||||
| -rw-r--r-- | src/widgets/InputLine.cpp | 91 | ||||
| -rw-r--r-- | src/widgets/MainWindow.cpp | 63 |
19 files changed, 446 insertions, 254 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 016f1ea..6154e5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,6 @@ target_link_libraries(tests PRIVATE Qt6::WebEngineWidgets Qt6::Test ${LuaJIT_LINK_LIBRARIES}) -add_test(NAME CommandInputSpec COMMAND tests) +add_test(NAME InputLineSpec COMMAND tests) install(TARGETS ${PROJECT} RUNTIME DESTINATION bin) @@ -13,11 +13,12 @@ - [ ] History persistance - [ ] History completion - [ ] Sketch lua api for managing ui +- [ ] Open url parsing (add protocol if missing, remove quotes, etc) ** Later - [ ] Fullscreen -- [ ] File picker - [ ] Dev tools - [ ] remote debugging with cdp (spider-repl) ** Maybe +- [ ] Custom file picker diff --git a/include/completion/Adapter.hpp b/include/completion/Adapter.hpp new file mode 100644 index 0000000..882d457 --- /dev/null +++ b/include/completion/Adapter.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include <QWidget> +#include <QtCore> + +#include "completion/Completer.hpp" + +class Adapter : public QObject { +public: + virtual Completer *completer() = 0; + virtual QString prompt() = 0; +}; diff --git a/include/completion/CommandsAdapter.hpp b/include/completion/CommandsAdapter.hpp new file mode 100644 index 0000000..0a0b61b --- /dev/null +++ b/include/completion/CommandsAdapter.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include <QWidget> +#include <QtCore> + +#include "completion/Adapter.hpp" + +class CommandsAdapter : public Adapter { + Q_OBJECT + +public: + CommandsAdapter(); + ~CommandsAdapter(); + Completer *completer() override; + QString prompt() override; + +private: + Completer *completerInstance; +}; diff --git a/include/completion/UrlAdapter.hpp b/include/completion/UrlAdapter.hpp new file mode 100644 index 0000000..e89167a --- /dev/null +++ b/include/completion/UrlAdapter.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include <QWidget> +#include <QtCore> + +#include "completion/Adapter.hpp" + +class UrlAdapter : public Adapter { + Q_OBJECT + +public: + UrlAdapter(); + ~UrlAdapter(); + Completer *completer() override; + QString prompt() override; + +private: + Completer *completerInstance; +}; diff --git a/include/completion/UrlModel.hpp b/include/completion/UrlModel.hpp new file mode 100644 index 0000000..e65a86a --- /dev/null +++ b/include/completion/UrlModel.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include <QAbstractListModel> +#include <QWidget> +#include <QtCore> + +struct Url { + QString url; + QString description; +}; + +class UrlModel : public QAbstractListModel { + Q_OBJECT + +public: + UrlModel(QObject *parent = nullptr); + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QHash<int, QByteArray> roleNames() const override; + QVariant data(const QModelIndex &index, + int role = Qt::DisplayRole) const override; + +private: + QList<Url> items; +}; diff --git a/include/widgets/CommandInput.hpp b/include/widgets/CommandInput.hpp deleted file mode 100644 index 3ce9500..0000000 --- a/include/widgets/CommandInput.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include <QBoxLayout> -#include <QLineEdit> -#include <QWidget> -#include <QtCore> - -class CommandInput : public QWidget { - Q_OBJECT - -public: - CommandInput(QString defaultInput = "", QWidget *parentNode = nullptr); - void setInputFocus(bool focussed); - bool isInputFocussed(); - QString getInputCommand(); - void setInputText(QString text); - -signals: - void submitted(QString command); - void cancelled(); - -protected: - void keyPressEvent(QKeyEvent *event) override; - void emitSubmit(); - -private: - QBoxLayout *layout; - QLineEdit *input; -}; diff --git a/include/widgets/InputLine.hpp b/include/widgets/InputLine.hpp new file mode 100644 index 0000000..2324f18 --- /dev/null +++ b/include/widgets/InputLine.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include <QBoxLayout> +#include <QLabel> +#include <QLineEdit> +#include <QWidget> +#include <QtCore> + +#include "completion/Adapter.hpp" + +class InputLine : public QWidget { + Q_OBJECT + +public: + InputLine(QString defaultInput = "", QWidget *parentNode = nullptr); + void setInputFocus(bool focussed); + bool isInputFocussed(); + QString getInputCommand(); + void setInputText(QString text); + void setAdapter(Adapter *adapter); + +signals: + void submitted(QString command); + void cancelled(); + +protected: + void keyPressEvent(QKeyEvent *event) override; + void emitSubmit(); + +private: + QBoxLayout *layout; + QLineEdit *input; + QLabel *promptPrefix; + Adapter *adapter = nullptr; +}; diff --git a/include/widgets/MainWindow.hpp b/include/widgets/MainWindow.hpp index 7f54ce2..b64bf8c 100644 --- a/include/widgets/MainWindow.hpp +++ b/include/widgets/MainWindow.hpp @@ -7,7 +7,7 @@ #include "LuaRuntime.hpp" #include "widgets/BrowserManager.hpp" -#include "widgets/CommandInput.hpp" +#include "widgets/InputLine.hpp" class MainWindow : public QMainWindow { public: @@ -15,14 +15,15 @@ public: protected: void keyPressEvent(QKeyEvent *event) override; - void toggleURLInput(); void evaluateCommand(QString command); - void hideURLInput(); - void showURLInput(); + void hideInputLine(); + void showInputLine(); + void showURLInput(QString url = ""); + void showCommandInput(QString command = ""); private: BrowserManager *browserManager; - CommandInput *commandInput; + InputLine *inputLine; LuaRuntime *luaRuntime; QStackedLayout *layout; }; diff --git a/spec/CommandInputSpec.cpp b/spec/CommandInputSpec.cpp deleted file mode 100644 index e687f70..0000000 --- a/spec/CommandInputSpec.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "testUtils.h" - -#include "widgets/CommandInput.hpp" - -class CommandInputSpec : public QObject { - Q_OBJECT - -private slots: - void testWithInitialInput() { - context("when initialized with some text"); - it("sets the initial input text") { - CommandInput inputWidget("Initial content", new QWidget()); - - QCOMPARE(inputWidget.getInputCommand(), QString("Initial content")); - } - } - - void testInputUpdate() { - context("when user types in input"); - it("updates input command") { - CommandInput inputWidget("Initial content", new QWidget()); - - auto input = inputWidget.findChild<QLineEdit *>(); - QTest::keyClicks(input, " updated"); - - QCOMPARE(inputWidget.getInputCommand(), - QString("Initial content updated")); - } - - context("when setInputText is called"); - it("sets input command") { - CommandInput inputWidget("Initial content", new QWidget()); - - inputWidget.setInputText("New content"); - - QCOMPARE(inputWidget.getInputCommand(), QString("New content")); - } - } - - void testSubmitSignalOnReturnKey() { - context("when user hits return key"); - it("emits the submitted signal with the input command") { - CommandInput inputWidget("Initial content", new QWidget()); - QSignalSpy submitSignal(&inputWidget, &CommandInput::submitted); - - auto input = inputWidget.findChild<QLineEdit *>(); - QTest::keyClicks(input, " updated"); - QTest::keyClick(&inputWidget, Qt::Key_Return); - - QCOMPARE(submitSignal.count(), 1); - QCOMPARE(submitSignal.takeFirst().at(0).toString(), - QString("Initial content updated")); - } - } - - void testCancelSignalOnEscapeKey() { - context("when user hits escape key"); - it("emits 'cancelled' signal") { - CommandInput inputWidget("Initial content", new QWidget()); - QSignalSpy cancelSignal(&inputWidget, &CommandInput::cancelled); - - auto input = inputWidget.findChild<QLineEdit *>(); - QTest::keyClick(&inputWidget, Qt::Key_Escape); - - QCOMPARE(cancelSignal.count(), 1); - } - - context("when user hits ctrl+l key"); - it("emits 'cancelled' signal") { - CommandInput inputWidget("Initial content", new QWidget()); - QSignalSpy cancelSignal(&inputWidget, &CommandInput::cancelled); - - auto input = inputWidget.findChild<QLineEdit *>(); - QTest::keyClick(&inputWidget, Qt::Key_L, Qt::ControlModifier); - - QCOMPARE(cancelSignal.count(), 1); - } - } - - void testSetFocus() { - context("when setInputFocus is called with true"); - xit("focusses input field") { - CommandInput inputWidget("Initial content", new QWidget()); - - inputWidget.setInputFocus(true); - QApplication::processEvents(); - - QVERIFY(inputWidget.isInputFocussed()); - } - - context("when setInputFocus is called with false"); - xit("unfocusses input field") { - CommandInput inputWidget("Initial content", new QWidget()); - - inputWidget.setInputFocus(false); - QApplication::processEvents(); - - QVERIFY(!inputWidget.isInputFocussed()); - } - } -}; - -QTEST_REGISTER(CommandInputSpec) -#include "CommandInputSpec.moc" diff --git a/spec/InputLineSpec.cpp b/spec/InputLineSpec.cpp new file mode 100644 index 0000000..e4eb9a5 --- /dev/null +++ b/spec/InputLineSpec.cpp @@ -0,0 +1,104 @@ +#include "testUtils.h" + +#include "widgets/InputLine.hpp" + +class InputLineSpec : public QObject { + Q_OBJECT + +private slots: + void testWithInitialInput() { + context("when initialized with some text"); + it("sets the initial input text") { + InputLine inputWidget("Initial content", new QWidget()); + + QCOMPARE(inputWidget.getInputCommand(), QString("Initial content")); + } + } + + void testInputUpdate() { + context("when user types in input"); + it("updates input command") { + InputLine inputWidget("Initial content", new QWidget()); + + auto input = inputWidget.findChild<QLineEdit *>(); + QTest::keyClicks(input, " updated"); + + QCOMPARE(inputWidget.getInputCommand(), + QString("Initial content updated")); + } + + context("when setInputText is called"); + it("sets input command") { + InputLine inputWidget("Initial content", new QWidget()); + + inputWidget.setInputText("New content"); + + QCOMPARE(inputWidget.getInputCommand(), QString("New content")); + } + } + + void testSubmitSignalOnReturnKey() { + context("when user hits return key"); + it("emits the submitted signal with the input command") { + InputLine inputWidget("Initial content", new QWidget()); + QSignalSpy submitSignal(&inputWidget, &InputLine::submitted); + + auto input = inputWidget.findChild<QLineEdit *>(); + QTest::keyClicks(input, " updated"); + QTest::keyClick(&inputWidget, Qt::Key_Return); + + QCOMPARE(submitSignal.count(), 1); + QCOMPARE(submitSignal.takeFirst().at(0).toString(), + QString("Initial content updated")); + } + } + + void testCancelSignalOnEscapeKey() { + context("when user hits escape key"); + it("emits 'cancelled' signal") { + InputLine inputWidget("Initial content", new QWidget()); + QSignalSpy cancelSignal(&inputWidget, &InputLine::cancelled); + + auto input = inputWidget.findChild<QLineEdit *>(); + QTest::keyClick(&inputWidget, Qt::Key_Escape); + + QCOMPARE(cancelSignal.count(), 1); + } + + context("when user hits ctrl+l key"); + it("emits 'cancelled' signal") { + InputLine inputWidget("Initial content", new QWidget()); + QSignalSpy cancelSignal(&inputWidget, &InputLine::cancelled); + + auto input = inputWidget.findChild<QLineEdit *>(); + QTest::keyClick(&inputWidget, Qt::Key_L, Qt::ControlModifier); + + QCOMPARE(cancelSignal.count(), 1); + } + } + + void testSetFocus() { + context("when setInputFocus is called with true"); + xit("focusses input field") { + InputLine inputWidget("Initial content", new QWidget()); + + inputWidget.setInputFocus(true); + QApplication::processEvents(); + + QVERIFY(inputWidget.isInputFocussed()); + } + + context("when setInputFocus is called with false"); + xit("unfocusses input field") { + InputLine inputWidget("Initial content", new QWidget()); + + inputWidget.setInputFocus(false); + QApplication::processEvents(); + + QVERIFY(!inputWidget.isInputFocussed()); + } + } +}; + +QTEST_REGISTER(InputLineSpec) +#include "InputLineSpec.moc" diff --git a/src/CommandParser.cpp b/src/CommandParser.cpp index 7a8eb00..8f83575 100644 --- a/src/CommandParser.cpp +++ b/src/CommandParser.cpp @@ -6,6 +6,7 @@ CommandParser::CommandParser() {} Cmd CommandParser::parse(QString input) { + // TODO: simplify this to only parse the command auto parts = input.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts); if (parts.isEmpty()) @@ -13,9 +14,7 @@ Cmd CommandParser::parse(QString input) { auto cmdStr = parts.first(); auto cmd = toCommandType(cmdStr); - auto rawArgs = input.slice(cmdStr.length()); - - parts.removeFirst(); + auto rawArgs = input.slice(cmdStr.length()).trimmed(); return {.command = cmd, .argsString = rawArgs, .rawInput = input}; } diff --git a/src/completion/CommandsAdapter.cpp b/src/completion/CommandsAdapter.cpp new file mode 100644 index 0000000..df71661 --- /dev/null +++ b/src/completion/CommandsAdapter.cpp @@ -0,0 +1,22 @@ +#include <QWidget> +#include <QtCore> + +#include "completion/CommandsAdapter.hpp" +#include "completion/CommandsModel.hpp" +#include "completion/Completer.hpp" + +const QString cmdPrompt = "[exec]"; + +CommandsAdapter::CommandsAdapter() : Adapter() { + completerInstance = new Completer(this); + completerInstance->setModel(new CommandsModel(this)); +} + +Completer *CommandsAdapter::completer() { return completerInstance; } + +QString CommandsAdapter::prompt() { return cmdPrompt; } + +CommandsAdapter::~CommandsAdapter() { + delete completerInstance->model(); + delete completerInstance; +} diff --git a/src/completion/Completer.cpp b/src/completion/Completer.cpp index 96a363e..a38d3f2 100644 --- a/src/completion/Completer.cpp +++ b/src/completion/Completer.cpp @@ -27,9 +27,7 @@ Completer::Completer(QObject *parent) : QCompleter(parent) { treeView->setRootIsDecorated(false); treeView->setUniformRowHeights(true); treeView->header()->hide(); - treeView->setColumnWidth(1, 160); - - complete(); + treeView->setColumnWidth(1, 300); } // bool Completer::eventFilter(QObject *watched, QEvent *event) { diff --git a/src/completion/UrlAdapter.cpp b/src/completion/UrlAdapter.cpp new file mode 100644 index 0000000..2f1bb08 --- /dev/null +++ b/src/completion/UrlAdapter.cpp @@ -0,0 +1,20 @@ +#include <QWidget> +#include <QtCore> + +#include "completion/Completer.hpp" +#include "completion/UrlAdapter.hpp" +#include "completion/UrlModel.hpp" + +UrlAdapter::UrlAdapter() : Adapter() { + completerInstance = new Completer(this); + completerInstance->setModel(new UrlModel(this)); +} + +Completer *UrlAdapter::completer() { return completerInstance; } + +QString UrlAdapter::prompt() { return "[url]"; } + +UrlAdapter::~UrlAdapter() { + delete completerInstance->model(); + delete completerInstance; +} diff --git a/src/completion/UrlModel.cpp b/src/completion/UrlModel.cpp new file mode 100644 index 0000000..7671fc3 --- /dev/null +++ b/src/completion/UrlModel.cpp @@ -0,0 +1,48 @@ +#include <QAbstractListModel> +#include <QWidget> +#include <QtCore> + +#include "completion/UrlModel.hpp" + +UrlModel::UrlModel(QObject *parent) : QAbstractListModel(parent) { + items = { + {.url = "https://google.com", .description = "Google"}, + {.url = "https://duckduckgo.com", .description = "DuckDuckGo"}, + {.url = "https://ediblemonad.dev", .description = "EdibleMonad website"}, + {.url = "https://lite.duckduckgo.com", .description = "DDG lite"}, + {.url = "https://github.com/trending", .description = "Github trending"}, + }; +} + +QVariant UrlModel::data(const QModelIndex &index, int role) const { + if (!index.isValid() || index.row() >= items.size()) + return QVariant(); + + const Url &item = items.at(index.row()); + + if (role == Qt::DisplayRole) + return item.url; + else if (role == Qt::ToolTipRole) + return item.description; + else if (role == Qt::UserRole) + return item.description; + + return QVariant(); +} + +QHash<int, QByteArray> UrlModel::roleNames() const { + QHash<int, QByteArray> roles; + roles[Qt::DisplayRole] = "url"; + roles[Qt::UserRole] = "description"; + return roles; +} + +int UrlModel::rowCount(const QModelIndex &parent) const { + Q_UNUSED(parent); + return items.size(); +} + +int UrlModel::columnCount(const QModelIndex &parent) const { + Q_UNUSED(parent); + return 2; // name + description +} diff --git a/src/widgets/CommandInput.cpp b/src/widgets/CommandInput.cpp deleted file mode 100644 index 3ea0f38..0000000 --- a/src/widgets/CommandInput.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#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(rootStyles); - - auto layout = new QVBoxLayout(this); - layout->setContentsMargins(0, 0, 0, 0); - - 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); - input->setCompleter(completer); - // input->installEventFilter(completer); - - cmdLineLayout->addWidget(promptPrefix); - cmdLineLayout->addWidget(input); - - setFixedHeight(input->sizeHint().height()); -} - -void CommandInput::emitSubmit() { emit submitted(getInputCommand()); } - -void CommandInput::keyPressEvent(QKeyEvent *event) { - auto combo = event->keyCombination(); - auto ctrlL = combo.key() == Qt::Key_L && - combo.keyboardModifiers().testFlag(Qt::ControlModifier); - auto esc = combo.key() == Qt::Key_Escape; - auto enter = combo.key() == Qt::Key_Return || combo.key() == Qt::Key_Enter; - - if (esc || ctrlL) - emit cancelled(); - else if (enter) - emitSubmit(); -} - -void CommandInput::setInputText(QString text) { input->setText(text); } - -bool CommandInput::isInputFocussed() { return input->hasFocus(); } - -void CommandInput::setInputFocus(bool focussed) { - if (focussed) - input->setFocus(Qt::PopupFocusReason); - else - input->clearFocus(); -} - -QString CommandInput::getInputCommand() { return input->text(); } diff --git a/src/widgets/InputLine.cpp b/src/widgets/InputLine.cpp new file mode 100644 index 0000000..d577e1d --- /dev/null +++ b/src/widgets/InputLine.cpp @@ -0,0 +1,91 @@ +#include <QBoxLayout> +#include <QCompleter> +#include <QHBoxLayout> +#include <QKeyEvent> +#include <QLabel> +#include <QLineEdit> +#include <QStringListModel> +#include <QWidget> +#include <QWidgetAction> +#include <QWindow> +#include <QtCore> + +#include "completion/CommandsAdapter.hpp" +#include "widgets/InputLine.hpp" + +const char *rootStyles = R"( + background-color: #000; + color: #fff; + border-radius: 0; +)"; + +const char *promptStyles = R"( + background-color: #aaa; + color: #555; + padding: 0 2px; +)"; + +InputLine::InputLine(QString defaultInput, QWidget *parentNode) + : QWidget(parentNode) { + setContentsMargins(0, 0, 0, 0); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + setStyleSheet(rootStyles); + + auto layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + + auto cmdLineBox = new QWidget(); + layout->addWidget(cmdLineBox); + auto cmdLineLayout = new QHBoxLayout(); + cmdLineBox->setLayout(cmdLineLayout); + cmdLineBox->layout()->setContentsMargins(0, 0, 0, 0); + cmdLineLayout->setSpacing(0); + + promptPrefix = new QLabel(); + promptPrefix->setStyleSheet(promptStyles); + promptPrefix->setContentsMargins(0, 0, 0, 0); + input = new QLineEdit(defaultInput); + input->setFocusPolicy(Qt::StrongFocus); + + cmdLineLayout->addWidget(promptPrefix); + cmdLineLayout->addWidget(input); + setFixedHeight(input->sizeHint().height()); + + setAdapter(new CommandsAdapter()); +} + +void InputLine::setAdapter(Adapter *adapter) { + if (this->adapter) + delete this->adapter; + this->adapter = adapter; + promptPrefix->setText(adapter->prompt()); + input->setCompleter(adapter->completer()); +} + +void InputLine::emitSubmit() { emit submitted(getInputCommand()); } + +void InputLine::keyPressEvent(QKeyEvent *event) { + auto combo = event->keyCombination(); + auto ctrlL = combo.key() == Qt::Key_L && + combo.keyboardModifiers().testFlag(Qt::ControlModifier); + auto esc = combo.key() == Qt::Key_Escape; + auto enter = combo.key() == Qt::Key_Return || combo.key() == Qt::Key_Enter; + + if (esc || ctrlL) + emit cancelled(); + else if (enter) + emitSubmit(); +} + +void InputLine::setInputText(QString text) { input->setText(text); } + +bool InputLine::isInputFocussed() { return input->hasFocus(); } + +void InputLine::setInputFocus(bool focussed) { + if (focussed) + input->setFocus(Qt::PopupFocusReason); + else + input->clearFocus(); +} + +QString InputLine::getInputCommand() { return input->text(); } diff --git a/src/widgets/MainWindow.cpp b/src/widgets/MainWindow.cpp index 3191719..03a4e6e 100644 --- a/src/widgets/MainWindow.cpp +++ b/src/widgets/MainWindow.cpp @@ -2,10 +2,13 @@ #include <QStackedLayout> #include <QVBoxLayout> #include <QWebEngineView> +#include <QtCore/qnamespace.h> #include "CommandParser.hpp" +#include "completion/CommandsAdapter.hpp" +#include "completion/UrlAdapter.hpp" #include "widgets/BrowserManager.hpp" -#include "widgets/CommandInput.hpp" +#include "widgets/InputLine.hpp" #include "widgets/MainWindow.hpp" MainWindow::MainWindow() { @@ -24,14 +27,12 @@ MainWindow::MainWindow() { layout->addWidget(browserManager); // Command input - commandInput = new CommandInput; - hideURLInput(); - commandInput->move(0, 0); - connect(commandInput, &CommandInput::submitted, this, - &MainWindow::evaluateCommand); - connect(commandInput, &CommandInput::cancelled, this, - &MainWindow::hideURLInput); - layout->addWidget(commandInput); + inputLine = new InputLine; + inputLine->setHidden(true); + inputLine->move(0, 0); + connect(inputLine, &InputLine::submitted, this, &MainWindow::evaluateCommand); + connect(inputLine, &InputLine::cancelled, this, &MainWindow::hideInputLine); + layout->addWidget(inputLine); // Lua runtime luaRuntime = LuaRuntime::instance(); @@ -41,20 +42,31 @@ MainWindow::MainWindow() { }); } -void MainWindow::hideURLInput() { - commandInput->setInputFocus(false); - commandInput->setHidden(true); +void MainWindow::hideInputLine() { + inputLine->setInputFocus(false); + inputLine->setHidden(true); } -void MainWindow::showURLInput() { - commandInput->setInputText("open " + browserManager->currentUrl().toString()); - commandInput->setHidden(false); - layout->setCurrentWidget(commandInput); - commandInput->setInputFocus(true); +void MainWindow::showInputLine() { + inputLine->setHidden(false); + layout->setCurrentWidget(inputLine); + inputLine->setInputFocus(true); +} + +void MainWindow::showURLInput(QString url) { + showInputLine(); + inputLine->setAdapter(new UrlAdapter); + inputLine->setInputText(url); +} + +void MainWindow::showCommandInput(QString cmd) { + showInputLine(); + inputLine->setAdapter(new CommandsAdapter); + inputLine->setInputText(cmd); } void MainWindow::evaluateCommand(QString command) { - hideURLInput(); + hideInputLine(); CommandParser parser; auto cmd = parser.parse(command); @@ -64,7 +76,11 @@ void MainWindow::evaluateCommand(QString command) { luaRuntime->evaluate(cmd.argsString); break; case CommandType::Open: - browserManager->openUrl(cmd.argsString, OpenType::OpenUrl); + if (cmd.argsString.trimmed().isEmpty()) { + showURLInput(); + } else { + browserManager->openUrl(cmd.argsString, OpenType::OpenUrl); + } break; case CommandType::TabOpen: browserManager->openUrl(cmd.argsString, OpenType::OpenUrlInTab); @@ -84,7 +100,10 @@ void MainWindow::keyPressEvent(QKeyEvent *event) { auto combo = event->keyCombination(); if (combo.key() == Qt::Key_L && combo.keyboardModifiers().testFlag(Qt::ControlModifier)) { - toggleURLInput(); + showURLInput(browserManager->currentUrl().toString()); + } else if (combo.key() == Qt::Key_Semicolon && + combo.keyboardModifiers().testFlag(Qt::ControlModifier)) { + showCommandInput(); } else if (combo.key() == Qt::Key_T && combo.keyboardModifiers().testFlag(Qt::ControlModifier)) { browserManager->createNewWebView(QUrl("https://lite.duckduckgo.com"), true); @@ -99,7 +118,3 @@ void MainWindow::keyPressEvent(QKeyEvent *event) { browserManager->closeCurrentWebView(); } } - -void MainWindow::toggleURLInput() { - commandInput->isHidden() ? showURLInput() : hideURLInput(); -} |
