Documentation
use crossterm::cursor::MoveToColumn;
use crossterm::execute;
use crossterm::style::Print;
use std::ffi::c_int;
use std::io::Write;

struct RawStdout {
    fd: c_int,
}

impl RawStdout {
    fn next_line(&mut self) -> Result<(), std::io::Error> {
        execute!(self, Print('\n'), MoveToColumn(0))
    }
}

impl Write for RawStdout {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        let n = unsafe { libc::write(self.fd, buf.as_ptr() as _, buf.len() as _) };

        if n > 0 {
            Ok(n as usize)
        } else {
            Err(std::io::Error::last_os_error())
        }
    }

    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}

const BUFFER_SIZE: usize = 4096;

const STDOUT_FILENO: c_int = 1;

pub fn handle_standard_output() -> std::io::Result<()> {
    let mut pipe = [0; 2];

    let stdout_bak = unsafe { libc::dup(STDOUT_FILENO) };

    let mut buf = [b'\0'; BUFFER_SIZE];
    unsafe {
        libc::pipe(pipe.as_mut_ptr());

        let stat = libc::dup2(pipe[1], STDOUT_FILENO);

        if stat == -1 {
            return Err(std::io::Error::last_os_error());
        }

        let mut stdout_fd = RawStdout { fd: stdout_bak };

        loop {
            let size = libc::read(pipe[0], buf.as_mut_ptr() as _, BUFFER_SIZE as _);

            if size == -1 {
                eprintln!("Error: {}", std::io::Error::last_os_error());
                break;
            }

            if size == 1 && buf[0] == b'\n' {
                stdout_fd.next_line()?;
                continue;
            }

            let split: Vec<&[u8]> = buf[..size as usize].split(|&b| b == b'\n').collect();
            let mut split = split.into_iter();

            if split.len() == 1 {
                let slice = split.next().unwrap();

                if slice.is_empty() {
                    stdout_fd.next_line()?;
                }

                stdout_fd.write_all(slice)?;
                continue;
            }

            let last = split.len().saturating_sub(1);
            for (i, slice) in split.enumerate() {
                if i == last {
                    if !slice.is_empty() {
                        stdout_fd.write_all(slice)?;
                    }

                    continue;
                }

                if slice.is_empty() {
                    stdout_fd.next_line()?;
                    continue;
                }

                stdout_fd.write_all(slice)?;
                stdout_fd.next_line()?;
            }
        }

        libc::dup2(stdout_bak, STDOUT_FILENO);
    }

    Ok(())
}