Add a new completion API for experimental plugins feature. (#5000)

Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
Mm2PL
2023-12-10 14:41:05 +01:00
committed by GitHub
parent e4258160cd
commit fd4cac2c2c
13 changed files with 448 additions and 16 deletions
+62 -10
View File
@@ -19,6 +19,7 @@
# include <memory>
# include <utility>
# include <variant>
namespace chatterino {
@@ -46,15 +47,13 @@ void PluginController::loadPlugins()
auto dir = QDir(getPaths()->pluginsDirectory);
qCDebug(chatterinoLua) << "Loading plugins in" << dir.path();
for (const auto &info :
dir.entryInfoList(QDir::NoFilter | QDir::NoDotAndDotDot))
dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot))
{
if (info.isDir())
{
auto pluginDir = QDir(info.absoluteFilePath());
this->tryLoadFromDir(pluginDir);
}
auto pluginDir = QDir(info.absoluteFilePath());
this->tryLoadFromDir(pluginDir);
}
}
bool PluginController::tryLoadFromDir(const QDir &pluginDir)
{
// look for init.lua
@@ -139,6 +138,7 @@ void PluginController::openLibrariesFor(lua_State *L,
static const luaL_Reg c2Lib[] = {
{"system_msg", lua::api::c2_system_msg},
{"register_command", lua::api::c2_register_command},
{"register_callback", lua::api::c2_register_callback},
{"send_msg", lua::api::c2_send_msg},
{"log", lua::api::c2_log},
{nullptr, nullptr},
@@ -146,14 +146,17 @@ void PluginController::openLibrariesFor(lua_State *L,
lua_pushglobaltable(L);
auto global = lua_gettop(L);
// count of elements in C2LIB + LogLevel
auto c2libIdx = lua::pushEmptyTable(L, 5);
// count of elements in C2LIB + LogLevel + EventType
auto c2libIdx = lua::pushEmptyTable(L, 8);
luaL_setfuncs(L, c2Lib, 0);
lua::pushEnumTable<lua::api::LogLevel>(L);
lua_setfield(L, c2libIdx, "LogLevel");
lua::pushEnumTable<lua::api::EventType>(L);
lua_setfield(L, c2libIdx, "EventType");
lua_setfield(L, global, "c2");
// ban functions
@@ -198,6 +201,7 @@ void PluginController::load(const QFileInfo &index, const QDir &pluginDir,
auto pluginName = pluginDir.dirName();
lua_State *l = luaL_newstate();
auto plugin = std::make_unique<Plugin>(pluginName, l, meta, pluginDir);
auto *temp = plugin.get();
this->plugins_.insert({pluginName, std::move(plugin)});
if (getArgs().safeMode)
@@ -220,9 +224,10 @@ void PluginController::load(const QFileInfo &index, const QDir &pluginDir,
int err = luaL_dofile(l, index.absoluteFilePath().toStdString().c_str());
if (err != 0)
{
temp->error_ = lua::humanErrorText(l, err);
qCWarning(chatterinoLua)
<< "Failed to load" << pluginName << "plugin from" << index << ": "
<< lua::humanErrorText(l, err);
<< temp->error_;
return;
}
qCInfo(chatterinoLua) << "Loaded" << pluginName << "plugin from" << index;
@@ -307,5 +312,52 @@ const std::map<QString, std::unique_ptr<Plugin>> &PluginController::plugins()
return this->plugins_;
}
}; // namespace chatterino
std::pair<bool, QStringList> PluginController::updateCustomCompletions(
const QString &query, const QString &fullTextContent, int cursorPosition,
bool isFirstWord) const
{
QStringList results;
for (const auto &[name, pl] : this->plugins())
{
if (!pl->error().isNull())
{
continue;
}
lua::StackGuard guard(pl->state_);
auto opt = pl->getCompletionCallback();
if (opt)
{
qCDebug(chatterinoLua)
<< "Processing custom completions from plugin" << name;
auto &cb = *opt;
auto errOrList =
cb(query, fullTextContent, cursorPosition, isFirstWord);
if (std::holds_alternative<int>(errOrList))
{
guard.handled();
int err = std::get<int>(errOrList);
qCDebug(chatterinoLua)
<< "Got error from plugin " << pl->meta.name
<< " while refreshing tab completion: "
<< lua::humanErrorText(pl->state_, err);
continue;
}
auto list = std::get<lua::api::CompletionList>(errOrList);
if (list.hideOthers)
{
results = QStringList(list.values.begin(), list.values.end());
return {true, results};
}
results += QStringList(list.values.begin(), list.values.end());
}
}
return {false, results};
}
} // namespace chatterino
#endif