From a618a7a770d59500b75f6b71a1ef9e8374147ce0 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Mon, 3 Apr 2023 13:47:00 +0200 Subject: [PATCH] Add ability to take glob patterns from stdin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit as requested in issue #51 This adds a new (hidden) flag `--stdin` to indicate that `et` should take input from stdin. Since the naming convention is to use `-` for this, we replace the args `-` with `--stdin` before we hand them over to Clap. Example usage: ```shell $ touch hello.rs helLo.rs HELlo.rs $ fd -e rs '^hel[lL]o' | et - erdtree 0 B ├─ hello.rs 0 B └─ helLo.rs ``` --- src/main.rs | 17 +++++++++++++++-- src/render/context/mod.rs | 13 +++++++++++-- src/utils.rs | 18 ++++++++++++++++++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6e93c972..a395b16e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,7 +20,10 @@ )] use clap::CommandFactory; use render::{context::Context, tree::Tree}; -use std::{io::stdout, process::ExitCode}; +use std::{ + io::{stdout, BufRead}, + process::ExitCode, +}; /// Filesystem operations. mod fs; @@ -44,7 +47,17 @@ fn main() -> ExitCode { } fn run() -> Result<(), Box> { - let ctx = Context::init()?; + let mut ctx = Context::init()?; + + if ctx.stdin { + let mut stdin_lines = std::io::stdin() + .lock() + .lines() + .filter_map(|s| s.ok()) + .filter(|l| !l.is_empty()) + .collect::>(); + ctx.glob.append(&mut stdin_lines); + } if let Some(shell) = ctx.completions { clap_complete::generate(shell, &mut Context::command(), "et", &mut stdout().lock()); diff --git a/src/render/context/mod.rs b/src/render/context/mod.rs index d118ffaa..42ce53ad 100644 --- a/src/render/context/mod.rs +++ b/src/render/context/mod.rs @@ -39,7 +39,7 @@ pub struct Context { /// Include or exclude files using glob patterns #[arg(short, long)] - glob: Vec, + pub glob: Vec, /// Include or exclude files using glob patterns; case insensitive #[arg(long)] @@ -128,13 +128,22 @@ pub struct Context { /// Don't read configuration file #[arg(long)] pub no_config: bool, + + /// Take input from Stdin + #[arg(long, hide = true)] + pub stdin: bool, } impl Context { /// Initializes [Context], optionally reading in the configuration file to override defaults. /// Arguments provided will take precedence over config. pub fn init() -> Result { - let user_args = Self::command().args_override_self(true).get_matches(); + let mut args: Vec<_> = std::env::args().collect(); + crate::utils::detect_stdin(&mut args); + + let user_args = Self::command() + .args_override_self(true) + .get_matches_from(args); let no_config = user_args.get_one("no_config").map_or(false, bool::clone); diff --git a/src/utils.rs b/src/utils.rs index 47f88214..593b0e61 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -25,3 +25,21 @@ where .filter(|item| set.insert(item.to_owned())) .collect::>() } + +/// Follow the naming convention and use "-" to specify a Standard Input. +/// Retain "-" from [`args`] and add "--stdin" if necessary. +pub fn detect_stdin(args: &mut Vec) { + let dash = String::from("-"); + let stdin_flag = String::from("--stdin"); + + let mut is_stdin = false; + args.retain(|e| { + if *e == dash { + is_stdin = true + }; + *e != dash + }); + if is_stdin && !args.contains(&stdin_flag) { + args.push(stdin_flag) + } +}