mirror of
https://github.com/lotabout/skim.git
synced 2026-09-10 07:16:23 -04:00
fix #300: move reader related options to default reader
This commit is contained in:
parent
44c61d64f9
commit
6876ef469d
19
examples/nth.rs
Normal file
19
examples/nth.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
extern crate skim;
|
||||
use skim::prelude::*;
|
||||
use std::io::Cursor;
|
||||
|
||||
pub fn main() {
|
||||
let input = "foo 123";
|
||||
|
||||
let options = SkimOptionsBuilder::default().query(Some("f")).build().unwrap();
|
||||
let item_reader = SkimItemReader::new(SkimItemReaderOption::default().nth("2").build());
|
||||
|
||||
let items = item_reader.of_bufread(Cursor::new(input));
|
||||
let selected_items = Skim::run_with(&options, Some(items))
|
||||
.map(|out| out.selected_items)
|
||||
.unwrap_or_else(|| Vec::new());
|
||||
|
||||
for item in selected_items.iter() {
|
||||
print!("{}{}", item.output(), "\n");
|
||||
}
|
||||
}
|
||||
|
|
@ -233,7 +233,7 @@ fn real_main() -> Result<i32, std::io::Error> {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// initialize collector
|
||||
let collector_option = CollectorOption::default()
|
||||
let item_reader_option = SkimItemReaderOption::default()
|
||||
.ansi(opts.is_present("ansi"))
|
||||
.delimiter(opts.values_of("delimiter").and_then(|vals| vals.last()).unwrap_or(""))
|
||||
.with_nth(opts.values_of("with-nth").and_then(|vals| vals.last()).unwrap_or(""))
|
||||
|
|
@ -241,7 +241,7 @@ fn real_main() -> Result<i32, std::io::Error> {
|
|||
.read0(opts.is_present("read0"))
|
||||
.build();
|
||||
|
||||
let cmd_collector = Rc::new(RefCell::new(DefaultSkimCollector::new(collector_option)));
|
||||
let cmd_collector = Rc::new(RefCell::new(SkimItemReader::new(item_reader_option)));
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// read in the history file
|
||||
|
|
@ -274,10 +274,9 @@ fn real_main() -> Result<i32, std::io::Error> {
|
|||
//------------------------------------------------------------------------------
|
||||
// read from pipe or command
|
||||
let stdin = std::io::stdin();
|
||||
let components_to_stop = Arc::new(AtomicUsize::new(0));
|
||||
let rx_item = match isatty(stdin.as_raw_fd()) {
|
||||
Ok(false) | Err(nix::Error::Sys(nix::errno::Errno::EINVAL)) => {
|
||||
let (rx_item, _) = cmd_collector.borrow().read_and_collect_from_command(components_to_stop, CollectorInput::Pipe(Box::new(BufReader::new(stdin))));
|
||||
let rx_item = cmd_collector.borrow().of_bufread(BufReader::new(stdin));
|
||||
Some(rx_item)
|
||||
}
|
||||
Ok(true) | Err(_) => None,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/// helper for turn a BufRead into a skim stream
|
||||
use crate::field::FieldRange;
|
||||
use crate::helper::item::DefaultSkimItem;
|
||||
use crate::reader::CommandCollector;
|
||||
|
|
@ -17,8 +18,13 @@ const ITEM_CHANNEL_SIZE: usize = 10240;
|
|||
const DELIMITER_STR: &str = r"[\t\n ]+";
|
||||
const READ_BUFFER_SIZE: usize = 1024;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CollectorOption {
|
||||
pub enum CollectorInput {
|
||||
Pipe(Box<dyn BufRead + Send>),
|
||||
Command(String),
|
||||
}
|
||||
|
||||
pub struct SkimItemReaderOption {
|
||||
buf_size: usize,
|
||||
use_ansi_color: bool,
|
||||
transform_fields: Vec<FieldRange>,
|
||||
matching_fields: Vec<FieldRange>,
|
||||
|
|
@ -26,19 +32,30 @@ pub struct CollectorOption {
|
|||
line_ending: u8,
|
||||
}
|
||||
|
||||
impl Default for CollectorOption {
|
||||
impl Default for SkimItemReaderOption {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
buf_size: READ_BUFFER_SIZE,
|
||||
line_ending: b'\n',
|
||||
use_ansi_color: false,
|
||||
transform_fields: Vec::new(),
|
||||
matching_fields: Vec::new(),
|
||||
delimiter: Regex::new(DELIMITER_STR).unwrap(),
|
||||
line_ending: b'\n',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CollectorOption {
|
||||
impl SkimItemReaderOption {
|
||||
pub fn buf_size(mut self, buf_size: usize) -> Self {
|
||||
self.buf_size = buf_size;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn line_ending(mut self, line_ending: u8) -> Self {
|
||||
self.line_ending = line_ending;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn ansi(mut self, enable: bool) -> Self {
|
||||
self.use_ansi_color = enable;
|
||||
self
|
||||
|
|
@ -93,27 +110,85 @@ impl CollectorOption {
|
|||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_simple(&self) -> bool {
|
||||
!self.use_ansi_color && self.matching_fields.is_empty() && self.transform_fields.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub enum CollectorInput {
|
||||
Pipe(Box<dyn BufRead + Send>),
|
||||
Command(String),
|
||||
pub struct SkimItemReader {
|
||||
option: Arc<SkimItemReaderOption>,
|
||||
}
|
||||
|
||||
pub struct DefaultSkimCollector {
|
||||
option: Arc<CollectorOption>,
|
||||
impl Default for SkimItemReader {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
option: Arc::new(Default::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DefaultSkimCollector {
|
||||
pub fn new(option: CollectorOption) -> Self {
|
||||
impl SkimItemReader {
|
||||
pub fn new(option: SkimItemReaderOption) -> Self {
|
||||
Self {
|
||||
option: Arc::new(option),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn option(mut self, option: SkimItemReaderOption) -> Self {
|
||||
self.option = Arc::new(option);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl SkimItemReader {
|
||||
pub fn of_bufread(&self, source: impl BufRead + Send + 'static) -> SkimItemReceiver {
|
||||
if self.option.is_simple() {
|
||||
self.raw_bufread(source)
|
||||
} else {
|
||||
self.read_and_collect_from_command(Arc::new(AtomicUsize::new(0)), CollectorInput::Pipe(Box::new(source)))
|
||||
.0
|
||||
}
|
||||
}
|
||||
|
||||
/// helper: convert bufread into SkimItemReceiver
|
||||
fn raw_bufread(&self, mut source: impl BufRead + Send + 'static) -> SkimItemReceiver {
|
||||
let (tx_item, rx_item): (SkimItemSender, SkimItemReceiver) = bounded(self.option.buf_size);
|
||||
let line_ending = self.option.line_ending;
|
||||
thread::spawn(move || {
|
||||
let mut buffer = Vec::with_capacity(1024);
|
||||
loop {
|
||||
buffer.clear();
|
||||
// start reading
|
||||
match source.read_until(line_ending, &mut buffer) {
|
||||
Ok(n) => {
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
if buffer.ends_with(&[b'\r', b'\n']) {
|
||||
buffer.pop();
|
||||
buffer.pop();
|
||||
} else if buffer.ends_with(&[b'\n']) || buffer.ends_with(&[b'\0']) {
|
||||
buffer.pop();
|
||||
}
|
||||
|
||||
let string = String::from_utf8_lossy(&buffer);
|
||||
let result = tx_item.send(Arc::new(string.into_owned()));
|
||||
if result.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(_err) => {} // String not UTF8 or other error, skip.
|
||||
}
|
||||
}
|
||||
});
|
||||
rx_item
|
||||
}
|
||||
|
||||
/// components_to_stop == 0 => all the threads have been stopped
|
||||
/// return (channel_for_receive_item, channel_to_stop_command)
|
||||
pub fn read_and_collect_from_command(
|
||||
fn read_and_collect_from_command(
|
||||
&self,
|
||||
components_to_stop: Arc<AtomicUsize>,
|
||||
input: CollectorInput,
|
||||
|
|
@ -129,7 +204,6 @@ impl DefaultSkimCollector {
|
|||
let started = Arc::new(AtomicBool::new(false));
|
||||
let started_clone = started.clone();
|
||||
let components_to_stop_clone = components_to_stop.clone();
|
||||
let option = self.option.clone();
|
||||
// listening to close signal and kill command if needed
|
||||
thread::spawn(move || {
|
||||
debug!("collector: command killer start");
|
||||
|
|
@ -154,12 +228,13 @@ impl DefaultSkimCollector {
|
|||
let started = Arc::new(AtomicBool::new(false));
|
||||
let started_clone = started.clone();
|
||||
let tx_interrupt_clone = tx_interrupt.clone();
|
||||
let option = self.option.clone();
|
||||
thread::spawn(move || {
|
||||
debug!("collector: command collector start");
|
||||
components_to_stop.fetch_add(1, Ordering::SeqCst);
|
||||
started_clone.store(true, Ordering::SeqCst); // notify parent that it is started
|
||||
|
||||
let mut buffer = Vec::with_capacity(READ_BUFFER_SIZE);
|
||||
let mut buffer = Vec::with_capacity(option.buf_size);
|
||||
loop {
|
||||
buffer.clear();
|
||||
|
||||
|
|
@ -212,7 +287,7 @@ impl DefaultSkimCollector {
|
|||
}
|
||||
}
|
||||
|
||||
impl CommandCollector for DefaultSkimCollector {
|
||||
impl CommandCollector for SkimItemReader {
|
||||
fn invoke(&mut self, cmd: &str, components_to_stop: Arc<AtomicUsize>) -> (SkimItemReceiver, Sender<i32>) {
|
||||
self.read_and_collect_from_command(components_to_stop, CollectorInput::Command(cmd.to_string()))
|
||||
}
|
||||
|
|
@ -1,3 +1,2 @@
|
|||
pub mod item;
|
||||
pub mod item_collector;
|
||||
pub mod string_reader;
|
||||
pub mod item_reader;
|
||||
|
|
|
|||
|
|
@ -1,71 +0,0 @@
|
|||
use crate::prelude::bounded;
|
||||
use crate::{SkimItemReceiver, SkimItemSender};
|
||||
/// helper for turn a BufRead into a skim stream
|
||||
use std::io::BufRead;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
const ITEM_CHANNEL_SIZE: usize = 10240;
|
||||
|
||||
pub struct SkimItemReader {
|
||||
buf_size: usize,
|
||||
line_ending: u8,
|
||||
}
|
||||
|
||||
impl Default for SkimItemReader {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
buf_size: ITEM_CHANNEL_SIZE,
|
||||
line_ending: b'\n',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SkimItemReader {
|
||||
pub fn buf_size(mut self, buf_size: usize) -> Self {
|
||||
self.buf_size = buf_size;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn line_ending(mut self, line_ending: u8) -> Self {
|
||||
self.line_ending = line_ending;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl SkimItemReader {
|
||||
/// helper: convert bufread into SkimItemReceiver
|
||||
pub fn of_bufread(&self, mut source: impl BufRead + Send + 'static) -> SkimItemReceiver {
|
||||
let (tx_item, rx_item): (SkimItemSender, SkimItemReceiver) = bounded(self.buf_size);
|
||||
let line_ending = self.line_ending;
|
||||
thread::spawn(move || {
|
||||
let mut buffer = Vec::with_capacity(1024);
|
||||
loop {
|
||||
buffer.clear();
|
||||
// start reading
|
||||
match source.read_until(line_ending, &mut buffer) {
|
||||
Ok(n) => {
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
if buffer.ends_with(&[b'\r', b'\n']) {
|
||||
buffer.pop();
|
||||
buffer.pop();
|
||||
} else if buffer.ends_with(&[b'\n']) || buffer.ends_with(&[b'\0']) {
|
||||
buffer.pop();
|
||||
}
|
||||
|
||||
let string = String::from_utf8_lossy(&buffer);
|
||||
let result = tx_item.send(Arc::new(string.into_owned()));
|
||||
if result.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(_err) => {} // String not UTF8 or other error, skip.
|
||||
}
|
||||
}
|
||||
});
|
||||
rx_item
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
|||
|
||||
use derive_builder::Builder;
|
||||
|
||||
use crate::helper::item_collector::DefaultSkimCollector;
|
||||
use crate::helper::item_reader::SkimItemReader;
|
||||
use crate::reader::CommandCollector;
|
||||
use crate::{CaseMatching, FuzzyAlgorithm, MatchEngineFactory};
|
||||
use std::cell::RefCell;
|
||||
|
|
@ -91,7 +91,7 @@ impl<'a> Default for SkimOptions<'a> {
|
|||
engine_factory: None,
|
||||
query_history: &[],
|
||||
cmd_history: &[],
|
||||
cmd_collector: Rc::new(RefCell::new(DefaultSkimCollector::new(Default::default()))),
|
||||
cmd_collector: Rc::new(RefCell::new(SkimItemReader::new(Default::default()))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
pub use crate::ansi::AnsiString;
|
||||
pub use crate::engine::{factory::*, fuzzy::FuzzyAlgorithm};
|
||||
pub use crate::helper::item_collector::{CollectorInput, CollectorOption, DefaultSkimCollector};
|
||||
pub use crate::helper::string_reader::SkimItemReader;
|
||||
pub use crate::helper::item_reader::{SkimItemReader, SkimItemReaderOption};
|
||||
pub use crate::options::{SkimOptions, SkimOptionsBuilder};
|
||||
pub use crate::output::SkimOutput;
|
||||
pub use crate::*;
|
||||
|
|
|
|||
Loading…
Reference in a new issue