Skip to content

Commit ab78c5b

Browse files
committed
feat: add REPL for plugins
1 parent 3f3a31d commit ab78c5b

14 files changed

+895
-15
lines changed

Diff for: resources/buttons/changeFontDark.svg

+1
Loading

Diff for: resources/buttons/changeFontLight.svg

+1
Loading

Diff for: resources/buttons/reloadDark.svg

+1
Loading

Diff for: resources/buttons/reloadLight.svg

+1
Loading

Diff for: src/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,8 @@ set(SOURCE_FILES
589589
widgets/Notebook.hpp
590590
widgets/OverlayWindow.cpp
591591
widgets/OverlayWindow.hpp
592+
widgets/PluginRepl.cpp
593+
widgets/PluginRepl.hpp
592594
widgets/Scrollbar.cpp
593595
widgets/Scrollbar.hpp
594596
widgets/TooltipEntryWidget.cpp

Diff for: src/controllers/plugins/LuaAPI.cpp

+2-15
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,6 @@
3131
namespace {
3232
using namespace chatterino;
3333

34-
void logHelper(lua_State *L, Plugin *pl, QDebug stream,
35-
const sol::variadic_args &args)
36-
{
37-
stream.noquote();
38-
stream << "[" + pl->id + ":" + pl->meta.name + "]";
39-
for (const auto &arg : args)
40-
{
41-
stream << lua::toString(L, arg.stack_index());
42-
// Remove this from our stack
43-
lua_pop(L, 1);
44-
}
45-
}
46-
4734
QDebug qdebugStreamForLogLevel(lua::api::LogLevel lvl)
4835
{
4936
auto base =
@@ -101,7 +88,7 @@ void c2_log(ThisPluginState L, LogLevel lvl, sol::variadic_args args)
10188
lua::StackGuard guard(L);
10289
{
10390
QDebug stream = qdebugStreamForLogLevel(lvl);
104-
logHelper(L, L.plugin(), stream, args);
91+
L.plugin()->log(L.state(), lvl, std::move(stream), args);
10592
}
10693
}
10794

@@ -261,7 +248,7 @@ void g_print(ThisPluginState L, sol::variadic_args args)
261248
(QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE,
262249
QT_MESSAGELOG_FUNC, chatterinoLua().categoryName())
263250
.debug());
264-
logHelper(L, L.plugin(), stream, args);
251+
L.plugin()->log(L.state(), LogLevel::Info, std::move(stream), args);
265252
}
266253

267254
void package_loadlib(sol::variadic_args args)

Diff for: src/controllers/plugins/Plugin.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ std::unordered_set<QString> Plugin::listRegisteredCommands()
218218

219219
Plugin::~Plugin()
220220
{
221+
this->onDestroyed_();
222+
221223
for (auto *timer : this->activeTimeouts)
222224
{
223225
QObject::disconnect(timer, nullptr, nullptr, nullptr);
@@ -293,5 +295,45 @@ bool Plugin::hasHTTPPermissionFor(const QUrl &url)
293295
});
294296
}
295297

298+
boost::signals2::connection Plugin::onDestroyed(
299+
const OnDestroyed::slot_type &slot)
300+
{
301+
return this->onDestroyed_.connect(slot);
302+
}
303+
304+
boost::signals2::connection Plugin::onLog(const OnLog::slot_type &slot)
305+
{
306+
return this->onLog_.connect(slot);
307+
}
308+
309+
void Plugin::log(lua_State *L, lua::api::LogLevel level, QDebug stream,
310+
const sol::variadic_args &args)
311+
{
312+
stream.noquote();
313+
stream << "[" + this->id + ":" + this->meta.name + "]";
314+
QString fullMessage;
315+
for (const auto &arg : args)
316+
{
317+
auto s = lua::toString(L, arg.stack_index());
318+
stream << s;
319+
320+
if (!fullMessage.isEmpty())
321+
{
322+
fullMessage.append(' ');
323+
}
324+
fullMessage.append(s);
325+
326+
// Remove this from our stack
327+
lua_pop(L, 1);
328+
}
329+
330+
this->onLog_(level, fullMessage);
331+
}
332+
333+
sol::state_view Plugin::state()
334+
{
335+
return {this->state_};
336+
}
337+
296338
} // namespace chatterino
297339
#endif

Diff for: src/controllers/plugins/Plugin.hpp

+20
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
# include "controllers/plugins/LuaUtilities.hpp"
88
# include "controllers/plugins/PluginPermission.hpp"
99

10+
# include <boost/signals2/signal.hpp>
1011
# include <QDir>
1112
# include <QString>
1213
# include <QUrl>
@@ -22,6 +23,10 @@
2223
struct lua_State;
2324
class QTimer;
2425

