Implement readLine in lune-std-stdio

This commit is contained in:
Filip Tibell 2025-04-24 18:53:17 +02:00
parent c4374a0e18
commit 6b45f44d1f
No known key found for this signature in database
4 changed files with 43 additions and 23 deletions

1
Cargo.lock generated
View file

@ -1776,6 +1776,7 @@ name = "lune-std-stdio"
version = "0.1.2" version = "0.1.2"
dependencies = [ dependencies = [
"async-io", "async-io",
"async-lock",
"blocking", "blocking",
"dialoguer", "dialoguer",
"futures-lite", "futures-lite",

View file

@ -17,6 +17,7 @@ mlua = { version = "0.10.3", features = ["luau", "error-send"] }
mlua-luau-scheduler = { version = "0.0.2", path = "../mlua-luau-scheduler" } mlua-luau-scheduler = { version = "0.0.2", path = "../mlua-luau-scheduler" }
async-io = "2.4" async-io = "2.4"
async-lock = "3.4"
blocking = "1.6" blocking = "1.6"
dialoguer = "0.11" dialoguer = "0.11"
futures-lite = "2.6" futures-lite = "2.6"

View file

@ -1,12 +1,16 @@
#![allow(clippy::cargo_common_metadata)] #![allow(clippy::cargo_common_metadata)]
use std::io::{stderr, stdin, stdout}; use std::{
io::{stderr, stdin, stdout, Stdin},
sync::{Arc, LazyLock},
};
use mlua::prelude::*; use mlua::prelude::*;
use mlua_luau_scheduler::LuaSpawnExt; use mlua_luau_scheduler::LuaSpawnExt;
use async_lock::Mutex as AsyncMutex;
use blocking::Unblock; use blocking::Unblock;
use futures_lite::prelude::*; use futures_lite::{io::BufReader, prelude::*};
use lune_utils::{ use lune_utils::{
fmt::{pretty_format_multi_value, ValueFormatConfig}, fmt::{pretty_format_multi_value, ValueFormatConfig},
@ -23,6 +27,12 @@ const FORMAT_CONFIG: ValueFormatConfig = ValueFormatConfig::new()
.with_max_depth(4) .with_max_depth(4)
.with_colors_enabled(false); .with_colors_enabled(false);
static STDIN: LazyLock<Arc<AsyncMutex<BufReader<Unblock<Stdin>>>>> = LazyLock::new(|| {
let stdin = Unblock::new(stdin());
let reader = BufReader::new(stdin);
Arc::new(AsyncMutex::new(reader))
});
/** /**
Creates the `stdio` standard library module. Creates the `stdio` standard library module.
@ -37,6 +47,7 @@ pub fn module(lua: Lua) -> LuaResult<LuaTable> {
.with_function("format", stdio_format)? .with_function("format", stdio_format)?
.with_async_function("write", stdio_write)? .with_async_function("write", stdio_write)?
.with_async_function("ewrite", stdio_ewrite)? .with_async_function("ewrite", stdio_ewrite)?
.with_async_function("readLine", stdio_read_line)?
.with_async_function("readToEnd", stdio_read_to_end)? .with_async_function("readToEnd", stdio_read_to_end)?
.with_async_function("prompt", stdio_prompt)? .with_async_function("prompt", stdio_prompt)?
.build_readonly() .build_readonly()
@ -68,19 +79,18 @@ async fn stdio_ewrite(_: Lua, s: LuaString) -> LuaResult<()> {
Ok(()) Ok(())
} }
/* async fn stdio_read_line(lua: Lua, (): ()) -> LuaResult<LuaString> {
FUTURE: Figure out how to expose some kind of "readLine" function using a buffered reader. let mut string = String::new();
let mut handle = STDIN.lock_arc().await;
This is a bit tricky since we would want to be able to use **both** readLine and readToEnd handle.read_line(&mut string).await?;
in the same script, doing something like readLine, readLine, readToEnd from lua, and lua.create_string(&string)
having that capture the first two lines and then read the rest of the input. }
*/
async fn stdio_read_to_end(lua: Lua, (): ()) -> LuaResult<LuaString> { async fn stdio_read_to_end(lua: Lua, (): ()) -> LuaResult<LuaString> {
let mut input = Vec::new(); let mut buffer = Vec::new();
let mut stdin = Unblock::new(stdin()); let mut handle = STDIN.lock_arc().await;
stdin.read_to_end(&mut input).await?; handle.read_to_end(&mut buffer).await?;
lua.create_string(&input) lua.create_string(&buffer)
} }
async fn stdio_prompt(lua: Lua, options: PromptOptions) -> LuaResult<PromptResult> { async fn stdio_prompt(lua: Lua, options: PromptOptions) -> LuaResult<PromptResult> {

View file

@ -1,13 +1,4 @@
export type Color = export type Color = "reset" | "black" | "red" | "green" | "yellow" | "blue" | "purple" | "cyan" | "white"
"reset"
| "black"
| "red"
| "green"
| "yellow"
| "blue"
| "purple"
| "cyan"
| "white"
export type Style = "reset" | "bold" | "dim" export type Style = "reset" | "bold" | "dim"
type PromptFn = ( type PromptFn = (
@ -59,6 +50,9 @@ end
stdio.write("All on the same line") stdio.write("All on the same line")
stdio.ewrite("\nAnd some error text, too") stdio.ewrite("\nAnd some error text, too")
-- Reading a single line from stdin
local line = stdio.readLine()
-- Reading the entire input from stdin -- Reading the entire input from stdin
local input = stdio.readToEnd() local input = stdio.readToEnd()
``` ```
@ -146,6 +140,20 @@ function stdio.write(s: string) end
]=] ]=]
function stdio.ewrite(s: string) end function stdio.ewrite(s: string) end
--[=[
@within Stdio
@tag must_use
Reads a single line from stdin.
If stdin is closed, returns all input up until its closure.
@return The input from stdin
]=]
function stdio.readLine(): string
return nil :: any
end
--[=[ --[=[
@within Stdio @within Stdio
@tag must_use @tag must_use