diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/bin/jvn.rs | 50 | ||||
| -rw-r--r-- | src/cmds/arg/single_file.rs | 2 | ||||
| -rw-r--r-- | src/cmds/cmd/hexdump.rs | 21 | ||||
| -rw-r--r-- | src/systems/cmd/cmd_system.rs | 3 |
4 files changed, 69 insertions, 7 deletions
diff --git a/src/bin/jvn.rs b/src/bin/jvn.rs index 062eab8..fd01431 100644 --- a/src/bin/jvn.rs +++ b/src/bin/jvn.rs @@ -1,4 +1,8 @@ -use std::{ops::Deref, process::exit}; +use std::{ + ops::Deref, + path::{Path, PathBuf}, + process::exit, +}; use cli_utils::legacy::{display::md, env::current_locales, levenshtein_distance}; use just_enough_vcs_cli::{ @@ -23,6 +27,7 @@ use just_progress::{ }; use log::{LevelFilter, error, info, trace, warn}; use rust_i18n::{set_locale, t}; +use tokio::io::AsyncReadExt; rust_i18n::i18n!("resources/locales/jvn", fallback = "en"); @@ -115,6 +120,18 @@ async fn main() { info!("{}", t!("verbose.user_input", command = args.join(" "))); + // Read pipe inpuit + let (stdin_path, stdin_data) = match read_all_from_stdin().await { + Ok((path, data)) => { + if data.is_empty() { + (None, None) + } else { + (path, Some(data)) + } + } + Err(_) => (None, None), + }; + // Build process future let args_clone = args.clone(); let process_future = jv_cmd_process( @@ -124,6 +141,8 @@ async fn main() { confirmed, args: args.clone(), lang, + stdin_path, + stdin_data, }, renderer_override, ); @@ -198,6 +217,35 @@ async fn main() { } } +/// Read path or raw information from standard input +async fn read_all_from_stdin() -> tokio::io::Result<(Option<PathBuf>, Vec<u8>)> { + if atty::is(atty::Stream::Stdin) { + return Ok((None, Vec::new())); + } + + let mut stdin = tokio::io::stdin(); + let mut buffer = Vec::new(); + + stdin.read_to_end(&mut buffer).await?; + + if buffer.is_empty() { + return Ok((None, Vec::new())); + } + + let path = if let Ok(input_str) = String::from_utf8(buffer.clone()) { + let trimmed = input_str.trim(); + if !trimmed.is_empty() && Path::new(trimmed).exists() { + Some(PathBuf::from(trimmed)) + } else { + None + } + } else { + None + }; + + Ok((path, buffer)) +} + fn handle_no_matching_command_error(args: Vec<String>) { let mut similar_nodes: Vec<String> = Vec::new(); for node in jv_cmd_nodes() { diff --git a/src/cmds/arg/single_file.rs b/src/cmds/arg/single_file.rs index 4ed9715..42927fc 100644 --- a/src/cmds/arg/single_file.rs +++ b/src/cmds/arg/single_file.rs @@ -4,5 +4,5 @@ use clap::Parser; #[derive(Parser, Debug)] pub struct JVSingleFileArgument { - pub file: PathBuf, + pub file: Option<PathBuf>, } diff --git a/src/cmds/cmd/hexdump.rs b/src/cmds/cmd/hexdump.rs index 346fffe..34df45c 100644 --- a/src/cmds/cmd/hexdump.rs +++ b/src/cmds/cmd/hexdump.rs @@ -1,9 +1,12 @@ use crate::{ cmd_output, cmds::{ - arg::single_file::JVSingleFileArgument, collect::single_file::JVSingleFileCollect, - r#in::empty::JVEmptyInput, out::hex::JVHexOutput, + arg::single_file::JVSingleFileArgument, + collect::single_file::JVSingleFileCollect, + r#in::empty::JVEmptyInput, + out::{hex::JVHexOutput, none::JVNoneOutput}, }, + early_cmd_output, systems::{ cmd::{ cmd_system::{AnyOutput, JVCommandContext}, @@ -30,9 +33,17 @@ async fn prepare(_args: &Arg, _ctx: &JVCommandContext) -> Result<In, CmdPrepareE Ok(In {}) } -async fn collect(args: &Arg, _ctx: &JVCommandContext) -> Result<Collect, CmdPrepareError> { - let file = &args.file; - let data = fs::read(file).await?; +async fn collect(args: &Arg, ctx: &JVCommandContext) -> Result<Collect, CmdPrepareError> { + let data = if let Some(ref stdin_path) = ctx.stdin_path { + fs::read(stdin_path).await? + } else if let Some(ref stdin_data) = ctx.stdin_data { + stdin_data.clone() + } else if let Some(path) = &args.file { + fs::read(&path).await? + } else { + // No path input, exit early + return early_cmd_output!(JVNoneOutput => JVNoneOutput); + }; Ok(Collect { data }) } diff --git a/src/systems/cmd/cmd_system.rs b/src/systems/cmd/cmd_system.rs index 43d5187..a89842b 100644 --- a/src/systems/cmd/cmd_system.rs +++ b/src/systems/cmd/cmd_system.rs @@ -12,6 +12,7 @@ use std::{ any::{TypeId, type_name}, collections::HashMap, future::Future, + path::PathBuf, }; pub type AnyOutput = (Box<dyn std::any::Any + Send + 'static>, TypeId); @@ -21,6 +22,8 @@ pub struct JVCommandContext { pub confirmed: bool, pub args: Vec<String>, pub lang: String, + pub stdin_path: Option<PathBuf>, + pub stdin_data: Option<Vec<u8>>, } pub trait JVCommand<Argument, Input, Collect> |
