use std::io::BufRead;
use std::sync::Arc;
use crossbeam_channel::{Sender, TrySendError};
use regex::Regex;
use crate::field::FieldRange;
use crate::SkimItem;
use super::item::DefaultSkimItem;
#[derive(Clone)]
pub enum SendRawOrBuild<'a> {
Raw,
Build(BuildOptions<'a>),
}
#[derive(Clone)]
pub struct BuildOptions<'a> {
pub ansi_enabled: bool,
pub trans_fields: &'a [FieldRange],
pub matching_fields: &'a [FieldRange],
pub delimiter: &'a Regex,
}
#[allow(unused_assignments)]
pub fn ingest_loop(
mut source: Box<dyn BufRead + Send>,
line_ending: u8,
tx_item: Sender<Arc<dyn SkimItem>>,
opts: SendRawOrBuild,
) {
let mut bytes_buffer = Vec::with_capacity(65_536);
loop {
bytes_buffer = if let Ok(res) = source.fill_buf() {
res.to_vec()
} else {
break;
};
source.consume(bytes_buffer.len());
let _ = source.read_until(line_ending, &mut bytes_buffer);
if bytes_buffer.is_empty() {
break;
}
std::str::from_utf8(&bytes_buffer)
.expect("Could not convert bytes to UTF8.")
.split(['\n', line_ending as char])
.map(|line| {
if line.ends_with("\r\n") {
return line.trim_end_matches("\r\n");
}
if line.ends_with('\r') {
return line.trim_end_matches('\r');
}
line
})
.for_each(|line| {
if send(line, &opts, &tx_item).is_err() {
if let Err(err) = send(line, &opts, &tx_item) {
eprintln!("Error: {}", err);
std::process::exit(1)
}
}
})
}
}
fn send(
line: &str,
opts: &SendRawOrBuild,
tx_item: &Sender<Arc<dyn SkimItem>>,
) -> Result<(), TrySendError<Arc<dyn SkimItem>>> {
match opts {
SendRawOrBuild::Build(opts) => {
let item = DefaultSkimItem::new(
line,
opts.ansi_enabled,
opts.trans_fields,
opts.matching_fields,
opts.delimiter,
);
tx_item.try_send(Arc::new(item))
}
SendRawOrBuild::Raw => {
let boxed: Box<str> = line.into();
tx_item.try_send(Arc::new(boxed))
}
}
}