Migrate console lib printing functions to regular globals

This commit is contained in:
Filip Tibell 2023-02-05 22:25:36 -05:00
parent 6ae139d987
commit 2e3f95ebd6
No known key found for this signature in database
17 changed files with 198 additions and 243 deletions

View file

@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Changed
- Migrated the pretty-printing and formatting behavior of `console.log/info/warn/error` to the standard Luau printing functions.
### Removed
- Removed printing functions `console.log/info/warn/error` in favor of regular global functions for printing.
## `0.2.2` - February 5th, 2023
### Added

View file

@ -2,32 +2,18 @@
---
globals:
# Console
console.resetColor:
args: []
console.setColor:
args:
- type: string
console.resetStyle:
args: []
console.setStyle:
args:
- type: string
- required: false
type: string
- required: false
type: string
console.format:
must_use: true
args:
- type: "..."
console.log:
args:
- type: "..."
console.info:
args:
- type: "..."
console.warn:
args:
- type: "..."
console.error:
args:
- type: "..."
# FS (filesystem)
fs.readFile:
must_use: true
@ -116,3 +102,18 @@ globals:
args:
- required: false
type: number
# Misc
print:
args:
- type: "..."
info:
args:
- type: "..."
warn:
args:
- type: "..."
error:
args:
- type: any
- required: false
type: number

View file

@ -7,21 +7,6 @@
},
"learn_more_link": ""
},
"@roblox/global/console.error": {
"code_sample": "",
"documentation": "Prints arguments as a human-readable string with syntax highlighting for tables to stderr.\n\nThis will also prepend an [ERROR] tag at the beginning of the message.\n\nUsing this function will automatically set the exit code of the process\nto 1, unless it gets manually specified afterwards using `process.exit`.",
"learn_more_link": "",
"params": [
{
"documentation": "@roblox/global/console.error/param/0",
"name": "..."
}
],
"returns": []
},
"@roblox/global/console.error/param/0": {
"documentation": "The values to print out to stderr"
},
"@roblox/global/console.format": {
"code_sample": "",
"documentation": "Formats arguments into a human-readable string with syntax highlighting for tables.",
@ -42,95 +27,35 @@
"@roblox/global/console.format/return/0": {
"documentation": "The formatted string"
},
"@roblox/global/console.info": {
"code_sample": "",
"documentation": "Prints arguments as a human-readable string with syntax highlighting for tables to stdout.\n\nThis will also prepend an [INFO] tag at the beginning of the message.",
"learn_more_link": "",
"params": [
{
"documentation": "@roblox/global/console.info/param/0",
"name": "..."
}
],
"returns": []
},
"@roblox/global/console.info/param/0": {
"documentation": "The values to print out"
},
"@roblox/global/console.log": {
"code_sample": "",
"documentation": "Prints arguments as a human-readable string with syntax highlighting for tables to stdout.",
"learn_more_link": "",
"params": [
{
"documentation": "@roblox/global/console.log/param/0",
"name": "..."
}
],
"returns": []
},
"@roblox/global/console.log/param/0": {
"documentation": "The values to print out"
},
"@roblox/global/console.resetColor": {
"code_sample": "",
"documentation": "Resets the current persistent output color.",
"learn_more_link": "",
"params": [],
"returns": []
},
"@roblox/global/console.resetStyle": {
"code_sample": "",
"documentation": "Resets the current persistent output style.",
"documentation": "Resets the current persistent output color and style.",
"learn_more_link": "",
"params": [],
"returns": []
},
"@roblox/global/console.setColor": {
"code_sample": "",
"documentation": "Sets the current persistent output color.",
"learn_more_link": "",
"params": [
{
"documentation": "@roblox/global/console.setColor/param/0",
"name": "color"
}
],
"returns": []
},
"@roblox/global/console.setColor/param/0": {
"documentation": "The color to set"
},
"@roblox/global/console.setStyle": {
"code_sample": "",
"documentation": "Sets the current persistent output style.",
"documentation": "Sets the current persistent output color and / or style.",
"learn_more_link": "",
"params": [
{
"documentation": "@roblox/global/console.setStyle/param/0",
"name": "color"
},
{
"documentation": "@roblox/global/console.setStyle/param/1",
"name": "style"
}
],
"returns": []
},
"@roblox/global/console.setStyle/param/0": {
"documentation": "The color to set"
},
"@roblox/global/console.setStyle/param/1": {
"documentation": "The style to set"
},
"@roblox/global/console.warn": {
"code_sample": "",
"documentation": "Prints arguments as a human-readable string with syntax highlighting for tables to stdout.\n\nThis will also prepend an [INFO] tag at the beginning of the message.",
"learn_more_link": "",
"params": [
{
"documentation": "@roblox/global/console.warn/param/0",
"name": "..."
}
],
"returns": []
},
"@roblox/global/console.warn/param/0": {
"documentation": "The values to print out"
},
"@roblox/global/fs": {
"code_sample": "",
"documentation": "Filesystem",

View file

@ -1,5 +1,8 @@
-- Lune v0.2.2
type ConsoleColor = "black" | "red" | "green" | "yellow" | "blue" | "purple" | "cyan" | "white"
type ConsoleStyle = "bold" | "dim"
--[=[
@class console
@ -9,31 +12,18 @@ declare console: {
--[=[
@within console
Resets the current persistent output color.
]=]
resetColor: () -> (),
--[=[
@within console
Sets the current persistent output color.
@param color The color to set
]=]
setColor: (color: "black" | "red" | "green" | "yellow" | "blue" | "purple" | "cyan" | "white") -> (),
--[=[
@within console
Resets the current persistent output style.
Resets the current persistent output color and style.
]=]
resetStyle: () -> (),
--[=[
@within console
Sets the current persistent output style.
Sets the current persistent output color and / or style.
@param color The color to set
@param style The style to set
]=]
setStyle: (style: "bold" | "dim") -> (),
setStyle: (color: ConsoleColor?, style: ConsoleStyle?) -> (),
--[=[
@within console
@ -43,47 +33,6 @@ declare console: {
@return The formatted string
]=]
format: (...any) -> (string),
--[=[
@within console
Prints arguments as a human-readable string with syntax highlighting for tables to stdout.
@param ... The values to print out
]=]
log: (...any) -> (),
--[=[
@within console
Prints arguments as a human-readable string with syntax highlighting for tables to stdout.
This will also prepend an [INFO] tag at the beginning of the message.
@param ... The values to print out
]=]
info: (...any) -> (),
--[=[
@within console
Prints arguments as a human-readable string with syntax highlighting for tables to stdout.
This will also prepend an [INFO] tag at the beginning of the message.
@param ... The values to print out
]=]
warn: (...any) -> (),
--[=[
@within console
Prints arguments as a human-readable string with syntax highlighting for tables to stderr.
This will also prepend an [ERROR] tag at the beginning of the message.
Using this function will automatically set the exit code of the process
to 1, unless it gets manually specified afterwards using `process.exit`.
@param ... The values to print out to stderr
]=]
error: (...any) -> (),
}
--[=[
@ -422,3 +371,10 @@ declare task: {
]=]
wait: (duration: number?) -> (number),
}
-- TODO: Write docs for these and include them in docs gen
declare print: <T...>(T...) -> ()
declare info: <T...>(T...) -> ()
declare warn: <T...>(T...) -> ()
declare error: <T>(message: T, level: number?) -> never

View file

@ -14,8 +14,8 @@ use self::{doc::DocsFunctionParamLink, visitor::DocumentationVisitor};
fn parse_definitions(contents: &str) -> Result<DocumentationVisitor> {
let (regex, replacement) = (
Regex::new(r#"declare (?P<n>\w+): \{"#).unwrap(),
r#"export type $n = {"#,
Regex::new(r#"declare (?P<n>\w+): "#).unwrap(),
r#"export type $n = "#,
);
let defs_ast = parse_luau_ast(&regex.replace_all(contents, replacement))?;
let mut visitor = DocumentationVisitor::new();

View file

@ -1,44 +1,30 @@
use mlua::prelude::*;
use crate::utils::{
formatting::{flush_stdout, pretty_format_multi_value, print_color, print_label, print_style},
formatting::{pretty_format_multi_value, print_color, print_reset, print_style},
table::TableBuilder,
};
pub fn create(lua: &Lua) -> LuaResult<()> {
let print = |args: &LuaMultiValue, throw: bool| -> LuaResult<()> {
let s = pretty_format_multi_value(args)?;
if throw {
eprintln!("{s}");
} else {
println!("{s}");
}
flush_stdout()?;
Ok(())
};
lua.globals().raw_set(
"console",
TableBuilder::new(lua)?
.with_function("resetColor", |_, _: ()| print_color("reset"))?
.with_function("setColor", |_, color: String| print_color(color))?
.with_function("resetStyle", |_, _: ()| print_style("reset"))?
.with_function("setStyle", |_, style: String| print_style(style))?
.with_function("resetStyle", |_, _: ()| print_reset())?
.with_function(
"setStyle",
|_, (color, style): (Option<String>, Option<String>)| {
if let Some(color) = color {
print_color(color)?;
}
if let Some(style) = style {
print_style(style)?;
}
Ok(())
},
)?
.with_function("format", |_, args: LuaMultiValue| {
pretty_format_multi_value(&args)
})?
.with_function("log", move |_, args: LuaMultiValue| print(&args, false))?
.with_function("info", move |_, args: LuaMultiValue| {
print_label("info")?;
print(&args, false)
})?
.with_function("warn", move |_, args: LuaMultiValue| {
print_label("warn")?;
print(&args, false)
})?
.with_function("error", move |_, args: LuaMultiValue| {
print_label("error")?;
print(&args, true)
})?
.build_readonly()?,
)
}

View file

@ -5,9 +5,67 @@ mod process;
mod require;
mod task;
// Global tables
pub use console::create as create_console;
pub use fs::create as create_fs;
pub use net::create as create_net;
pub use process::create as create_process;
pub use require::create as create_require;
pub use task::create as create_task;
// Individual top-level global values
use mlua::prelude::*;
use crate::utils::formatting::pretty_format_multi_value;
pub fn create_top_level(lua: &Lua) -> LuaResult<()> {
let globals = lua.globals();
// HACK: We need to preserve the default behavior of the
// print and error functions, for pcall and such, which
// is really tricky to do from scratch so we will just
// proxy the default print and error functions here
let print_fn: LuaFunction = globals.raw_get("print")?;
let error_fn: LuaFunction = globals.raw_get("error")?;
lua.set_named_registry_value("print", print_fn)?;
lua.set_named_registry_value("error", error_fn)?;
globals.raw_set(
"print",
lua.create_function(|lua, args: LuaMultiValue| {
let formatted = pretty_format_multi_value(&args)?;
let print: LuaFunction = lua.named_registry_value("print")?;
print.call(formatted)?;
Ok(())
})?,
)?;
globals.raw_set(
"info",
lua.create_function(|lua, args: LuaMultiValue| {
let formatted = pretty_format_multi_value(&args)?;
let print: LuaFunction = lua.named_registry_value("print")?;
print.call(formatted)?;
Ok(())
})?,
)?;
globals.raw_set(
"warn",
lua.create_function(|lua, args: LuaMultiValue| {
let formatted = pretty_format_multi_value(&args)?;
let print: LuaFunction = lua.named_registry_value("print")?;
print.call(formatted)?;
Ok(())
})?,
)?;
globals.raw_set(
"error",
lua.create_function(|lua, (arg, level): (LuaValue, Option<u32>)| {
let multi = arg.to_lua_multi(lua)?;
let formatted = pretty_format_multi_value(&multi)?;
let error: LuaFunction = lua.named_registry_value("error")?;
error.call((formatted, level))?;
Ok(())
})?,
)?;
Ok(())
}

View file

@ -3,17 +3,14 @@ use std::{
env,
path::PathBuf,
process::{Command, Stdio},
sync::Weak,
time::Duration,
};
use mlua::prelude::*;
use os_str_bytes::RawOsString;
use tokio::{sync::mpsc::Sender, time};
use crate::{
utils::{process::pipe_and_inherit_child_process_stdio, table::TableBuilder},
LuneMessage,
use crate::utils::{
process::{exit_and_yield_forever, pipe_and_inherit_child_process_stdio},
table::TableBuilder,
};
pub fn create(lua: &Lua, args_vec: Vec<String>) -> LuaResult<()> {
@ -116,21 +113,7 @@ fn process_env_iter<'lua>(
}
async fn process_exit(lua: &Lua, exit_code: Option<u8>) -> LuaResult<()> {
let sender = lua
.app_data_ref::<Weak<Sender<LuneMessage>>>()
.unwrap()
.upgrade()
.unwrap();
// Send an exit signal to the main thread, which
// will try to exit safely and as soon as possible
sender
.send(LuneMessage::Exit(exit_code.unwrap_or(0)))
.await
.map_err(LuaError::external)?;
// Make sure to block the rest of this thread indefinitely since
// the main thread may not register the exit signal right away
time::sleep(Duration::MAX).await;
Ok(())
exit_and_yield_forever(lua, exit_code).await
}
fn process_spawn<'a>(

View file

@ -7,7 +7,10 @@ pub mod globals;
pub mod utils;
use crate::{
globals::{create_console, create_fs, create_net, create_process, create_require, create_task},
globals::{
create_console, create_fs, create_net, create_process, create_require, create_task,
create_top_level,
},
utils::formatting::pretty_format_luau_error,
};
@ -19,6 +22,7 @@ pub enum LuneGlobal {
Process,
Require,
Task,
TopLevel,
}
impl LuneGlobal {
@ -30,6 +34,7 @@ impl LuneGlobal {
Self::Process,
Self::Require,
Self::Task,
Self::TopLevel,
]
}
}
@ -39,7 +44,7 @@ pub(crate) enum LuneMessage {
Exit(u8),
Spawned,
Finished,
LuaError(mlua::Error),
LuaError(LuaError),
}
#[derive(Clone, Debug, Default)]
@ -86,6 +91,7 @@ impl Lune {
LuneGlobal::Process => create_process(&lua, self.args.clone())?,
LuneGlobal::Require => create_require(&lua)?,
LuneGlobal::Task => create_task(&lua)?,
LuneGlobal::TopLevel => create_top_level(&lua)?,
}
}
// Spawn the main thread from our entrypoint script
@ -213,7 +219,6 @@ mod tests {
run_tests! {
console_format: "console/format",
console_set_color: "console/set_color",
console_set_style: "console/set_style",
fs_files: "fs/files",
fs_dirs: "fs/dirs",

View file

@ -81,6 +81,11 @@ pub fn print_style<S: AsRef<str>>(s: S) -> LuaResult<()> {
Ok(())
}
pub fn print_reset() -> LuaResult<()> {
print_style("reset")?;
Ok(())
}
pub fn print_color<S: AsRef<str>>(s: S) -> LuaResult<()> {
print!(
"{}",
@ -124,6 +129,7 @@ pub fn pretty_format_value(
COLOR_GREEN,
s.to_string_lossy()
.replace('"', r#"\""#)
.replace('\r', r#"\r"#)
.replace('\n', r#"\n"#),
COLOR_RESET
)?,

View file

@ -4,9 +4,14 @@ use std::{
io,
io::Write,
process::{Child, ExitStatus},
sync::Weak,
time::Duration,
};
use mlua::prelude::*;
use tokio::{sync::mpsc::Sender, time};
use crate::LuneMessage;
pub struct TeeWriter<'a, W0: Write, W1: Write> {
w0: &'a mut W0,
@ -72,3 +77,21 @@ pub fn pipe_and_inherit_child_process_stdio(
Ok::<_, LuaError>((status, stdout_log?, stderr_log?))
})
}
pub async fn exit_and_yield_forever(lua: &Lua, exit_code: Option<u8>) -> LuaResult<()> {
let sender = lua
.app_data_ref::<Weak<Sender<LuneMessage>>>()
.unwrap()
.upgrade()
.unwrap();
// Send an exit signal to the main thread, which
// will try to exit safely and as soon as possible
sender
.send(LuneMessage::Exit(exit_code.unwrap_or(0)))
.await
.map_err(LuaError::external)?;
// Make sure to block the rest of this thread indefinitely since
// the main thread may not register the exit signal right away
time::sleep(Duration::MAX).await;
Ok(())
}

View file

@ -1,15 +0,0 @@
local VALID_COLORS = { "black", "red", "green", "yellow", "blue", "purple", "cyan", "white" }
local INVALID_COLORS = { "", "gray", "grass", "red?", "super red", " ", "none" }
for _, color in VALID_COLORS do
if not pcall(console.setColor, color :: any) then
error(string.format("Setting color failed for color '%s'", color))
end
end
for _, color in INVALID_COLORS do
if pcall(console.setColor, color :: any) then
console.resetColor()
error(string.format("Setting color should have failed for color '%s' but succeeded", color))
end
end

View file

@ -1,14 +1,34 @@
local VALID_STYLES = { "bold", "dim" }
local INVALID_STYLES = { "", "*bold*", "dimm", "megabright", "cheerful", "sad", " " }
local STYLES_VALID = { "bold", "dim" }
local STYLES_INVALID = { "", "*bold*", "dimm", "megabright", "cheerful", "sad", " " }
for _, style in VALID_STYLES do
if not pcall(console.setStyle, style :: any) then
local COLORS_VALID = { "black", "red", "green", "yellow", "blue", "purple", "cyan", "white" }
local COLORS_INVALID = { "", "gray", "grass", "red?", "super red", " ", "none" }
-- Test colors
for _, color in COLORS_VALID do
if not pcall(console.setStyle, color :: any, nil) then
error(string.format("Setting color failed for color '%s'", color))
end
end
for _, color in COLORS_INVALID do
if pcall(console.setStyle, color :: any, nil) then
console.resetStyle()
error(string.format("Setting color should have failed for color '%s' but succeeded", color))
end
end
-- Test styles
for _, style in STYLES_VALID do
if not pcall(console.setStyle, nil, style :: any) then
error(string.format("Setting style failed for style '%s'", style))
end
end
for _, style in INVALID_STYLES do
if pcall(console.setStyle, style :: any) then
for _, style in STYLES_INVALID do
if pcall(console.setStyle, nil, style :: any) then
console.resetStyle()
error(string.format("Setting style should have failed for style '%s' but succeeded", style))
end

View file

@ -13,7 +13,6 @@ function util.fail(method, url, message: string)
method = method,
url = url,
})
console.log(response)
assert(not response.ok, message)
end

View file

@ -2,8 +2,8 @@ local RESPONSE = "Hello, lune!"
task.spawn(function()
net.serve(8080, function(request)
console.info("Request:", request)
console.info("Responding with", RESPONSE)
-- info("Request:", request)
-- info("Responding with", RESPONSE)
return RESPONSE
end)
end)
@ -16,6 +16,5 @@ task.delay(1, function()
end)
task.delay(2, function()
console.error("Process did not exit")
process.exit(1)
error("Process did not exit")
end)

View file

@ -1,6 +1,6 @@
local function assert(condition, err)
if not condition then
console.error(err)
task.spawn(error, err)
process.exit(0)
end
end

View file

@ -1,6 +1,6 @@
return function(index: number, type: string, value: any)
if typeof(value) ~= type then
console.error(
error(
string.format(
"Expected argument #%d to be of type %s, got %s",
index,
@ -8,6 +8,5 @@ return function(index: number, type: string, value: any)
console.format(value)
)
)
process.exit(1)
end
end