forked from qt-creator/qt-creator
Lua: Interactive Shell
Change-Id: Iedd620abcb62b9dd3e640bcb80ae011016386484 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -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
|
||||
|
Reference in New Issue
Block a user