26+
namespace chatterino::lua::api {
27+
enum class LogLevel;
28+
} // namespace chatterino::lua::api
29+
2530
namespace chatterino {
2631

2732
struct PluginMeta {
@@ -65,6 +70,10 @@ struct PluginMeta {
6570

6671
class Plugin
6772
{
73+
using OnDestroyed = boost::signals2::signal<void()>;
74+
using OnLog =
75+
boost::signals2::signal<void(lua::api::LogLevel, const QString &)>;
76+
6877
public:
6978
QString id;
7079
PluginMeta meta;
@@ -137,6 +146,14 @@ class Plugin
137146
bool hasFSPermissionFor(bool write, const QString &path);
138147
bool hasHTTPPermissionFor(const QUrl &url);
139148

149+
boost::signals2::connection onDestroyed(const OnDestroyed::slot_type &slot);
150+
boost::signals2::connection onLog(const OnLog::slot_type &slot);
151+
152+
void log(lua_State *L, lua::api::LogLevel level, QDebug stream,
153+
const sol::variadic_args &args);
154+
155+
sol::state_view state();
156+
140157
std::map<lua::api::EventType, sol::protected_function> callbacks;
141158

142159
// In-flight HTTP Requests
@@ -154,6 +171,9 @@ class Plugin
154171
std::vector<QTimer *> activeTimeouts;
155172
int lastTimerId = 0;
156173

174+
OnDestroyed onDestroyed_;
175+
OnLog onLog_;
176+
157177
friend class PluginController;
158178
friend class PluginControllerAccess; // this is for tests
159179
};

Diff for: src/controllers/plugins/PluginController.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ void PluginController::load(const QFileInfo &index, const QDir &pluginDir,
276276
}
277277
temp->dataDirectory().mkpath(".");
278278

279+
// make sure we capture log messages during load
280+
this->onPluginLoaded_(temp);
279281
qCDebug(chatterinoLua) << "Running lua file:" << index;
280282
int err = luaL_dofile(l, index.absoluteFilePath().toStdString().c_str());
281283
if (err != 0)
@@ -428,5 +430,11 @@ std::pair<bool, QStringList> PluginController::updateCustomCompletions(
428430
return {false, results};
429431
}
430432

433+
boost::signals2::connection PluginController::onPluginLoaded(
434+
const OnPluginLoaded::slot_type &slot)
435+
{
436+
return this->onPluginLoaded_.connect(slot);
437+
}
438+
431439
} // namespace chatterino
432440
#endif

Diff for: src/controllers/plugins/PluginController.hpp

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# include "controllers/commands/CommandContext.hpp"
66
# include "controllers/plugins/Plugin.hpp"
77

8+
# include <boost/signals2/signal.hpp>
89
# include <QDir>
910
# include <QFileInfo>
1011
# include <QJsonArray>
@@ -26,6 +27,8 @@ class Paths;
2627

2728
class PluginController
2829
{
30+
using OnPluginLoaded = boost::signals2::signal<void(Plugin *)>;
31+
2932
const Paths &paths;
3033

3134
public:
@@ -61,6 +64,9 @@ class PluginController
6164
const QString &query, const QString &fullTextContent,
6265
int cursorPosition, bool isFirstWord) const;
6366

67+
boost::signals2::connection onPluginLoaded(
68+
const OnPluginLoaded::slot_type &slot);
69+
6470
private:
6571
void loadPlugins();
6672
void load(const QFileInfo &index, const QDir &pluginDir,
@@ -75,6 +81,8 @@ class PluginController
7581
bool tryLoadFromDir(const QDir &pluginDir);
7682
std::map<QString, std::unique_ptr<Plugin>> plugins_;
7783

84+
OnPluginLoaded onPluginLoaded_;
85+
7886
// This is for tests, pay no attention
7987
friend class PluginControllerAccess;
8088
};

Diff for: src/singletons/Settings.hpp

+6
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,12 @@ class Settings
645645

646646
BoolSetting showSendButton = {"/ui/showSendButton", false};
647647

648+
struct {
649+
QStringSetting fontFamily = {"/ui/pluginRepl/fontFamily", {}};
650+
QStringSetting fontStyle = {"/ui/pluginRepl/fontStyle", "Regular"};
651+
IntSetting fontSize = {"/ui/pluginRepl/fontSize", 10};
652+
} pluginRepl;
653+
648654
// Similarity
649655
BoolSetting similarityEnabled = {"/similarity/similarityEnabled", false};
650656
BoolSetting colorSimilarDisabled = {"/similarity/colorSimilarDisabled",

0 commit comments

Comments
 (0)