mirror of
https://github.com/lune-org/lune.git
synced 2024-12-13 05:20:37 +00:00
Migrate console global to stdio
This commit is contained in:
parent
420a861061
commit
bbf1c9f4f7
19 changed files with 435 additions and 299 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -7,14 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
- Added a new global `stdio` which replaces `console` and adds a couple new functions:
|
||||
- `write` writes a string directly to stdout, without any newlines
|
||||
- `ewrite` writes a string directly to stderr, without any newlines
|
||||
|
||||
### Changed
|
||||
|
||||
- Migrated `console.setColor/resetColor` and `console.setStyle/resetStyle` to `stdio.color` and `stdio.style` to allow for more flexibility in custom printing using ANSI color codes. Check the documentation for new usage and behavior.
|
||||
- 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.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed scripts hanging indefinitely on error
|
||||
|
||||
## `0.2.2` - February 5th, 2023
|
||||
|
||||
### Added
|
||||
|
|
33
Cargo.lock
generated
33
Cargo.lock
generated
|
@ -117,6 +117,19 @@ dependencies = [
|
|||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"unicode-width",
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
|
@ -136,6 +149,12 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.32"
|
||||
|
@ -450,6 +469,12 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.139"
|
||||
|
@ -518,7 +543,9 @@ name = "lune"
|
|||
version = "0.2.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"console",
|
||||
"hyper",
|
||||
"lazy_static",
|
||||
"mlua",
|
||||
"os_str_bytes",
|
||||
"reqwest",
|
||||
|
@ -1134,6 +1161,12 @@ dependencies = [
|
|||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
|
|
|
@ -35,10 +35,10 @@ More examples of how to write Lune scripts can be found in the [examples](.lune/
|
|||
<details>
|
||||
<summary><b>🔎 List of APIs</b></summary>
|
||||
|
||||
`console` - Logging & formatting <br />
|
||||
`fs` - Filesystem <br />
|
||||
`net` - Networking <br />
|
||||
`process` - Current process & child processes <br />
|
||||
`stdio` - Standard input / output & utility functions <br />
|
||||
`task` - Task scheduler & thread spawning <br />
|
||||
|
||||
Documentation for individual members and types can be found using your editor of choice and [Luau LSP](https://github.com/JohnnyMorganz/luau-lsp).
|
||||
|
|
32
lune.yml
32
lune.yml
|
@ -1,19 +1,6 @@
|
|||
# Lune v0.2.2
|
||||
---
|
||||
globals:
|
||||
# Console
|
||||
console.resetStyle:
|
||||
args: []
|
||||
console.setStyle:
|
||||
args:
|
||||
- required: false
|
||||
type: string
|
||||
- required: false
|
||||
type: string
|
||||
console.format:
|
||||
must_use: true
|
||||
args:
|
||||
- type: "..."
|
||||
# FS (filesystem)
|
||||
fs.readFile:
|
||||
must_use: true
|
||||
|
@ -80,6 +67,25 @@ globals:
|
|||
type: table
|
||||
- required: false
|
||||
type: table
|
||||
# Stdio
|
||||
stdio.color:
|
||||
must_use: true
|
||||
args:
|
||||
- type: string
|
||||
stdio.style:
|
||||
must_use: true
|
||||
args:
|
||||
- type: string
|
||||
console.format:
|
||||
must_use: true
|
||||
args:
|
||||
- type: "..."
|
||||
stdio.write:
|
||||
args:
|
||||
- type: string
|
||||
stdio.ewrite:
|
||||
args:
|
||||
- type: string
|
||||
# Task
|
||||
task.cancel:
|
||||
args:
|
||||
|
|
145
luneDocs.json
145
luneDocs.json
|
@ -1,61 +1,4 @@
|
|||
{
|
||||
"@roblox/global/console": {
|
||||
"code_sample": "",
|
||||
"documentation": "Logging & formatting",
|
||||
"keys": {
|
||||
"console": "@roblox/global/console.console"
|
||||
},
|
||||
"learn_more_link": ""
|
||||
},
|
||||
"@roblox/global/console.format": {
|
||||
"code_sample": "",
|
||||
"documentation": "Formats arguments into a human-readable string with syntax highlighting for tables.",
|
||||
"learn_more_link": "",
|
||||
"params": [
|
||||
{
|
||||
"documentation": "@roblox/global/console.format/param/0",
|
||||
"name": "..."
|
||||
}
|
||||
],
|
||||
"returns": [
|
||||
"@roblox/global/console.format/return/0"
|
||||
]
|
||||
},
|
||||
"@roblox/global/console.format/param/0": {
|
||||
"documentation": "The values to format"
|
||||
},
|
||||
"@roblox/global/console.format/return/0": {
|
||||
"documentation": "The formatted string"
|
||||
},
|
||||
"@roblox/global/console.resetStyle": {
|
||||
"code_sample": "",
|
||||
"documentation": "Resets the current persistent output color and style.",
|
||||
"learn_more_link": "",
|
||||
"params": [],
|
||||
"returns": []
|
||||
},
|
||||
"@roblox/global/console.setStyle": {
|
||||
"code_sample": "",
|
||||
"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/fs": {
|
||||
"code_sample": "",
|
||||
"documentation": "Filesystem",
|
||||
|
@ -386,6 +329,94 @@
|
|||
"@roblox/global/process.spawn/return/0": {
|
||||
"documentation": "A dictionary representing the result of the child process"
|
||||
},
|
||||
"@roblox/global/stdio": {
|
||||
"code_sample": "",
|
||||
"documentation": "Standard input / output & utility functions",
|
||||
"keys": {
|
||||
"stdio": "@roblox/global/stdio.stdio"
|
||||
},
|
||||
"learn_more_link": ""
|
||||
},
|
||||
"@roblox/global/stdio.color": {
|
||||
"code_sample": "",
|
||||
"documentation": "Return an ANSI string that can be used to modify the persistent output color.\n\nPass `\"reset\"` to get a string that can reset the persistent output color.\n\n### Example usage\n\n```lua\nstdio.write(stdio.color(\"red\"))\nprint(\"This text will be red\")\nstdio.write(stdio.color(\"reset\"))\nprint(\"This text will be normal\")\n```",
|
||||
"learn_more_link": "",
|
||||
"params": [
|
||||
{
|
||||
"documentation": "@roblox/global/stdio.color/param/0",
|
||||
"name": "color"
|
||||
}
|
||||
],
|
||||
"returns": []
|
||||
},
|
||||
"@roblox/global/stdio.color/param/0": {
|
||||
"documentation": "The color to use"
|
||||
},
|
||||
"@roblox/global/stdio.ewrite": {
|
||||
"code_sample": "",
|
||||
"documentation": "Writes a string directly to stderr, without any newline.",
|
||||
"learn_more_link": "",
|
||||
"params": [
|
||||
{
|
||||
"documentation": "@roblox/global/stdio.ewrite/param/0",
|
||||
"name": "s"
|
||||
}
|
||||
],
|
||||
"returns": []
|
||||
},
|
||||
"@roblox/global/stdio.ewrite/param/0": {
|
||||
"documentation": "The string to write to stderr"
|
||||
},
|
||||
"@roblox/global/stdio.format": {
|
||||
"code_sample": "",
|
||||
"documentation": "Formats arguments into a human-readable string with syntax highlighting for tables.",
|
||||
"learn_more_link": "",
|
||||
"params": [
|
||||
{
|
||||
"documentation": "@roblox/global/stdio.format/param/0",
|
||||
"name": "..."
|
||||
}
|
||||
],
|
||||
"returns": [
|
||||
"@roblox/global/stdio.format/return/0"
|
||||
]
|
||||
},
|
||||
"@roblox/global/stdio.format/param/0": {
|
||||
"documentation": "The values to format"
|
||||
},
|
||||
"@roblox/global/stdio.format/return/0": {
|
||||
"documentation": "The formatted string"
|
||||
},
|
||||
"@roblox/global/stdio.style": {
|
||||
"code_sample": "",
|
||||
"documentation": "Return an ANSI string that can be used to modify the persistent output style.\n\nPass `\"reset\"` to get a string that can reset the persistent output style.\n\n### Example usage\n\n```lua\nstdio.write(stdio.style(\"bold\"))\nprint(\"This text will be bold\")\nstdio.write(stdio.style(\"reset\"))\nprint(\"This text will be normal\")\n```",
|
||||
"learn_more_link": "",
|
||||
"params": [
|
||||
{
|
||||
"documentation": "@roblox/global/stdio.style/param/0",
|
||||
"name": "style"
|
||||
}
|
||||
],
|
||||
"returns": []
|
||||
},
|
||||
"@roblox/global/stdio.style/param/0": {
|
||||
"documentation": "The style to use"
|
||||
},
|
||||
"@roblox/global/stdio.write": {
|
||||
"code_sample": "",
|
||||
"documentation": "Writes a string directly to stdout, without any newline.",
|
||||
"learn_more_link": "",
|
||||
"params": [
|
||||
{
|
||||
"documentation": "@roblox/global/stdio.write/param/0",
|
||||
"name": "s"
|
||||
}
|
||||
],
|
||||
"returns": []
|
||||
},
|
||||
"@roblox/global/stdio.write/param/0": {
|
||||
"documentation": "The string to write to stdout"
|
||||
},
|
||||
"@roblox/global/task": {
|
||||
"code_sample": "",
|
||||
"documentation": "Task scheduler & thread spawning",
|
||||
|
|
106
luneTypes.d.luau
106
luneTypes.d.luau
|
@ -1,40 +1,5 @@
|
|||
-- Lune v0.2.2
|
||||
|
||||
type ConsoleColor = "black" | "red" | "green" | "yellow" | "blue" | "purple" | "cyan" | "white"
|
||||
type ConsoleStyle = "bold" | "dim"
|
||||
|
||||
--[=[
|
||||
@class console
|
||||
|
||||
Logging & formatting
|
||||
]=]
|
||||
declare console: {
|
||||
--[=[
|
||||
@within console
|
||||
|
||||
Resets the current persistent output color and style.
|
||||
]=]
|
||||
resetStyle: () -> (),
|
||||
--[=[
|
||||
@within console
|
||||
|
||||
Sets the current persistent output color and / or style.
|
||||
|
||||
@param color The color to set
|
||||
@param style The style to set
|
||||
]=]
|
||||
setStyle: (color: ConsoleColor?, style: ConsoleStyle?) -> (),
|
||||
--[=[
|
||||
@within console
|
||||
|
||||
Formats arguments into a human-readable string with syntax highlighting for tables.
|
||||
|
||||
@param ... The values to format
|
||||
@return The formatted string
|
||||
]=]
|
||||
format: (...any) -> (string),
|
||||
}
|
||||
|
||||
--[=[
|
||||
@class fs
|
||||
|
||||
|
@ -317,6 +282,77 @@ declare process: {
|
|||
},
|
||||
}
|
||||
|
||||
--[=[
|
||||
@class stdio
|
||||
|
||||
Standard input / output & utility functions
|
||||
]=]
|
||||
declare stdio: {
|
||||
--[=[
|
||||
@within stdio
|
||||
|
||||
Return an ANSI string that can be used to modify the persistent output color.
|
||||
|
||||
Pass `"reset"` to get a string that can reset the persistent output color.
|
||||
|
||||
### Example usage
|
||||
|
||||
```lua
|
||||
stdio.write(stdio.color("red"))
|
||||
print("This text will be red")
|
||||
stdio.write(stdio.color("reset"))
|
||||
print("This text will be normal")
|
||||
```
|
||||
|
||||
@param color The color to use
|
||||
]=]
|
||||
color: (color: "reset" | "black" | "red" | "green" | "yellow" | "blue" | "purple" | "cyan" | "white") -> (),
|
||||
--[=[
|
||||
@within stdio
|
||||
|
||||
Return an ANSI string that can be used to modify the persistent output style.
|
||||
|
||||
Pass `"reset"` to get a string that can reset the persistent output style.
|
||||
|
||||
### Example usage
|
||||
|
||||
```lua
|
||||
stdio.write(stdio.style("bold"))
|
||||
print("This text will be bold")
|
||||
stdio.write(stdio.style("reset"))
|
||||
print("This text will be normal")
|
||||
```
|
||||
|
||||
@param style The style to use
|
||||
]=]
|
||||
style: (style: "reset" | "bold" | "dim") -> (),
|
||||
--[=[
|
||||
@within stdio
|
||||
|
||||
Formats arguments into a human-readable string with syntax highlighting for tables.
|
||||
|
||||
@param ... The values to format
|
||||
@return The formatted string
|
||||
]=]
|
||||
format: (...any) -> (string),
|
||||
--[=[
|
||||
@within stdio
|
||||
|
||||
Writes a string directly to stdout, without any newline.
|
||||
|
||||
@param s The string to write to stdout
|
||||
]=]
|
||||
write: (s: string) -> (),
|
||||
--[=[
|
||||
@within stdio
|
||||
|
||||
Writes a string directly to stderr, without any newline.
|
||||
|
||||
@param s The string to write to stderr
|
||||
]=]
|
||||
ewrite: (s: string) -> (),
|
||||
}
|
||||
|
||||
--[=[
|
||||
@class task
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ serde.workspace = true
|
|||
tokio.workspace = true
|
||||
reqwest.workspace = true
|
||||
|
||||
console = "0.15.5"
|
||||
lazy_static = "1.4.0"
|
||||
os_str_bytes = "6.4.1"
|
||||
|
||||
hyper = { version = "0.14.24", features = ["full"] }
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
use mlua::prelude::*;
|
||||
|
||||
use crate::utils::{
|
||||
formatting::{pretty_format_multi_value, print_color, print_reset, print_style},
|
||||
table::TableBuilder,
|
||||
};
|
||||
|
||||
pub fn create(lua: &Lua) -> LuaResult<()> {
|
||||
lua.globals().raw_set(
|
||||
"console",
|
||||
TableBuilder::new(lua)?
|
||||
.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)
|
||||
})?
|
||||
.build_readonly()?,
|
||||
)
|
||||
}
|
|
@ -1,24 +1,24 @@
|
|||
mod console;
|
||||
mod fs;
|
||||
mod net;
|
||||
mod process;
|
||||
mod require;
|
||||
mod stdio;
|
||||
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 stdio::create as create_stdio;
|
||||
pub use task::create as create_task;
|
||||
|
||||
// Individual top-level global values
|
||||
|
||||
use mlua::prelude::*;
|
||||
|
||||
use crate::utils::formatting::pretty_format_multi_value;
|
||||
use crate::utils::formatting::{format_label, pretty_format_multi_value};
|
||||
|
||||
pub fn create_top_level(lua: &Lua) -> LuaResult<()> {
|
||||
let globals = lua.globals();
|
||||
|
@ -42,28 +42,40 @@ pub fn create_top_level(lua: &Lua) -> LuaResult<()> {
|
|||
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)?;
|
||||
print.call(format!(
|
||||
"{}\n{}",
|
||||
format_label("info"),
|
||||
pretty_format_multi_value(&args)?
|
||||
))?;
|
||||
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)?;
|
||||
print.call(format!(
|
||||
"{}\n{}",
|
||||
format_label("warn"),
|
||||
pretty_format_multi_value(&args)?
|
||||
))?;
|
||||
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))?;
|
||||
let multi = arg.to_lua_multi(lua)?;
|
||||
error.call((
|
||||
format!(
|
||||
"{}\n{}",
|
||||
format_label("error"),
|
||||
pretty_format_multi_value(&multi)?
|
||||
),
|
||||
level,
|
||||
))?;
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
|
|
35
packages/lib/src/globals/stdio.rs
Normal file
35
packages/lib/src/globals/stdio.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use mlua::prelude::*;
|
||||
|
||||
use crate::utils::{
|
||||
formatting::{
|
||||
format_style, pretty_format_multi_value, style_from_color_str, style_from_style_str,
|
||||
},
|
||||
table::TableBuilder,
|
||||
};
|
||||
|
||||
pub fn create(lua: &Lua) -> LuaResult<()> {
|
||||
lua.globals().raw_set(
|
||||
"stdio",
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("color", |_, color: String| {
|
||||
let ansi_string = format_style(style_from_color_str(&color)?);
|
||||
Ok(ansi_string)
|
||||
})?
|
||||
.with_function("style", |_, style: String| {
|
||||
let ansi_string = format_style(style_from_style_str(&style)?);
|
||||
Ok(ansi_string)
|
||||
})?
|
||||
.with_function("format", |_, args: LuaMultiValue| {
|
||||
pretty_format_multi_value(&args)
|
||||
})?
|
||||
.with_function("write", |_, s: String| {
|
||||
print!("{s}");
|
||||
Ok(())
|
||||
})?
|
||||
.with_function("ewrite", |_, s: String| {
|
||||
eprint!("{s}");
|
||||
Ok(())
|
||||
})?
|
||||
.build_readonly()?,
|
||||
)
|
||||
}
|
|
@ -8,7 +8,7 @@ pub(crate) mod utils;
|
|||
|
||||
use crate::{
|
||||
globals::{
|
||||
create_console, create_fs, create_net, create_process, create_require, create_task,
|
||||
create_fs, create_net, create_process, create_require, create_stdio, create_task,
|
||||
create_top_level,
|
||||
},
|
||||
utils::formatting::pretty_format_luau_error,
|
||||
|
@ -16,11 +16,11 @@ use crate::{
|
|||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum LuneGlobal {
|
||||
Console,
|
||||
Fs,
|
||||
Net,
|
||||
Process,
|
||||
Require,
|
||||
Stdio,
|
||||
Task,
|
||||
TopLevel,
|
||||
}
|
||||
|
@ -28,11 +28,11 @@ pub enum LuneGlobal {
|
|||
impl LuneGlobal {
|
||||
pub fn get_all() -> Vec<Self> {
|
||||
vec![
|
||||
Self::Console,
|
||||
Self::Fs,
|
||||
Self::Net,
|
||||
Self::Process,
|
||||
Self::Require,
|
||||
Self::Stdio,
|
||||
Self::Task,
|
||||
Self::TopLevel,
|
||||
]
|
||||
|
@ -85,11 +85,11 @@ impl Lune {
|
|||
// Add in wanted lune globals
|
||||
for global in &self.globals {
|
||||
match &global {
|
||||
LuneGlobal::Console => create_console(&lua)?,
|
||||
LuneGlobal::Fs => create_fs(&lua)?,
|
||||
LuneGlobal::Net => create_net(&lua)?,
|
||||
LuneGlobal::Process => create_process(&lua, self.args.clone())?,
|
||||
LuneGlobal::Require => create_require(&lua)?,
|
||||
LuneGlobal::Stdio => create_stdio(&lua)?,
|
||||
LuneGlobal::Task => create_task(&lua)?,
|
||||
LuneGlobal::TopLevel => create_top_level(&lua)?,
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ impl Lune {
|
|||
LuneMessage::LuaError(e) => {
|
||||
eprintln!("{}", pretty_format_luau_error(&e));
|
||||
got_error = true;
|
||||
task_count += 1;
|
||||
task_count -= 1;
|
||||
}
|
||||
};
|
||||
// If there are no tasks left running, it is now
|
||||
|
@ -180,6 +180,8 @@ mod tests {
|
|||
use std::{env::set_current_dir, path::PathBuf, process::ExitCode};
|
||||
|
||||
use anyhow::Result;
|
||||
use console::set_colors_enabled;
|
||||
use console::set_colors_enabled_stderr;
|
||||
use tokio::fs::read_to_string;
|
||||
|
||||
use crate::Lune;
|
||||
|
@ -191,6 +193,10 @@ mod tests {
|
|||
$(
|
||||
#[tokio::test]
|
||||
async fn $name() -> Result<ExitCode> {
|
||||
// Disable styling for stdout and stderr since
|
||||
// some tests rely on output not being styled
|
||||
set_colors_enabled(false);
|
||||
set_colors_enabled_stderr(false);
|
||||
// NOTE: This path is relative to the lib
|
||||
// package, not the cwd or workspace root,
|
||||
// so we need to cd to the repo root first
|
||||
|
@ -218,8 +224,6 @@ mod tests {
|
|||
}
|
||||
|
||||
run_tests! {
|
||||
console_format: "console/format",
|
||||
console_set_style: "console/set_style",
|
||||
fs_files: "fs/files",
|
||||
fs_dirs: "fs/dirs",
|
||||
net_request_codes: "net/request/codes",
|
||||
|
@ -238,6 +242,11 @@ mod tests {
|
|||
require_nested: "require/tests/nested",
|
||||
require_parents: "require/tests/parents",
|
||||
require_siblings: "require/tests/siblings",
|
||||
stdio_format: "stdio/format",
|
||||
stdio_color: "stdio/color",
|
||||
stdio_style: "stdio/style",
|
||||
stdio_write: "stdio/write",
|
||||
stdio_ewrite: "stdio/ewrite",
|
||||
task_cancel: "task/cancel",
|
||||
task_defer: "task/defer",
|
||||
task_delay: "task/delay",
|
||||
|
|
|
@ -1,32 +1,28 @@
|
|||
use std::{
|
||||
fmt::Write as _,
|
||||
io::{self, Write as _},
|
||||
};
|
||||
use std::fmt::Write;
|
||||
|
||||
use console::{style, Style};
|
||||
use lazy_static::lazy_static;
|
||||
use mlua::prelude::*;
|
||||
|
||||
const MAX_FORMAT_DEPTH: usize = 4;
|
||||
|
||||
const INDENT: &str = " ";
|
||||
|
||||
// TODO: Use some crate for this instead
|
||||
pub const STYLE_RESET_STR: &str = "\x1b[0m";
|
||||
|
||||
pub const COLOR_RESET: &str = if cfg!(test) { "" } else { "\x1B[0m" };
|
||||
pub const COLOR_BLACK: &str = if cfg!(test) { "" } else { "\x1B[30m" };
|
||||
pub const COLOR_RED: &str = if cfg!(test) { "" } else { "\x1B[31m" };
|
||||
pub const COLOR_GREEN: &str = if cfg!(test) { "" } else { "\x1B[32m" };
|
||||
pub const COLOR_YELLOW: &str = if cfg!(test) { "" } else { "\x1B[33m" };
|
||||
pub const COLOR_BLUE: &str = if cfg!(test) { "" } else { "\x1B[34m" };
|
||||
pub const COLOR_PURPLE: &str = if cfg!(test) { "" } else { "\x1B[35m" };
|
||||
pub const COLOR_CYAN: &str = if cfg!(test) { "" } else { "\x1B[36m" };
|
||||
pub const COLOR_WHITE: &str = if cfg!(test) { "" } else { "\x1B[37m" };
|
||||
|
||||
pub const STYLE_RESET: &str = if cfg!(test) { "" } else { "\x1B[22m" };
|
||||
pub const STYLE_BOLD: &str = if cfg!(test) { "" } else { "\x1B[1m" };
|
||||
pub const STYLE_DIM: &str = if cfg!(test) { "" } else { "\x1B[2m" };
|
||||
|
||||
pub fn flush_stdout() -> LuaResult<()> {
|
||||
io::stdout().flush().map_err(LuaError::external)
|
||||
lazy_static! {
|
||||
// Colors
|
||||
pub static ref COLOR_BLACK: Style = Style::new().black();
|
||||
pub static ref COLOR_RED: Style = Style::new().red();
|
||||
pub static ref COLOR_GREEN: Style = Style::new().green();
|
||||
pub static ref COLOR_YELLOW: Style = Style::new().yellow();
|
||||
pub static ref COLOR_BLUE: Style = Style::new().blue();
|
||||
pub static ref COLOR_PURPLE: Style = Style::new().magenta();
|
||||
pub static ref COLOR_CYAN: Style = Style::new().cyan();
|
||||
pub static ref COLOR_WHITE: Style = Style::new().white();
|
||||
// Styles
|
||||
pub static ref STYLE_BOLD: Style = Style::new().bold();
|
||||
pub static ref STYLE_DIM: Style = Style::new().dim();
|
||||
}
|
||||
|
||||
fn can_be_plain_lua_table_key(s: &LuaString) -> bool {
|
||||
|
@ -41,74 +37,68 @@ fn can_be_plain_lua_table_key(s: &LuaString) -> bool {
|
|||
|
||||
pub fn format_label<S: AsRef<str>>(s: S) -> String {
|
||||
format!(
|
||||
"{}[{}{}{}{}]{} ",
|
||||
STYLE_BOLD,
|
||||
"{}{}{} ",
|
||||
style("[").bold(),
|
||||
match s.as_ref().to_ascii_lowercase().as_str() {
|
||||
"info" => COLOR_BLUE,
|
||||
"warn" => COLOR_YELLOW,
|
||||
"error" => COLOR_RED,
|
||||
_ => COLOR_WHITE,
|
||||
"info" => style("INFO").blue(),
|
||||
"warn" => style("WARN").yellow(),
|
||||
"error" => style("ERROR").red(),
|
||||
_ => style(""),
|
||||
},
|
||||
s.as_ref().to_ascii_uppercase(),
|
||||
COLOR_RESET,
|
||||
STYLE_BOLD,
|
||||
STYLE_RESET
|
||||
style("]").bold()
|
||||
)
|
||||
}
|
||||
|
||||
pub fn print_label<S: AsRef<str>>(s: S) -> LuaResult<()> {
|
||||
print!("{}", format_label(s));
|
||||
flush_stdout()?;
|
||||
Ok(())
|
||||
pub fn format_style(style: Option<&'static Style>) -> String {
|
||||
if cfg!(test) {
|
||||
"".to_string()
|
||||
} else if let Some(style) = style {
|
||||
// HACK: We have no direct way of referencing the ansi color code
|
||||
// of the style that console::Style provides, and we also know for
|
||||
// sure that styles always include the reset sequence at the end
|
||||
style
|
||||
.apply_to("")
|
||||
.to_string()
|
||||
.strip_suffix(STYLE_RESET_STR)
|
||||
.unwrap()
|
||||
.to_string()
|
||||
} else {
|
||||
STYLE_RESET_STR.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_style<S: AsRef<str>>(s: S) -> LuaResult<()> {
|
||||
print!(
|
||||
"{}",
|
||||
match s.as_ref() {
|
||||
"reset" => STYLE_RESET,
|
||||
"bold" => STYLE_BOLD,
|
||||
"dim" => STYLE_DIM,
|
||||
_ => {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"The style '{}' is not a valid style name",
|
||||
s.as_ref()
|
||||
)));
|
||||
}
|
||||
}
|
||||
);
|
||||
flush_stdout()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn print_reset() -> LuaResult<()> {
|
||||
print_style("reset")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn print_color<S: AsRef<str>>(s: S) -> LuaResult<()> {
|
||||
print!(
|
||||
"{}",
|
||||
match s.as_ref() {
|
||||
"reset" => COLOR_RESET,
|
||||
"black" => COLOR_BLACK,
|
||||
"red" => COLOR_RED,
|
||||
"green" => COLOR_GREEN,
|
||||
"yellow" => COLOR_YELLOW,
|
||||
"blue" => COLOR_BLUE,
|
||||
"purple" => COLOR_PURPLE,
|
||||
"cyan" => COLOR_CYAN,
|
||||
"white" => COLOR_WHITE,
|
||||
pub fn style_from_color_str<S: AsRef<str>>(s: S) -> LuaResult<Option<&'static Style>> {
|
||||
Ok(match s.as_ref() {
|
||||
"reset" => None,
|
||||
"black" => Some(&COLOR_BLACK),
|
||||
"red" => Some(&COLOR_RED),
|
||||
"green" => Some(&COLOR_GREEN),
|
||||
"yellow" => Some(&COLOR_YELLOW),
|
||||
"blue" => Some(&COLOR_BLUE),
|
||||
"purple" => Some(&COLOR_PURPLE),
|
||||
"cyan" => Some(&COLOR_CYAN),
|
||||
"white" => Some(&COLOR_WHITE),
|
||||
_ => {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"The color '{}' is not a valid color name",
|
||||
s.as_ref()
|
||||
)));
|
||||
}
|
||||
})
|
||||
}
|
||||
);
|
||||
flush_stdout()?;
|
||||
Ok(())
|
||||
|
||||
pub fn style_from_style_str<S: AsRef<str>>(s: S) -> LuaResult<Option<&'static Style>> {
|
||||
Ok(match s.as_ref() {
|
||||
"reset" => None,
|
||||
"bold" => Some(&STYLE_BOLD),
|
||||
"dim" => Some(&STYLE_DIM),
|
||||
_ => {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"The style '{}' is not a valid style name",
|
||||
s.as_ref()
|
||||
)));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn pretty_format_value(
|
||||
|
@ -119,65 +109,66 @@ pub fn pretty_format_value(
|
|||
// TODO: Handle tables with cyclic references
|
||||
match &value {
|
||||
LuaValue::Nil => write!(buffer, "nil")?,
|
||||
LuaValue::Boolean(true) => write!(buffer, "{COLOR_YELLOW}true{COLOR_RESET}")?,
|
||||
LuaValue::Boolean(false) => write!(buffer, "{COLOR_YELLOW}false{COLOR_RESET}")?,
|
||||
LuaValue::Number(n) => write!(buffer, "{COLOR_CYAN}{n}{COLOR_RESET}")?,
|
||||
LuaValue::Integer(i) => write!(buffer, "{COLOR_CYAN}{i}{COLOR_RESET}")?,
|
||||
LuaValue::Boolean(true) => write!(buffer, "{}", COLOR_YELLOW.apply_to("true"))?,
|
||||
LuaValue::Boolean(false) => write!(buffer, "{}", COLOR_YELLOW.apply_to("false"))?,
|
||||
LuaValue::Number(n) => write!(buffer, "{}", COLOR_CYAN.apply_to(format!("{n}")))?,
|
||||
LuaValue::Integer(i) => write!(buffer, "{}", COLOR_CYAN.apply_to(format!("{i}")))?,
|
||||
LuaValue::String(s) => write!(
|
||||
buffer,
|
||||
"{}\"{}\"{}",
|
||||
COLOR_GREEN,
|
||||
"\"{}\"",
|
||||
COLOR_GREEN.apply_to(
|
||||
s.to_string_lossy()
|
||||
.replace('"', r#"\""#)
|
||||
.replace('\r', r#"\r"#)
|
||||
.replace('\n', r#"\n"#),
|
||||
COLOR_RESET
|
||||
.replace('\n', r#"\n"#)
|
||||
)
|
||||
)?,
|
||||
LuaValue::Table(ref tab) => {
|
||||
if depth >= MAX_FORMAT_DEPTH {
|
||||
write!(buffer, "{STYLE_DIM}{{ ... }}{STYLE_RESET}")?;
|
||||
write!(buffer, "{}", STYLE_DIM.apply_to("{ ... }"))?;
|
||||
} else {
|
||||
let mut is_empty = false;
|
||||
let depth_indent = INDENT.repeat(depth);
|
||||
write!(buffer, "{STYLE_DIM}{{{STYLE_RESET}")?;
|
||||
write!(buffer, "{}", STYLE_DIM.apply_to("{"))?;
|
||||
for pair in tab.clone().pairs::<LuaValue, LuaValue>() {
|
||||
let (key, value) = pair.unwrap();
|
||||
match &key {
|
||||
LuaValue::String(s) if can_be_plain_lua_table_key(s) => write!(
|
||||
buffer,
|
||||
"\n{}{}{} {}={} ",
|
||||
"\n{}{}{} {} ",
|
||||
depth_indent,
|
||||
INDENT,
|
||||
s.to_string_lossy(),
|
||||
STYLE_DIM,
|
||||
STYLE_RESET
|
||||
STYLE_DIM.apply_to("=")
|
||||
)?,
|
||||
_ => {
|
||||
write!(buffer, "\n{depth_indent}{INDENT}[")?;
|
||||
pretty_format_value(buffer, &key, depth)?;
|
||||
write!(buffer, "] {STYLE_DIM}={STYLE_RESET} ")?;
|
||||
write!(buffer, "] {} ", STYLE_DIM.apply_to("="))?;
|
||||
}
|
||||
}
|
||||
pretty_format_value(buffer, &value, depth + 1)?;
|
||||
write!(buffer, "{STYLE_DIM},{STYLE_RESET}")?;
|
||||
write!(buffer, "{}", STYLE_DIM.apply_to(","))?;
|
||||
is_empty = false;
|
||||
}
|
||||
if is_empty {
|
||||
write!(buffer, " {STYLE_DIM}}}{STYLE_RESET}")?;
|
||||
write!(buffer, "{}", STYLE_DIM.apply_to(" }"))?;
|
||||
} else {
|
||||
write!(buffer, "\n{depth_indent}{STYLE_DIM}}}{STYLE_RESET}")?;
|
||||
write!(buffer, "\n{}", STYLE_DIM.apply_to("}"))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
LuaValue::Vector(x, y, z) => {
|
||||
write!(buffer, "{COLOR_PURPLE}<vector({x}, {y}, {z})>{COLOR_RESET}",)?
|
||||
}
|
||||
LuaValue::Thread(_) => write!(buffer, "{COLOR_PURPLE}<thread>{COLOR_RESET}")?,
|
||||
LuaValue::Function(_) => write!(buffer, "{COLOR_PURPLE}<function>{COLOR_RESET}")?,
|
||||
LuaValue::Vector(x, y, z) => write!(
|
||||
buffer,
|
||||
"{}",
|
||||
COLOR_PURPLE.apply_to(format!("<vector({x}, {y}, {z})>"))
|
||||
)?,
|
||||
LuaValue::Thread(_) => write!(buffer, "{}", COLOR_PURPLE.apply_to("<thread>"))?,
|
||||
LuaValue::Function(_) => write!(buffer, "{}", COLOR_PURPLE.apply_to("<function>"))?,
|
||||
LuaValue::UserData(_) | LuaValue::LightUserData(_) => {
|
||||
write!(buffer, "{COLOR_PURPLE}<userdata>{COLOR_RESET}")?
|
||||
write!(buffer, "{}", COLOR_PURPLE.apply_to("<userdata>"))?
|
||||
}
|
||||
_ => write!(buffer, "?")?,
|
||||
_ => write!(buffer, "{}", STYLE_DIM.apply_to("?"))?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -200,8 +191,8 @@ pub fn pretty_format_multi_value(multi: &LuaMultiValue) -> LuaResult<String> {
|
|||
}
|
||||
|
||||
pub fn pretty_format_luau_error(e: &LuaError) -> String {
|
||||
let stack_begin = format!("[{}Stack Begin{}]", COLOR_BLUE, COLOR_RESET);
|
||||
let stack_end = format!("[{}Stack End{}]", COLOR_BLUE, COLOR_RESET);
|
||||
let stack_begin = format!("[{}]", COLOR_BLUE.apply_to("Stack Begin"));
|
||||
let stack_end = format!("[{}]", COLOR_BLUE.apply_to("Stack End"));
|
||||
let err_string = match e {
|
||||
LuaError::RuntimeError(e) => {
|
||||
// Remove unnecessary prefix
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
local STYLES_VALID = { "bold", "dim" }
|
||||
local STYLES_INVALID = { "", "*bold*", "dimm", "megabright", "cheerful", "sad", " " }
|
||||
|
||||
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 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
|
||||
end
|
15
tests/stdio/color.luau
Normal file
15
tests/stdio/color.luau
Normal file
|
@ -0,0 +1,15 @@
|
|||
local COLORS_VALID =
|
||||
{ "reset", "black", "red", "green", "yellow", "blue", "purple", "cyan", "white" }
|
||||
local COLORS_INVALID = { "", "gray", "grass", "red?", "super red", " ", "none" }
|
||||
|
||||
for _, color in COLORS_VALID do
|
||||
stdio.color(color :: any)
|
||||
stdio.color("reset")
|
||||
end
|
||||
|
||||
for _, color in COLORS_INVALID do
|
||||
if pcall(stdio.color, color :: any) then
|
||||
stdio.color("reset")
|
||||
error(string.format("Setting color should have failed for color '%s' but succeeded", color))
|
||||
end
|
||||
end
|
3
tests/stdio/ewrite.luau
Normal file
3
tests/stdio/ewrite.luau
Normal file
|
@ -0,0 +1,3 @@
|
|||
stdio.ewrite("Hello, stderr!")
|
||||
|
||||
process.exit(0)
|
|
@ -1,10 +1,10 @@
|
|||
assert(
|
||||
console.format("Hello", "world", "!") == "Hello world !",
|
||||
stdio.format("Hello", "world", "!") == "Hello world !",
|
||||
"Format should add a single space between arguments"
|
||||
)
|
||||
|
||||
assert(
|
||||
console.format({ Hello = "World" }) == '{\n Hello = "World",\n}',
|
||||
stdio.format({ Hello = "World" }) == '{\n Hello = "World",\n}',
|
||||
"Format should print out proper tables"
|
||||
)
|
||||
|
||||
|
@ -21,6 +21,6 @@ local nested = {
|
|||
}
|
||||
|
||||
assert(
|
||||
string.find(console.format(nested), "Nesting = { ... }", 1, true) ~= nil,
|
||||
string.find(stdio.format(nested), "Nesting = { ... }", 1, true) ~= nil,
|
||||
"Format should print 4 levels of nested tables before cutting off"
|
||||
)
|
14
tests/stdio/style.luau
Normal file
14
tests/stdio/style.luau
Normal file
|
@ -0,0 +1,14 @@
|
|||
local STYLES_VALID = { "reset", "bold", "dim" }
|
||||
local STYLES_INVALID = { "", "*bold*", "dimm", "megabright", "cheerful", "sad", " " }
|
||||
|
||||
for _, style in STYLES_VALID do
|
||||
stdio.style(style :: any)
|
||||
stdio.style("reset")
|
||||
end
|
||||
|
||||
for _, style in STYLES_INVALID do
|
||||
if pcall(stdio.style, style :: any) then
|
||||
stdio.style("reset")
|
||||
error(string.format("Setting style should have failed for style '%s' but succeeded", style))
|
||||
end
|
||||
end
|
3
tests/stdio/write.luau
Normal file
3
tests/stdio/write.luau
Normal file
|
@ -0,0 +1,3 @@
|
|||
stdio.write("Hello, stdout!")
|
||||
|
||||
process.exit(0)
|
|
@ -5,7 +5,7 @@ return function(index: number, type: string, value: any)
|
|||
"Expected argument #%d to be of type %s, got %s",
|
||||
index,
|
||||
type,
|
||||
console.format(value)
|
||||
stdio.format(value)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue