Add proper support for logging from lua

This commit is contained in:
Mm2PL 2023-02-08 23:58:50 +01:00
parent b1031c7211
commit 86c872d4af
No known key found for this signature in database
GPG key ID: 94AC9B80EFA15ED9
4 changed files with 118 additions and 3 deletions

View file

@ -55,7 +55,30 @@ The official manual for them is available [here](https://www.lua.org/manual/5.4/
### Chatterino API
All Chatterino functions are exposed in a global table called `c2`. The following functions are available
All Chatterino functions are exposed in a global table called `c2`. The following members are available:
#### `log(level, args...)`
Writes a message to the Chatterino log. The `level` argument should be a
`LogLevel` member. All `args` should be convertible to a string with
`tostring()`.
Example:
```
c2.log(c2.LogLevel.Warning, "Hello, this should show up in the Chatterino log by default")
c2.log(c2.LogLevel.Debug, "Hello world")
-- Equivalent to doing qCDebug(chatterinoLua) << "[pluginDirectory:Plugin Name]" << "Hello, world"; from C++
```
#### `LogLevel` enum
This table describes log levels available to Lua Plugins. The values behind the names may change, do not count on them. It has the following keys:
- `Debug`
- `Info`
- `Warning`
- `Critical`
#### `register_command(name, handler)`
@ -139,3 +162,7 @@ execfile("./stuff.lua") -- executes Plugins/name/stuff.lua
execfile("../stuff.lua") -- tries to load Plugins/stuff.lua and errors
execfile("luac.out") -- tried to load Plugins/name/luac.out and errors because it contains non-utf8 data
```
#### `print(Args...)`
The `print` global function is equivalent to calling `c2.log(c2.LogLevel.Debug, Args...)`

View file

@ -15,6 +15,7 @@
# include "lualib.h"
# include <QFileInfo>
# include <QLoggingCategory>
# include <QTextCodec>
// NOLINTBEGIN(*vararg)
@ -102,6 +103,63 @@ int c2_system_msg(lua_State *L)
return 1;
}
namespace {
void logHelper(lua_State *L, Plugin *pl, QDebug stream, int argc)
{
stream.noquote();
stream << "[" + pl->codename + ":" + pl->meta.name + "]";
for (int i = 1; i <= argc; i++)
{
stream << lua::toString(L, i);
}
lua_pop(L, argc);
}
} // namespace
int c2_log(lua_State *L)
{
auto *pl = getApp()->plugins->getPluginByStatePtr(L);
if (pl == nullptr)
{
luaL_error(L, "print: internal error: no plugin?");
return 0;
}
auto logc = lua_gettop(L) - 1;
// this is the expansion of qCDebug() macro
auto temp =
(QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE,
QT_MESSAGELOG_FUNC, chatterinoLua().categoryName()));
LogLevel lvl{};
if (!lua::pop(L, &lvl, 1))
{
luaL_error(L, "Invalid log level, use one from c2.LogLevel.");
return 0;
}
QDebug stream{(QString *)nullptr};
switch (lvl)
{
case LogLevel::Debug:
stream = temp.debug();
break;
case LogLevel::Critical:
stream = temp.critical();
break;
case LogLevel::Info:
stream = temp.info();
break;
case LogLevel::Warning:
stream = temp.warning();
break;
default:
assert(false && "if this happens magic_enum must have failed us");
break;
}
logHelper(L, pl, stream, logc);
return 0;
}
int g_load(lua_State *L)
{
auto countArgs = lua_gettop(L);
@ -207,6 +265,24 @@ int g_dofile(lua_State *L)
return lua_gettop(L);
}
int g_print(lua_State *L)
{
auto *pl = getApp()->plugins->getPluginByStatePtr(L);
if (pl == nullptr)
{
luaL_error(L, "print: internal error: no plugin?");
return 0;
}
auto argc = lua_gettop(L);
// this is the expansion of qCDebug() macro
auto stream =
(QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE,
QT_MESSAGELOG_FUNC, chatterinoLua().categoryName())
.debug());
logHelper(L, pl, stream, argc);
return 0;
}
} // namespace chatterino::lua::api
// NOLINTEND(*vararg)
#endif

View file

@ -9,11 +9,16 @@ namespace chatterino::lua::api {
int c2_register_command(lua_State *L);
int c2_send_msg(lua_State *L);
int c2_system_msg(lua_State *L);
int c2_log(lua_State *L);
int g_load(lua_State *L);
int g_dofile(lua_State *L);
int g_print(lua_State *L);
// NOLINTEND(readability-identifier-naming)
// Represents "calls" to qCDebug, qCInfo ...
enum LogLevel { Debug, Info, Warning, Critical };
} // namespace chatterino::lua::api
#endif

View file

@ -147,15 +147,20 @@ void PluginController::openLibrariesFor(lua_State *L,
{"system_msg", lua::api::c2_system_msg},
{"register_command", lua::api::c2_register_command},
{"send_msg", lua::api::c2_send_msg},
{"log", lua::api::c2_log},
{nullptr, nullptr},
};
lua_pushglobaltable(L);
auto global = lua_gettop(L);
// count of elements in C2LIB - 1 (to account for terminator)
lua::pushEmptyTable(L, 3);
// count of elements in C2LIB + LogLevel
auto c2libIdx = lua::pushEmptyTable(L, 5);
luaL_setfuncs(L, c2Lib, 0);
lua::pushEnumTable<lua::api::LogLevel>(L);
lua_setfield(L, c2libIdx, "LogLevel");
lua_setfield(L, global, "c2");
// ban functions
@ -177,6 +182,8 @@ void PluginController::openLibrariesFor(lua_State *L,
// chatterino dofile is way more similar to require() than dofile()
{"execfile", lua::api::g_dofile},
{"print", lua::api::g_print},
{nullptr, nullptr},
};
luaL_setfuncs(L, replacementFuncs, 0);