Autogenerate docs/plugin-meta.lua (#5055)

This commit is contained in:
Mm2PL 2023-12-30 10:26:19 +00:00 committed by GitHub
parent 9a2c27d258
commit 69a54d944d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 247 additions and 37 deletions

View file

@ -103,6 +103,7 @@
- Dev: Added the ability to show `ChannelView`s without a `Split`. (#4747)
- Dev: Refactor Args to be less of a singleton. (#5041)
- Dev: Channels without any animated elements on screen will skip updates from the GIF timer. (#5042, #5043, #5045)
- Dev: Autogenerate docs/plugin-meta.lua. (#5055)
## 2.4.6

View file

@ -1,10 +1,18 @@
---@meta Chatterino2
-- This file is automatically generated from src/controllers/plugins/LuaAPI.hpp by the scripts/make_luals_meta.py script
-- This file is intended to be used with LuaLS (https://luals.github.io/).
-- Add the folder this file is in to "Lua.workspace.library".
---@alias LogLevel integer
c2 = {}
---@alias LogLevel integer
---@type { Debug: LogLevel, Info: LogLevel, Warning: LogLevel, Critical: LogLevel }
c2.LogLevel = {}
---@alias EventType integer
---@type { CompletionRequested: EventType }
c2.EventType = {}
---@class CommandContext
---@field words string[] The words typed when executing the command. For example `/foo bar baz` will result in `{"/foo", "bar", "baz"}`.
---@field channel_name string The name of the channel the command was executed in.
@ -13,22 +21,19 @@
---@field values string[] The completions
---@field hide_others boolean Whether other completions from Chatterino should be hidden/ignored.
c2 = {}
---@type { Debug: LogLevel, Info: LogLevel, Warning: LogLevel, Critical: LogLevel }
c2.LogLevel = {}
--- Writes a message to the Chatterino log.
---@param level LogLevel The desired level.
---@param ... any Values to log. Should be convertible to a string with `tostring()`.
function c2.log(level, ...) end
--- Registers a new command called `name` which when executed will call `handler`.
---
---@param name string The name of the command.
---@param handler fun(ctx: CommandContext) The handler to be invoked when the command gets executed.
---@return boolean ok Returns `true` if everything went ok, `false` if a command with this name exists.
function c2.register_command(name, handler) end
--- Registers a callback to be invoked when completions for a term are requested.
---
---@param type "CompletionRequested"
---@param func fun(query: string, full_text_content: string, cursor_position: integer, is_first_word: boolean): CompletionList The callback to be invoked.
function c2.register_callback(type, func) end
--- Sends a message to `channel` with the specified text. Also executes commands.
---
--- **Warning**: It is possible to trigger your own Lua command with this causing a potentially infinite loop.
@ -39,12 +44,15 @@ function c2.register_command(name, handler) end
function c2.send_msg(channel, text) end
--- Creates a system message (gray message) and adds it to the Twitch channel specified by `channel`.
---
---@param channel string
---@param text string
---@return boolean ok
function c2.system_msg(channel, text) end
--- Registers a callback to be invoked when completions for a term are requested.
---@param type "CompletionRequested"
---@param func fun(query: string, full_text_content: string, cursor_position: integer, is_first_word: boolean): CompletionList The callback to be invoked.
function c2.register_callback(type, func) end
--- Writes a message to the Chatterino log.
---
---@param level LogLevel The desired level.
---@param ... any Values to log. Should be convertible to a string with `tostring()`.
function c2.log(level, ...) end

142
scripts/make_luals_meta.py Normal file
View file

@ -0,0 +1,142 @@
"""
This script generates docs/plugin-meta.lua. It accepts no arguments
It assumes comments look like:
/**
* Thing
*
* @lua@param thing boolean
* @lua@returns boolean
* @exposed name
*/
- Do not have any useful info on '/**' and '*/' lines.
- Class members are not allowed to have non-@command lines and commands different from @lua@field
Valid commands are:
1. @exposeenum [dotted.name.in_lua.last_part]
Define a table with keys of the enum. Values behind those keys aren't
written on purpose.
This generates three lines:
- An type alias of [last_part] to integer,
- A type description that describes available values of the enum,
- A global table definition for the num
2. @lua[@command]
Writes [@command] to the file as a comment, usually this is @class, @param, @return, ...
@lua@class and @lua@field have special treatment when it comes to generation of spacing new lines
3. @exposed [c2.name]
Generates a function definition line from the last `@lua@param`s.
Non-command lines of comments are written with a space after '---'
"""
from pathlib import Path
BOILERPLATE = """
---@meta Chatterino2
-- This file is automatically generated from src/controllers/plugins/LuaAPI.hpp by the scripts/make_luals_meta.py script
-- This file is intended to be used with LuaLS (https://luals.github.io/).
-- Add the folder this file is in to "Lua.workspace.library".
c2 = {}
"""
repo_root = Path(__file__).parent.parent
lua_api_file = repo_root / "src" / "controllers" / "plugins" / "LuaAPI.hpp"
lua_meta = repo_root / "docs" / "plugin-meta.lua"
print("Reading from", lua_api_file.relative_to(repo_root))
print("Writing to", lua_meta.relative_to(repo_root))
with lua_api_file.open("r") as f:
lines = f.read().splitlines()
# Are we in a doc comment?
comment: bool = False
# Last `@lua@param`s seen - for @exposed generation
last_params_names: list[str] = []
# Are we in a `@lua@class` definition? - makes newlines around @lua@class and @lua@field prettier
is_class = False
# The name of the next enum in lua world
expose_next_enum_as: str | None = None
# Name of the current enum in c++ world, used to generate internal typenames for
current_enum_name: str | None = None
with lua_meta.open("w") as out:
out.write(BOILERPLATE[1:]) # skip the newline after triple quote
for line in lines:
line = line.strip()
if line.startswith("enum class "):
line = line.removeprefix("enum class ")
temp = line.split(" ", 2)
current_enum_name = temp[0]
if not expose_next_enum_as:
print(
f"Skipping enum {current_enum_name}, there wasn't a @exposeenum command"
)
current_enum_name = None
continue
current_enum_name = expose_next_enum_as.split(".", 1)[-1]
out.write("---@alias " + current_enum_name + " integer\n")
out.write("---@type { ")
# temp[1] is '{'
if len(temp) == 2: # no values on this line
continue
line = temp[2]
if current_enum_name is not None:
for i, tok in enumerate(line.split(" ")):
if tok == "};":
break
entry = tok.removesuffix(",")
if i != 0:
out.write(", ")
out.write(entry + ": " + current_enum_name)
out.write(" }\n" f"{expose_next_enum_as} = {{}}\n")
print(f"Wrote enum {expose_next_enum_as} => {current_enum_name}")
current_enum_name = None
expose_next_enum_as = None
continue
if line.startswith("/**"):
comment = True
continue
elif "*/" in line:
comment = False
if not is_class:
out.write("\n")
continue
if not comment:
continue
line = line.replace("*", "", 1).lstrip()
if line == "":
out.write("---\n")
elif line.startswith("@exposeenum "):
expose_next_enum_as = line.split(" ", 1)[1]
elif line.startswith("@exposed "):
exp = line.replace("@exposed ", "", 1)
params = ", ".join(last_params_names)
out.write(f"function {exp}({params}) end\n")
print(f"Wrote function {exp}(...)")
last_params_names = []
elif line.startswith("@lua"):
command = line.replace("@lua", "", 1)
if command.startswith("@param"):
last_params_names.append(command.split(" ", 2)[1])
elif command.startswith("@class"):
print(f"Writing {command}")
if is_class:
out.write("\n")
is_class = True
elif not command.startswith("@field"):
is_class = False
out.write("---" + command + "\n")
else:
if is_class:
is_class = False
out.write("\n")
# note the space difference from the branch above
out.write("--- " + line + "\n")

View file

@ -11,10 +11,91 @@ namespace chatterino::lua::api {
// NOLINTBEGIN(readability-identifier-naming)
// Following functions are exposed in c2 table.
// Comments in this file are special, the docs/plugin-meta.lua file is generated from them
// All multiline comments will be added into that file. See scripts/make_luals_meta.py script for more info.
/**
* @exposeenum c2.LogLevel
*/
// Represents "calls" to qCDebug, qCInfo ...
enum class LogLevel { Debug, Info, Warning, Critical };
/**
* @exposeenum c2.EventType
*/
enum class EventType {
CompletionRequested,
};
/**
* @lua@class CommandContext
* @lua@field words string[] The words typed when executing the command. For example `/foo bar baz` will result in `{"/foo", "bar", "baz"}`.
* @lua@field channel_name string The name of the channel the command was executed in.
*/
/**
* @lua@class CompletionList
*/
struct CompletionList {
/**
* @lua@field values string[] The completions
*/
std::vector<QString> values{};
/**
* @lua@field hide_others boolean Whether other completions from Chatterino should be hidden/ignored.
*/
bool hideOthers{};
};
/**
* Registers a new command called `name` which when executed will call `handler`.
*
* @lua@param name string The name of the command.
* @lua@param handler fun(ctx: CommandContext) The handler to be invoked when the command gets executed.
* @lua@return boolean ok Returns `true` if everything went ok, `false` if a command with this name exists.
* @exposed c2.register_command
*/
int c2_register_command(lua_State *L);
/**
* Registers a callback to be invoked when completions for a term are requested.
*
* @lua@param type "CompletionRequested"
* @lua@param func fun(query: string, full_text_content: string, cursor_position: integer, is_first_word: boolean): CompletionList The callback to be invoked.
* @exposed c2.register_callback
*/
int c2_register_callback(lua_State *L);
/**
* Sends a message to `channel` with the specified text. Also executes commands.
*
* **Warning**: It is possible to trigger your own Lua command with this causing a potentially infinite loop.
*
* @lua@param channel string The name of the Twitch channel
* @lua@param text string The text to be sent
* @lua@return boolean ok
* @exposed c2.send_msg
*/
int c2_send_msg(lua_State *L);
/**
* Creates a system message (gray message) and adds it to the Twitch channel specified by `channel`.
*
* @lua@param channel string
* @lua@param text string
* @lua@return boolean ok
* @exposed c2.system_msg
*/
int c2_system_msg(lua_State *L);
/**
* Writes a message to the Chatterino log.
*
* @lua@param level LogLevel The desired level.
* @lua@param ... any Values to log. Should be convertible to a string with `tostring()`.
* @exposed c2.log
*/
int c2_log(lua_State *L);
// These ones are global
@ -26,28 +107,6 @@ int g_print(lua_State *L);
int searcherAbsolute(lua_State *L);
int searcherRelative(lua_State *L);
// Exposed as c2.LogLevel
// Represents "calls" to qCDebug, qCInfo ...
enum class LogLevel { Debug, Info, Warning, Critical };
// Exposed as c2.EventType
// Represents callbacks c2 can do into lua world
enum class EventType {
CompletionRequested,
};
/**
* This is for custom completion, a registered function returns this type
* however in Lua array part (value) and object part (hideOthers) are in the same
* table.
*/
struct CompletionList {
std::vector<QString> values{};
// exposed as hide_others
bool hideOthers{};
};
} // namespace chatterino::lua::api
#endif