diff options
author | Jesse Luehrs <doy@tozt.net> | 2022-01-08 08:06:05 -0500 |
---|---|---|
committer | Jesse Luehrs <doy@tozt.net> | 2022-01-08 08:06:05 -0500 |
commit | 27a911d8e22518503cb926d3c545cdde0c582a2e (patch) | |
tree | 96e8ec35f362468575df94eb6e337977db12fd36 /src | |
parent | 778b1f751a036fc025026be883e336074bde7d9b (diff) | |
download | nbsh-27a911d8e22518503cb926d3c545cdde0c582a2e.tar.gz nbsh-27a911d8e22518503cb926d3c545cdde0c582a2e.zip |
implement read builtin
Diffstat (limited to 'src')
-rw-r--r-- | src/pipeline/builtins/command.rs | 15 | ||||
-rw-r--r-- | src/pipeline/builtins/mod.rs | 34 |
2 files changed, 43 insertions, 6 deletions
diff --git a/src/pipeline/builtins/command.rs b/src/pipeline/builtins/command.rs index 8119a55..2e6b4af 100644 --- a/src/pipeline/builtins/command.rs +++ b/src/pipeline/builtins/command.rs @@ -1,5 +1,7 @@ use crate::pipeline::prelude::*; +use async_std::io::prelude::BufReadExt as _; + pub struct Command { exe: crate::parse::Exe, f: super::Builtin, @@ -196,16 +198,17 @@ impl Io { } } - pub async fn read_stdin(&self, buf: &mut [u8]) -> anyhow::Result<usize> { + pub async fn read_line_stdin(&self) -> anyhow::Result<String> { + let mut buf = String::new(); if let Some(fh) = self.stdin() { if let File::In(fh) = &mut *fh.lock_arc().await { - Ok(fh.read(buf).await?) - } else { - Ok(0) + fh.read_line(&mut buf).await?; } - } else { - Ok(0) } + if buf.ends_with('\n') { + buf.truncate(buf.len() - 1); + } + Ok(buf) } pub async fn write_stdout(&self, buf: &[u8]) -> anyhow::Result<()> { diff --git a/src/pipeline/builtins/mod.rs b/src/pipeline/builtins/mod.rs index 9670c0f..4e9cf2a 100644 --- a/src/pipeline/builtins/mod.rs +++ b/src/pipeline/builtins/mod.rs @@ -20,6 +20,7 @@ static BUILTINS: once_cell::sync::Lazy< builtins.insert("setenv", &setenv); builtins.insert("unsetenv", &unsetenv); builtins.insert("echo", &echo); + builtins.insert("read", &read); builtins.insert("and", &and); builtins.insert("or", &or); builtins.insert("command", &command); @@ -217,6 +218,39 @@ fn echo( })) } +#[allow(clippy::unnecessary_wraps)] +fn read( + exe: crate::parse::Exe, + env: &Env, + cfg: command::Cfg, +) -> anyhow::Result<command::Child> { + async fn async_read( + exe: crate::parse::Exe, + _env: &Env, + cfg: command::Cfg, + ) -> std::process::ExitStatus { + let var = if let Some(var) = exe.args().get(0).map(String::as_str) { + var + } else { + bail!(cfg, exe, "usage: read var"); + }; + + let val = match cfg.io().read_line_stdin().await { + Ok(line) => line, + Err(e) => { + bail!(cfg, exe, e); + } + }; + + std::env::set_var(var, val); + async_std::process::ExitStatus::from_raw(0) + } + + Ok(command::Child::new_fut(async move { + async_read(exe, env, cfg).await + })) +} + fn and( mut exe: crate::parse::Exe, env: &Env, |