mirror of
https://github.com/lotabout/skim.git
synced 2026-09-10 07:16:23 -04:00
[collector] add helper SkimItemReader
This commit is contained in:
parent
83080e305e
commit
e3f3d35561
30
README.md
30
README.md
|
|
@ -372,10 +372,7 @@ Also you can use `--with-nth` to re-arrange the order of fields.
|
|||
|
||||
## Use as a library
|
||||
|
||||
Skim can now be used as a library in your Rust crates. The basic idea is to
|
||||
throw anything that is `BufRead`(we can easily turn a `File` for `String` into
|
||||
`BufRead`) and skim will do its job and bring us back the user selection
|
||||
including the selected items(with their indices), the query, etc.
|
||||
Skim can be used as a library in your Rust crates.
|
||||
|
||||
First, add skim into your `Cargo.toml`:
|
||||
|
||||
|
|
@ -388,7 +385,7 @@ Then try to run this simple example:
|
|||
|
||||
```rust
|
||||
extern crate skim;
|
||||
use skim::{Skim, SkimOptionsBuilder};
|
||||
use skim::prelude::*;
|
||||
use std::io::Cursor;
|
||||
|
||||
pub fn main() {
|
||||
|
|
@ -400,7 +397,13 @@ pub fn main() {
|
|||
|
||||
let input = "aaaaa\nbbbb\nccc".to_string();
|
||||
|
||||
let selected_items = Skim::run_with(&options, Some(Box::new(Cursor::new(input))))
|
||||
// `SkimItemReader` is a helper to turn any `BufRead` into a stream of `SkimItem`
|
||||
// `SkimItem` was implemented for `AsRef<str>` by default
|
||||
let item_reader = SkimItemReader::default();
|
||||
let items = item_reader.of_bufread(Cursor::new(input));
|
||||
|
||||
// `run_with` would read and show items from the stream
|
||||
let selected_items = Skim::run_with(&options, Some(items))
|
||||
.map(|out| out.selected_items)
|
||||
.unwrap_or_else(|| Vec::new());
|
||||
|
||||
|
|
@ -410,6 +413,21 @@ pub fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
Given an `Option<SkimItemReceiver>`, skim will read items accordingly, do its
|
||||
job and bring us back the user selection including the selected items(with
|
||||
their indices), the query, etc. Note that:
|
||||
|
||||
- `SkimItemReceiver` is `crossbeam::channel::Receiver<Arc<dyn SkimItem>>`
|
||||
- If it is none, it will invoke the given command and read items from command output
|
||||
- Otherwise, it will read the items from the (crossbeam) channel.
|
||||
|
||||
Trait `SkimItem` is provided to customize how a line could be displayed,
|
||||
compared and previewed. It is implemented by default for `AsRef<str>`
|
||||
|
||||
Plus, `SkimItemReader` is a helper to convert a `BufRead` into
|
||||
`SkimItemReceiver` (we can easily turn a `File` for `String` into `BufRead`).
|
||||
So that you could deal with strings or files easily.
|
||||
|
||||
Check more examples under [examples/](https://github.com/lotabout/skim/tree/master/examples) directory.
|
||||
|
||||
# FAQ
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
extern crate skim;
|
||||
use crossbeam::channel::unbounded;
|
||||
use skim::prelude::*;
|
||||
use std::sync::Arc;
|
||||
use std::io::Cursor;
|
||||
|
||||
pub fn main() {
|
||||
let options = SkimOptionsBuilder::default()
|
||||
|
|
@ -9,16 +8,13 @@ pub fn main() {
|
|||
.multi(true)
|
||||
.build()
|
||||
.unwrap();
|
||||
let item_reader = SkimItemReader::default();
|
||||
|
||||
//==================================================
|
||||
// first run
|
||||
let (tx_item, rx_item): (SkimItemSender, SkimItemReceiver) = unbounded();
|
||||
let _ = tx_item.send(Arc::new("aaaaa"));
|
||||
let _ = tx_item.send(Arc::new("bbbb"));
|
||||
let _ = tx_item.send(Arc::new("ccc"));
|
||||
drop(tx_item);
|
||||
|
||||
let selected_items = Skim::run_with(&options, Some(rx_item))
|
||||
let input = "aaaaa\nbbbb\nccc".to_string();
|
||||
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());
|
||||
|
||||
|
|
@ -28,13 +24,9 @@ pub fn main() {
|
|||
|
||||
//==================================================
|
||||
// second run
|
||||
let (tx_item, rx_item): (SkimItemSender, SkimItemReceiver) = unbounded();
|
||||
let _ = tx_item.send(Arc::new("11111"));
|
||||
let _ = tx_item.send(Arc::new("22222"));
|
||||
let _ = tx_item.send(Arc::new("333333333"));
|
||||
drop(tx_item);
|
||||
|
||||
let selected_items = Skim::run_with(&options, Some(rx_item))
|
||||
let input = "11111\n22222\n333333333".to_string();
|
||||
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());
|
||||
|
||||
|
|
|
|||
|
|
@ -182,3 +182,68 @@ fn get_command_output(cmd: &str) -> Result<CommandOutput, Box<dyn Error>> {
|
|||
|
||||
Ok((Some(command), Box::new(BufReader::new(stdout))))
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// helper
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue