diff --git a/CHANGELOG.md b/CHANGELOG.md index 6827cd7..8256221 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/lune.yml b/lune.yml index 3b36aa6..6e90e21 100644 --- a/lune.yml +++ b/lune.yml @@ -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 diff --git a/luneDocs.json b/luneDocs.json index 9f06f86..d764046 100644 --- a/luneDocs.json +++ b/luneDocs.json @@ -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", diff --git a/luneTypes.d.luau b/luneTypes.d.luau index c3ee189..4caf960 100644 --- a/luneTypes.d.luau +++ b/luneTypes.d.luau @@ -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...) -> () +declare info: (T...) -> () +declare warn: (T...) -> () +declare error: (message: T, level: number?) -> never diff --git a/packages/cli/src/gen/mod.rs b/packages/cli/src/gen/mod.rs index 5daa0b6..a2154e4 100644 --- a/packages/cli/src/gen/mod.rs +++ b/packages/cli/src/gen/mod.rs @@ -14,8 +14,8 @@ use self::{doc::DocsFunctionParamLink, visitor::DocumentationVisitor}; fn parse_definitions(contents: &str) -> Result { let (regex, replacement) = ( - Regex::new(r#"declare (?P\w+): \{"#).unwrap(), - r#"export type $n = {"#, + Regex::new(r#"declare (?P\w+): "#).unwrap(), + r#"export type $n = "#, ); let defs_ast = parse_luau_ast(®ex.replace_all(contents, replacement))?; let mut visitor = DocumentationVisitor::new(); diff --git a/packages/lib/src/globals/console.rs b/packages/lib/src/globals/console.rs index f897daf..a197ddf 100644 --- a/packages/lib/src/globals/console.rs +++ b/packages/lib/src/globals/console.rs @@ -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, Option)| { + 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()?, ) } diff --git a/packages/lib/src/globals/mod.rs b/packages/lib/src/globals/mod.rs index 50e8620..b0a27ed 100644 --- a/packages/lib/src/globals/mod.rs +++ b/packages/lib/src/globals/mod.rs @@ -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)| { + 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(()) +} diff --git a/packages/lib/src/globals/process.rs b/packages/lib/src/globals/process.rs index a795b27..d84b259 100644 --- a/packages/lib/src/globals/process.rs +++ b/packages/lib/src/globals/process.rs @@ -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) -> LuaResult<()> { @@ -116,21 +113,7 @@ fn process_env_iter<'lua>( } async fn process_exit(lua: &Lua, exit_code: Option) -> LuaResult<()> { - let sender = lua - .app_data_ref::>>() - .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>( diff --git a/packages/lib/src/lib.rs b/packages/lib/src/lib.rs index 5c6f8f3..d6eba6c 100644 --- a/packages/lib/src/lib.rs +++ b/packages/lib/src/lib.rs @@ -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", diff --git a/packages/lib/src/utils/formatting.rs b/packages/lib/src/utils/formatting.rs index bfd9adc..3d433ba 100644 --- a/packages/lib/src/utils/formatting.rs +++ b/packages/lib/src/utils/formatting.rs @@ -81,6 +81,11 @@ pub fn print_style>(s: S) -> LuaResult<()> { Ok(()) } +pub fn print_reset() -> LuaResult<()> { + print_style("reset")?; + Ok(()) +} + pub fn print_color>(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 )?, diff --git a/packages/lib/src/utils/process.rs b/packages/lib/src/utils/process.rs index 49ad233..5d7398d 100644 --- a/packages/lib/src/utils/process.rs +++ b/packages/lib/src/utils/process.rs @@ -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) -> LuaResult<()> { + let sender = lua + .app_data_ref::>>() + .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(()) +} diff --git a/tests/console/set_color.luau b/tests/console/set_color.luau deleted file mode 100644 index af0dca5..0000000 --- a/tests/console/set_color.luau +++ /dev/null @@ -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 diff --git a/tests/console/set_style.luau b/tests/console/set_style.luau index 78d65e1..bc8697d 100644 --- a/tests/console/set_style.luau +++ b/tests/console/set_style.luau @@ -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 diff --git a/tests/net/request/util.luau b/tests/net/request/util.luau index 4c64d8c..e099d93 100644 --- a/tests/net/request/util.luau +++ b/tests/net/request/util.luau @@ -13,7 +13,6 @@ function util.fail(method, url, message: string) method = method, url = url, }) - console.log(response) assert(not response.ok, message) end diff --git a/tests/net/serve.luau b/tests/net/serve.luau index 7fa4e21..03921f0 100644 --- a/tests/net/serve.luau +++ b/tests/net/serve.luau @@ -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) diff --git a/tests/process/exit.luau b/tests/process/exit.luau index 1d7f26d..eec67ca 100644 --- a/tests/process/exit.luau +++ b/tests/process/exit.luau @@ -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 diff --git a/tests/task/fcheck.luau b/tests/task/fcheck.luau index 04e0081..a6e4139 100644 --- a/tests/task/fcheck.luau +++ b/tests/task/fcheck.luau @@ -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