logss 0.0.4

A simple command line tool that helps you visualize an input stream of text.
Documentation
use std::{
    io::{stdin, BufRead, BufReader, Error},
    process::{Command, Stdio},
    sync::{mpsc, mpsc::Sender},
    thread,
};

use anyhow::Result;

#[derive(Debug)]
pub struct StdinHandler {
    receiver: mpsc::Receiver<String>,
    pub sender: mpsc::Sender<String>,
}

impl Default for StdinHandler {
    fn default() -> Self {
        Self::new()
    }
}

impl StdinHandler {
    pub fn new() -> Self {
        let (sender, receiver) = mpsc::channel();
        Self { receiver, sender }
    }

    pub fn init(&self, cmd: Option<Vec<String>>) -> Result<()> {
        let sender = self.sender.clone();
        match cmd {
            Some(inner_cmd) => {
                let child = Command::new(&inner_cmd[0])
                    .args(&inner_cmd[1..])
                    .stderr(Stdio::null())
                    .stdout(Stdio::piped())
                    .spawn()?;

                let stdout = child
                    .stdout
                    .ok_or_else(|| Error::other("Failed to run command"))?;
                let reader = BufReader::new(stdout);
                read_lines_and_send(reader, sender);
            }
            // If no command set then we are being pipped
            None => {
                let stdin = stdin();
                let reader = BufReader::new(stdin);

                read_lines_and_send(reader, sender);
            }
        }

        Ok(())
    }

    pub fn recv(&self) -> Result<String, mpsc::RecvError> {
        self.receiver.recv()
    }

    pub fn try_recv(&self) -> Result<String, mpsc::TryRecvError> {
        self.receiver.try_recv()
    }
}

fn read_lines_and_send<R>(mut reader: R, sender: Sender<String>)
where
    R: BufRead + Send + 'static,
{
    let mut line = String::new();
    thread::spawn(move || loop {
        match reader.read_line(&mut line) {
            Ok(len) => {
                if len == 0 {
                    break;
                } else {
                    sender.send(line.clone()).ok();
                }
            }
            Err(e) => {
                sender.send(e.to_string()).ok();
                break;
            }
        }
        line.clear();
    });
}