Add a Plugins settings page

This commit is contained in:
Mm2PL 2023-01-30 23:22:14 +01:00
parent cc0aa1aa82
commit 03de6869c4
No known key found for this signature in database
GPG key ID: 94AC9B80EFA15ED9
6 changed files with 128 additions and 14 deletions

View file

@ -542,6 +542,8 @@ set(SOURCE_FILES
widgets/settingspages/NicknamesPage.hpp
widgets/settingspages/NotificationPage.cpp
widgets/settingspages/NotificationPage.hpp
widgets/settingspages/PluginsPage.cpp
widgets/settingspages/PluginsPage.hpp
widgets/settingspages/SettingsPage.cpp
widgets/settingspages/SettingsPage.hpp

View file

@ -11,6 +11,8 @@
#include "widgets/splits/Split.hpp"
#include "widgets/Window.hpp"
#include <QJsonDocument>
#include <memory>
#include <utility>
@ -43,14 +45,32 @@ void PluginController::initialize(Settings &settings, Paths &paths)
<< "Missing index.lua in plugin directory" << pluginDir;
continue;
}
qCDebug(chatterinoLua) << "found index.lua, running it!";
qCDebug(chatterinoLua)
<< "found index.lua, now looking for info.json!";
auto info = QFileInfo(pluginDir.filePath("info.json"));
if (!info.exists())
{
qCDebug(chatterinoLua)
<< "Missing info.json in plugin directory" << pluginDir;
continue;
}
QFile infoFile(info.absoluteFilePath());
infoFile.open(QIODevice::ReadOnly);
auto everything = infoFile.readAll();
auto doc = QJsonDocument::fromJson(everything);
if (!doc.isObject())
{
qCDebug(chatterinoLua)
<< "info.json root is not an object" << pluginDir;
continue;
}
this->load(index, pluginDir);
this->load(index, pluginDir, PluginMeta(doc.object()));
}
}
}
void PluginController::load(QFileInfo index, QDir pluginDir)
void PluginController::load(QFileInfo index, QDir pluginDir, PluginMeta meta)
{
qCDebug(chatterinoLua) << "Running lua file" << index;
lua_State *l = luaL_newstate();
@ -58,8 +78,8 @@ void PluginController::load(QFileInfo index, QDir pluginDir)
this->loadChatterinoLib(l);
auto pluginName = pluginDir.dirName();
auto plugin = std::make_unique<Plugin>(pluginName, l);
this->plugins.insert({pluginName, std::move(plugin)});
auto plugin = std::make_unique<Plugin>(pluginName, l, meta);
this->plugins_.insert({pluginName, std::move(plugin)});
luaL_dofile(l, index.absoluteFilePath().toStdString().c_str());
qCInfo(chatterinoLua) << "Loaded" << pluginName << "plugin from" << index;
@ -67,7 +87,7 @@ void PluginController::load(QFileInfo index, QDir pluginDir)
void PluginController::callEvery(const QString &functionName)
{
for (const auto &[name, plugin] : this->plugins)
for (const auto &[name, plugin] : this->plugins_)
{
lua_getglobal(plugin->state_, functionName.toStdString().c_str());
lua_pcall(plugin->state_, 0, 0, 0);
@ -78,7 +98,7 @@ void PluginController::callEveryWithArgs(
const QString &functionName, int count,
std::function<void(const std::unique_ptr<Plugin> &pl, lua_State *L)> argCb)
{
for (const auto &[name, plugin] : this->plugins)
for (const auto &[name, plugin] : this->plugins_)
{
lua_getglobal(plugin->state_, functionName.toStdString().c_str());
argCb(plugin, plugin->state_);
@ -89,7 +109,7 @@ void PluginController::callEveryWithArgs(
QString PluginController::tryExecPluginCommand(const QString &commandName,
const CommandContext &ctx)
{
for (auto &[name, plugin] : this->plugins)
for (auto &[name, plugin] : this->plugins_)
{
if (auto it = plugin->ownedCommands.find(commandName);
it != plugin->ownedCommands.end())

View file

@ -9,6 +9,8 @@
#include <QDir>
#include <QFileInfo>
#include <QJsonArray>
#include <QJsonObject>
#include <QString>
#include <map>
@ -20,12 +22,34 @@ struct lua_State;
namespace chatterino {
struct PluginMeta {
QString name;
QString description;
QString authors;
QString homepage;
std::vector<QString> tags;
explicit PluginMeta(const QJsonObject &obj)
: name(obj.value("name").toString())
, description(obj.value("description").toString())
, authors(obj.value("authors").toString())
, homepage(obj.value("homepage").toString())
{
for (const auto &t : obj.value("tags").toArray())
{
tags.push_back(t.toString());
}
}
};
class Plugin
{
public:
QString name;
Plugin(QString name, lua_State *state)
: name(std::move(name))
QString codename;
PluginMeta meta;
Plugin(QString codename, lua_State *state, PluginMeta meta)
: codename(std::move(codename))
, meta(std::move(meta))
, state_(state)
{
}
@ -73,7 +97,7 @@ public:
// This is required to be public because of c functions
Plugin *getPluginByStatePtr(lua_State *L)
{
for (auto &[name, plugin] : this->plugins)
for (auto &[name, plugin] : this->plugins_)
{
if (plugin->state_ == L)
{
@ -83,10 +107,15 @@ public:
return nullptr;
}
const std::map<QString, std::unique_ptr<Plugin>> &plugins() const
{
return this->plugins_;
}
private:
void load(QFileInfo index, QDir pluginDir);
void load(QFileInfo index, QDir pluginDir, PluginMeta meta);
void loadChatterinoLib(lua_State *l);
std::map<QString, std::unique_ptr<Plugin>> plugins;
std::map<QString, std::unique_ptr<Plugin>> plugins_;
};
}; // namespace chatterino

View file

@ -20,6 +20,7 @@
#include "widgets/settingspages/ModerationPage.hpp"
#include "widgets/settingspages/NicknamesPage.hpp"
#include "widgets/settingspages/NotificationPage.hpp"
#include "widgets/settingspages/PluginsPage.hpp"
#include <QDialogButtonBox>
#include <QLineEdit>
@ -215,6 +216,7 @@ void SettingsDialog::addTabs()
this->addTab([]{return new ModerationPage;}, "Moderation", ":/settings/moderation.svg", SettingsTabId::Moderation);
this->addTab([]{return new NotificationPage;}, "Live Notifications", ":/settings/notification2.svg");
this->addTab([]{return new ExternalToolsPage;}, "External tools", ":/settings/externaltools.svg");
this->addTab([]{return new PluginsPage;}, "Plugins", ":/settings/externaltools.svg");
this->ui_.tabContainer->addStretch(1);
this->addTab([]{return new AboutPage;}, "About", ":/settings/about.svg", SettingsTabId(), Qt::AlignBottom);
// clang-format on

View file

@ -0,0 +1,52 @@
#include "PluginsPage.hpp"
#include "Application.hpp"
#include "controllers/plugins/PluginController.hpp"
#include "singletons/Settings.hpp"
#include "util/Helpers.hpp"
#include "util/LayoutCreator.hpp"
#include "util/RemoveScrollAreaBackground.hpp"
#include <QFormLayout>
#include <QGroupBox>
#include <QLabel>
namespace chatterino {
PluginsPage::PluginsPage()
{
LayoutCreator<PluginsPage> layoutCreator(this);
auto scroll = layoutCreator.emplace<QScrollArea>();
auto widget = scroll.emplaceScrollAreaWidget();
removeScrollAreaBackground(scroll.getElement(), widget.getElement());
auto layout = widget.setLayoutType<QVBoxLayout>();
auto group = layout.emplace<QGroupBox>("Plugins");
auto groupLayout = group.setLayoutType<QFormLayout>();
auto *description =
new QLabel("You can load plugins by putting them into "
"<chatterino-app-data-folder>/Plugins/. Each one is a "
"new directory.");
description->setWordWrap(true);
description->setStyleSheet("color: #bbb");
groupLayout->addRow(description);
for (const auto &[codename, plugin] : getApp()->plugins->plugins())
{
auto plgroup = groupLayout.emplace<QGroupBox>(plugin->meta.name);
auto pl = plgroup.setLayoutType<QFormLayout>();
auto *descrText = new QLabel(plugin->meta.description);
descrText->setTextFormat(Qt::TextFormat::MarkdownText);
descrText->setWordWrap(true);
descrText->setStyleSheet("color: #bbb");
pl->addRow(descrText);
pl->addRow("Authors", new QLabel(plugin->meta.authors));
auto *homepage = new QLabel(formatRichLink(plugin->meta.homepage));
homepage->setOpenExternalLinks(true);
pl->addRow("Homepage", homepage);
}
}
} // namespace chatterino

View file

@ -0,0 +1,9 @@
#pragma once
#include "widgets/settingspages/SettingsPage.hpp"
namespace chatterino {
class PluginsPage : public SettingsPage
{
public:
PluginsPage();
};
} // namespace chatterino