aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/lua/luaplugin.cpp
diff options
context:
space:
mode:
authorMarcus Tillmanns <[email protected]>2024-06-13 14:50:37 +0200
committerMarcus Tillmanns <[email protected]>2024-06-24 14:29:31 +0000
commit0214cac51d7ebda76c0fa56d9ce63663afce70fc (patch)
tree32544c7203225c3f8fb7b37359956dac78915df9 /src/plugins/lua/luaplugin.cpp
parentc0bfd9bbd64db0bfecab1e091a01b96b60c453f1 (diff)
Lua: Interactive Shell
Diffstat (limited to 'src/plugins/lua/luaplugin.cpp')
-rw-r--r--src/plugins/lua/luaplugin.cpp171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/plugins/lua/luaplugin.cpp b/src/plugins/lua/luaplugin.cpp
index 0290df988c3..54beafafe12 100644
--- a/src/plugins/lua/luaplugin.cpp
+++ b/src/plugins/lua/luaplugin.cpp
@@ -3,8 +3,10 @@
#include "luaengine.h"
#include "luapluginspec.h"
+#include "luatr.h"
#include <coreplugin/icore.h>
+#include <coreplugin/ioutputpane.h>
#include <coreplugin/jsexpander.h>
#include <coreplugin/messagemanager.h>
@@ -12,8 +14,15 @@
#include <extensionsystem/pluginmanager.h>
#include <utils/algorithm.h>
+#include <utils/layoutbuilder.h>
+#include <utils/qtcprocess.h>
+#include <utils/theme/theme.h>
#include <QDebug>
+#include <QLabel>
+#include <QLineEdit>
+#include <QListView>
+#include <QStringListModel>
using namespace Core;
using namespace Utils;
@@ -49,6 +58,164 @@ public:
}
};
+class LuaTerminal : public QListView
+{
+ Q_OBJECT
+
+ std::unique_ptr<LuaState> m_luaState;
+ sol::function m_readCallback;
+
+ QStringListModel m_model;
+
+public:
+ LuaTerminal(QWidget *parent = nullptr)
+ : QListView(parent)
+ {
+ setModel(&m_model);
+ }
+
+ void showEvent(QShowEvent *) override
+ {
+ if (m_luaState) {
+ return;
+ }
+ resetTerminal();
+ }
+
+ void keyPressEvent(QKeyEvent *e) override { emit keyPressed(e); }
+
+ void handleRequestResult(const QString &result)
+ {
+ auto cb = m_readCallback;
+ m_readCallback = {};
+ cb(result);
+ }
+
+ void resetTerminal()
+ {
+ m_model.setStringList({});
+ m_readCallback = {};
+
+ QFile f(":/lua/scripts/ilua.lua");
+ f.open(QIODevice::ReadOnly);
+ const auto ilua = QString::fromUtf8(f.readAll());
+ m_luaState = LuaEngine::instance().runScript(ilua, "ilua.lua", [this](sol::state &lua) {
+ lua["print"] = [this](sol::variadic_args va) {
+ const QStringList msgs = LuaEngine::variadicToStringList(va)
+ .join("\t")
+ .replace("\r\n", "\n")
+ .split('\n');
+ m_model.setStringList(m_model.stringList() + msgs);
+ scrollToBottom();
+ };
+
+ sol::table async = lua.script("return require('async')", "_ilua_").get<sol::table>();
+ sol::function wrap = async["wrap"];
+
+ lua["readline_cb"] = [this](const QString &prompt, sol::function callback) {
+ m_model.setStringList(m_model.stringList() << prompt);
+ scrollToBottom();
+ emit inputRequested(prompt);
+ m_readCallback = callback;
+ };
+
+ lua["readline"] = wrap(lua["readline_cb"]);
+ });
+
+ QListView::reset();
+ }
+
+signals:
+ void inputRequested(const QString &prompt);
+ void keyPressed(QKeyEvent *e);
+};
+
+class LineEdit : public FancyLineEdit
+{
+public:
+ using FancyLineEdit::FancyLineEdit;
+ void keyPressEvent(QKeyEvent *e) override { FancyLineEdit::keyPressEvent(e); }
+};
+
+class LuaPane : public Core::IOutputPane
+{
+ Q_OBJECT
+
+protected:
+ QWidget *m_ui{nullptr};
+ LuaTerminal *m_terminal{nullptr};
+
+public:
+ LuaPane(QObject *parent = nullptr)
+ : Core::IOutputPane(parent)
+ {
+ setId("LuaPane");
+ setDisplayName(Tr::tr("Lua"));
+ setPriorityInStatusBar(20);
+ }
+
+ QWidget *outputWidget(QWidget *parent) override
+ {
+ using namespace Layouting;
+
+ if (!m_ui && parent) {
+ m_terminal = new LuaTerminal;
+ LineEdit *inputEdit = new LineEdit;
+ QLabel *prompt = new QLabel;
+
+ // clang-format off
+ m_ui = Column {
+ m_terminal,
+ Row { prompt, inputEdit },
+ }.emerge();
+ // clang-format on
+
+ inputEdit->setReadOnly(true);
+ inputEdit->setHistoryCompleter(Utils::Key("LuaREPL.InputHistory"));
+
+ connect(inputEdit, &QLineEdit::returnPressed, this, [this, inputEdit] {
+ inputEdit->setReadOnly(true);
+ m_terminal->handleRequestResult(inputEdit->text());
+ inputEdit->onEditingFinished();
+ inputEdit->clear();
+ });
+ connect(
+ m_terminal,
+ &LuaTerminal::inputRequested,
+ this,
+ [prompt, inputEdit](const QString &p) {
+ prompt->setText(p);
+ inputEdit->setReadOnly(false);
+ });
+ connect(m_terminal, &LuaTerminal::keyPressed, this, [inputEdit](QKeyEvent *e) {
+ inputEdit->keyPressEvent(e);
+ inputEdit->setFocus();
+ });
+ }
+
+ return m_ui;
+ }
+
+ void visibilityChanged(bool) override {};
+
+ void clearContents() override
+ {
+ if (m_terminal)
+ m_terminal->resetTerminal();
+ }
+ void setFocus() override { outputWidget(nullptr)->setFocus(); }
+ bool hasFocus() const override { return true; }
+ bool canFocus() const override { return true; }
+
+ bool canNavigate() const override { return false; }
+ bool canNext() const override { return false; }
+ bool canPrevious() const override { return false; }
+ void goToNext() override {}
+ void goToPrev() override {}
+
+ QList<QWidget *> toolBarWidgets() const override { return {}; }
+};
+
class LuaPlugin : public IPlugin
{
Q_OBJECT
@@ -56,6 +223,7 @@ class LuaPlugin : public IPlugin
private:
std::unique_ptr<LuaEngine> m_luaEngine;
+ LuaPane *m_pane = nullptr;
public:
LuaPlugin() {}
@@ -79,6 +247,9 @@ public:
addInstallModule();
Core::JsExpander::registerGlobalObject("Lua", [] { return new LuaJsExtension(); });
+
+ m_pane = new LuaPane;
+ ExtensionSystem::PluginManager::addObject(m_pane);
}
bool delayedInitialize() final