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"
dependencies = [
"async-io",
"async-lock",
"blocking",
"dialoguer",
"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" }
async-io = "2.4"
async-lock = "3.4"
blocking = "1.6"
dialoguer = "0.11"
futures-lite = "2.6"

View file

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

View file

@ -1,13 +1,4 @@
export type Color =
"reset"
| "black"
| "red"
| "green"
| "yellow"
| "blue"
| "purple"
| "cyan"
| "white"
export type Color = "reset" | "black" | "red" | "green" | "yellow" | "blue" | "purple" | "cyan" | "white"
export type Style = "reset" | "bold" | "dim"
type PromptFn = (
@ -59,6 +50,9 @@ end
stdio.write("All on the same line")
stdio.ewrite("\nAnd some error text, too")
-- Reading a single line from stdin
local line = stdio.readLine()
-- Reading the entire input from stdin
local input = stdio.readToEnd()
```
@ -146,6 +140,20 @@ function stdio.write(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
@tag must_use