mirror of
https://github.com/alexpasmantier/television.git
synced 2025-06-06 19:45:23 +00:00
refactoring: extract matcher logic into separate crate
This commit is contained in:
parent
4e4ef9761b
commit
c1f41bf107
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
@ -39,11 +39,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@nightly
|
||||
uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: clippy
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: Clippy check
|
||||
run: cargo clippy --all-targets --all-features --workspace -- -D warnings
|
||||
- name: Clippy Check
|
||||
run: cargo clippy -- -D warnings
|
||||
|
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -3094,7 +3094,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "television"
|
||||
version = "0.2.13"
|
||||
version = "0.3.13"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bat",
|
||||
@ -3127,6 +3127,7 @@ dependencies = [
|
||||
"strum",
|
||||
"syntect",
|
||||
"television-derive",
|
||||
"television-fuzzy",
|
||||
"termtree",
|
||||
"tokio",
|
||||
"toml",
|
||||
@ -3146,6 +3147,14 @@ dependencies = [
|
||||
"syn 2.0.87",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "television-fuzzy"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"nucleo",
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.14.0"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "television"
|
||||
version = "0.2.13"
|
||||
version = "0.3.13"
|
||||
edition = "2021"
|
||||
description = "The revolution will be televised."
|
||||
license = "MIT"
|
||||
@ -22,9 +22,10 @@ path = "crates/television/main.rs"
|
||||
name = "tv"
|
||||
|
||||
[workspace]
|
||||
members = ["crates/television_derive"]
|
||||
members = ["crates/television_derive", "crates/television_fuzzy"]
|
||||
|
||||
[dependencies]
|
||||
television-fuzzy = { version = "0.1.1", path = "crates/television_fuzzy" }
|
||||
television-derive = { version = "0.1.2", path = "crates/television_derive" }
|
||||
better-panic = "0.3.0"
|
||||
clap = { version = "4.4.5", features = [
|
||||
|
2
Makefile
2
Makefile
@ -1,4 +1,4 @@
|
||||
VERSION=0.2.13
|
||||
VERSION=0.3.13
|
||||
NAME=television
|
||||
EXEC=tv
|
||||
PREFIX=$(HOME)/.local
|
||||
|
@ -1,12 +1,11 @@
|
||||
use crate::fuzzy::matcher::{Config, Injector, Matcher};
|
||||
use devicons::FileIcon;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::channels::OnAir;
|
||||
use crate::entry::Entry;
|
||||
use crate::previewers::PreviewType;
|
||||
use crate::utils::indices::sep_name_and_value_indices;
|
||||
use crate::utils::strings::preprocess_line;
|
||||
use devicons::FileIcon;
|
||||
use television_fuzzy::matcher::{config::Config, injector::Injector, Matcher};
|
||||
use tracing::debug;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Alias {
|
||||
|
@ -2,10 +2,10 @@ use devicons::FileIcon;
|
||||
|
||||
use super::OnAir;
|
||||
use crate::entry::Entry;
|
||||
use crate::fuzzy::matcher::{Config, Matcher};
|
||||
use crate::previewers::PreviewType;
|
||||
use crate::utils::indices::sep_name_and_value_indices;
|
||||
use crate::utils::strings::preprocess_line;
|
||||
use television_fuzzy::matcher::{config::Config, Matcher};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct EnvVar {
|
||||
|
@ -1,12 +1,12 @@
|
||||
use crate::channels::{OnAir, TelevisionChannel};
|
||||
use crate::entry::Entry;
|
||||
use crate::fuzzy::matcher::{Config, Injector, Matcher};
|
||||
use crate::previewers::PreviewType;
|
||||
use crate::utils::files::{walk_builder, DEFAULT_NUM_THREADS};
|
||||
use crate::utils::strings::preprocess_line;
|
||||
use devicons::FileIcon;
|
||||
use std::collections::HashSet;
|
||||
use std::path::PathBuf;
|
||||
use television_fuzzy::matcher::{config::Config, injector::Injector, Matcher};
|
||||
|
||||
pub struct Channel {
|
||||
matcher: Matcher<String>,
|
||||
|
@ -12,8 +12,8 @@ use crate::{
|
||||
};
|
||||
|
||||
use crate::channels::OnAir;
|
||||
use crate::fuzzy::matcher::{Config, Injector, Matcher};
|
||||
use crate::utils::strings::preprocess_line;
|
||||
use television_fuzzy::matcher::{config::Config, injector::Injector, Matcher};
|
||||
|
||||
pub struct Channel {
|
||||
matcher: Matcher<String>,
|
||||
|
@ -1,13 +1,12 @@
|
||||
use clap::ValueEnum;
|
||||
use devicons::FileIcon;
|
||||
|
||||
use crate::channels::{TelevisionChannel, UnitChannel};
|
||||
use crate::{
|
||||
channels::{CliTvChannel, OnAir},
|
||||
entry::Entry,
|
||||
fuzzy::matcher::{Config, Matcher},
|
||||
previewers::PreviewType,
|
||||
};
|
||||
use clap::ValueEnum;
|
||||
use devicons::FileIcon;
|
||||
use television_fuzzy::matcher::{config::Config, Matcher};
|
||||
|
||||
pub struct RemoteControl {
|
||||
matcher: Matcher<String>,
|
||||
|
@ -5,9 +5,9 @@ use devicons::FileIcon;
|
||||
|
||||
use super::OnAir;
|
||||
use crate::entry::Entry;
|
||||
use crate::fuzzy::matcher::{Config, Matcher};
|
||||
use crate::previewers::PreviewType;
|
||||
use crate::utils::strings::preprocess_line;
|
||||
use television_fuzzy::matcher::{config::Config, Matcher};
|
||||
|
||||
pub struct Channel {
|
||||
matcher: Matcher<String>,
|
||||
|
@ -1,14 +1,5 @@
|
||||
use devicons::FileIcon;
|
||||
use ignore::WalkState;
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufRead, Read, Seek},
|
||||
path::{Path, PathBuf},
|
||||
sync::{atomic::AtomicUsize, Arc},
|
||||
};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use super::{OnAir, TelevisionChannel};
|
||||
use crate::previewers::PreviewType;
|
||||
use crate::utils::strings::PRINTABLE_ASCII_THRESHOLD;
|
||||
use crate::utils::{
|
||||
files::{is_not_text, walk_builder, DEFAULT_NUM_THREADS},
|
||||
@ -17,10 +8,16 @@ use crate::utils::{
|
||||
use crate::{
|
||||
entry::Entry, utils::strings::proportion_of_printable_ascii_characters,
|
||||
};
|
||||
use crate::{
|
||||
fuzzy::matcher::{Config, Injector, Matcher},
|
||||
previewers::PreviewType,
|
||||
use devicons::FileIcon;
|
||||
use ignore::WalkState;
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufRead, Read, Seek},
|
||||
path::{Path, PathBuf},
|
||||
sync::{atomic::AtomicUsize, Arc},
|
||||
};
|
||||
use television_fuzzy::matcher::{config::Config, injector::Injector, Matcher};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct CandidateLine {
|
||||
|
@ -1,27 +0,0 @@
|
||||
use parking_lot::Mutex;
|
||||
use std::ops::DerefMut;
|
||||
|
||||
pub mod matcher;
|
||||
|
||||
pub struct LazyMutex<T> {
|
||||
inner: Mutex<Option<T>>,
|
||||
init: fn() -> T,
|
||||
}
|
||||
|
||||
impl<T> LazyMutex<T> {
|
||||
pub const fn new(init: fn() -> T) -> Self {
|
||||
Self {
|
||||
inner: Mutex::new(None),
|
||||
init,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lock(&self) -> impl DerefMut<Target = T> + '_ {
|
||||
parking_lot::MutexGuard::map(self.inner.lock(), |val| {
|
||||
val.get_or_insert_with(self.init)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub static MATCHER: LazyMutex<nucleo::Matcher> =
|
||||
LazyMutex::new(nucleo::Matcher::default);
|
@ -18,7 +18,6 @@ pub mod config;
|
||||
pub mod entry;
|
||||
pub mod errors;
|
||||
pub mod event;
|
||||
pub mod fuzzy;
|
||||
pub mod logging;
|
||||
pub mod picker;
|
||||
pub mod previewers;
|
||||
|
@ -101,5 +101,5 @@ lazy_static! {
|
||||
|
||||
pub fn load_highlighting_assets() -> HighlightingAssets {
|
||||
HighlightingAssets::from_cache(PROJECT_DIRS.cache_dir())
|
||||
.unwrap_or_else(|_| bat::assets::HighlightingAssets::from_binary())
|
||||
.unwrap_or_else(|_| HighlightingAssets::from_binary())
|
||||
}
|
||||
|
19
crates/television_fuzzy/Cargo.toml
Normal file
19
crates/television_fuzzy/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "television-fuzzy"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
description = "The revolution will be televised."
|
||||
license = "MIT"
|
||||
authors = ["Alexandre Pasmantier <alex.pasmant@gmail.com>"]
|
||||
repository = "https://github.com/alexpasmantier/television"
|
||||
keywords = ["search", "fuzzy", "preview", "tui", "terminal"]
|
||||
categories = [
|
||||
"command-line-utilities",
|
||||
"command-line-interface",
|
||||
"concurrency",
|
||||
"development-tools",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
nucleo = "0.5.0"
|
||||
parking_lot = "0.12.3"
|
3
crates/television_fuzzy/src/lib.rs
Normal file
3
crates/television_fuzzy/src/lib.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod matcher;
|
||||
|
||||
pub use matcher::Matcher;
|
70
crates/television_fuzzy/src/matcher/config.rs
Normal file
70
crates/television_fuzzy/src/matcher/config.rs
Normal file
@ -0,0 +1,70 @@
|
||||
/// The configuration of the fuzzy matcher.
|
||||
///
|
||||
/// This contains the number of threads to use, whether to ignore case, whether
|
||||
/// to prefer prefix matches, and whether to optimize for matching paths.
|
||||
///
|
||||
/// The default configuration uses the default configuration of the `Nucleo`
|
||||
/// fuzzy matcher, e.g. case-insensitive matching, no preference for prefix
|
||||
/// matches, and no optimization for matching paths as well as using the
|
||||
/// default number of threads (which corresponds to the number of available logical
|
||||
/// cores on the current machine).
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Config {
|
||||
/// The number of threads to use for the fuzzy matcher.
|
||||
pub n_threads: Option<usize>,
|
||||
/// Whether to ignore case when matching.
|
||||
pub ignore_case: bool,
|
||||
/// Whether to prefer prefix matches.
|
||||
pub prefer_prefix: bool,
|
||||
/// Whether to optimize for matching paths.
|
||||
pub match_paths: bool,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
n_threads: None,
|
||||
ignore_case: true,
|
||||
prefer_prefix: false,
|
||||
match_paths: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Set the number of threads to use.
|
||||
pub fn n_threads(mut self, n_threads: usize) -> Self {
|
||||
self.n_threads = Some(n_threads);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to ignore case.
|
||||
pub fn ignore_case(mut self, ignore_case: bool) -> Self {
|
||||
self.ignore_case = ignore_case;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to prefer prefix matches.
|
||||
pub fn prefer_prefix(mut self, prefer_prefix: bool) -> Self {
|
||||
self.prefer_prefix = prefer_prefix;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to optimize for matching paths.
|
||||
pub fn match_paths(mut self, match_paths: bool) -> Self {
|
||||
self.match_paths = match_paths;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Config> for nucleo::Config {
|
||||
fn from(config: &Config) -> Self {
|
||||
let mut matcher_config = nucleo::Config::DEFAULT;
|
||||
matcher_config.ignore_case = config.ignore_case;
|
||||
matcher_config.prefer_prefix = config.prefer_prefix;
|
||||
if config.match_paths {
|
||||
matcher_config = matcher_config.match_paths();
|
||||
}
|
||||
matcher_config
|
||||
}
|
||||
}
|
49
crates/television_fuzzy/src/matcher/injector.rs
Normal file
49
crates/television_fuzzy/src/matcher/injector.rs
Normal file
@ -0,0 +1,49 @@
|
||||
/// An injector that can be used to push items of type `I` into the fuzzy matcher.
|
||||
///
|
||||
/// This is a wrapper around the `Injector` type from the `Nucleo` fuzzy matcher.
|
||||
///
|
||||
/// The `push` method takes an item of type `I` and a closure that produces the
|
||||
/// string to match against based on the item.
|
||||
#[derive(Clone)]
|
||||
pub struct Injector<I>
|
||||
where
|
||||
I: Sync + Send + Clone + 'static,
|
||||
{
|
||||
/// The inner `Injector` from the `Nucleo` fuzzy matcher.
|
||||
inner: nucleo::Injector<I>,
|
||||
}
|
||||
|
||||
impl<I> Injector<I>
|
||||
where
|
||||
I: Sync + Send + Clone + 'static,
|
||||
{
|
||||
pub fn new(inner: nucleo::Injector<I>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
/// Push an item into the fuzzy matcher.
|
||||
///
|
||||
/// The closure `f` should produce the string to match against based on the
|
||||
/// item.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use television_fuzzy::matcher::{Config, Matcher};
|
||||
///
|
||||
/// let config = Config::default();
|
||||
/// let matcher = Matcher::new(config);
|
||||
///
|
||||
/// let injector = matcher.injector();
|
||||
/// injector.push(
|
||||
/// ("some string", 3, "some other string"),
|
||||
/// // Say we want to match against the third element of the tuple
|
||||
/// |s, cols| cols[0] = s.2.into()
|
||||
/// );
|
||||
/// ```
|
||||
pub fn push<F>(&self, item: I, f: F)
|
||||
where
|
||||
F: FnOnce(&I, &mut [nucleo::Utf32String]),
|
||||
{
|
||||
self.inner.push(item, f);
|
||||
}
|
||||
}
|
91
crates/television_fuzzy/src/matcher/lazy.rs
Normal file
91
crates/television_fuzzy/src/matcher/lazy.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use nucleo::Matcher;
|
||||
use parking_lot::Mutex;
|
||||
use std::ops::DerefMut;
|
||||
|
||||
/// A lazy-initialized mutex.
|
||||
///
|
||||
/// This is used to lazily initialize a nucleo matcher (which pre-allocates
|
||||
/// quite a bit of memory upfront which can be expensive during initialization).
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// use television_fuzzy::matcher::lazy::LazyMutex;
|
||||
///
|
||||
/// struct Thing {
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// impl Thing {
|
||||
/// fn new() -> Self {
|
||||
/// // something expensive
|
||||
/// Thing { }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// static THING_TO_LAZY_INIT: LazyMutex<Thing> = LazyMutex::new(|| {
|
||||
/// Thing::new()
|
||||
/// });
|
||||
/// ```
|
||||
pub struct LazyMutex<T> {
|
||||
/// The inner value, wrapped in a mutex.
|
||||
inner: Mutex<Option<T>>,
|
||||
/// The initialization function.
|
||||
init: fn() -> T,
|
||||
}
|
||||
|
||||
impl<T> LazyMutex<T> {
|
||||
pub const fn new(init: fn() -> T) -> Self {
|
||||
Self {
|
||||
inner: Mutex::new(None),
|
||||
init,
|
||||
}
|
||||
}
|
||||
|
||||
/// Locks the mutex and returns a guard that allows mutable access to the
|
||||
/// inner value.
|
||||
pub fn lock(&self) -> impl DerefMut<Target = T> + '_ {
|
||||
parking_lot::MutexGuard::map(self.inner.lock(), |val| {
|
||||
val.get_or_insert_with(self.init)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A lazy-initialized nucleo matcher used for conveniently computing match indices.
|
||||
///
|
||||
/// This is used to lazily initialize a nucleo matcher (which pre-allocates quite a bit of memory
|
||||
/// upfront which can be expensive at initialization).
|
||||
///
|
||||
/// This matcher is used as a convenience for computing match indices on a subset of matched items.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use television_fuzzy::matcher::{lazy::MATCHER, matched_item::MatchedItem};
|
||||
///
|
||||
/// let snapshot = channel_matcher.snapshot();
|
||||
///
|
||||
/// let mut col_indices = vec![];
|
||||
/// let mut matcher = MATCHER.lock();
|
||||
///
|
||||
/// snapshot
|
||||
/// .matched_items(..)
|
||||
/// .map(move |item| {
|
||||
/// snapshot.pattern().column_pattern(0).indices(
|
||||
/// item.matcher_columns[0].slice(..),
|
||||
/// &mut matcher,
|
||||
/// &mut col_indices,
|
||||
/// );
|
||||
/// col_indices.sort_unstable();
|
||||
/// col_indices.dedup();
|
||||
///
|
||||
/// let indices = col_indices.drain(..);
|
||||
///
|
||||
/// let matched_string = item.matcher_columns[0].to_string();
|
||||
/// MatchedItem {
|
||||
/// inner: item.data.clone(),
|
||||
/// matched_string,
|
||||
/// match_indices: indices.map(|i| (i, i + 1)).collect(),
|
||||
/// }
|
||||
/// })
|
||||
/// .collect();
|
||||
/// ```
|
||||
pub static MATCHER: LazyMutex<Matcher> = LazyMutex::new(Matcher::default);
|
20
crates/television_fuzzy/src/matcher/matched_item.rs
Normal file
20
crates/television_fuzzy/src/matcher/matched_item.rs
Normal file
@ -0,0 +1,20 @@
|
||||
/// A matched item.
|
||||
///
|
||||
/// This contains the matched item, the dimension against which it was matched,
|
||||
/// represented as a string, and the indices of the matched characters.
|
||||
///
|
||||
/// The indices are pairs of `(start, end)` where `start` is the index of the
|
||||
/// first character in the match, and `end` is the index of the character after
|
||||
/// the last character in the match.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MatchedItem<I>
|
||||
where
|
||||
I: Sync + Send + Clone + 'static,
|
||||
{
|
||||
/// The matched item.
|
||||
pub inner: I,
|
||||
/// The dimension against which the item was matched (as a string).
|
||||
pub matched_string: String,
|
||||
/// The indices of the matched characters.
|
||||
pub match_indices: Vec<(u32, u32)>,
|
||||
}
|
@ -1,36 +1,24 @@
|
||||
use injector::Injector;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::MATCHER;
|
||||
use crate::matcher::{
|
||||
config::Config, lazy::MATCHER, matched_item::MatchedItem,
|
||||
};
|
||||
|
||||
pub mod config;
|
||||
pub mod injector;
|
||||
pub mod lazy;
|
||||
pub mod matched_item;
|
||||
|
||||
const MATCHER_TICK_TIMEOUT: u64 = 2;
|
||||
|
||||
/// A matched item.
|
||||
///
|
||||
/// This contains the matched item, the dimension against which it was matched,
|
||||
/// represented as a string, and the indices of the matched characters.
|
||||
///
|
||||
/// The indices are pairs of `(start, end)` where `start` is the index of the
|
||||
/// first character in the match, and `end` is the index of the character after
|
||||
/// the last character in the match.
|
||||
pub struct MatchedItem<I>
|
||||
where
|
||||
I: Sync + Send + Clone + 'static,
|
||||
{
|
||||
/// The matched item.
|
||||
pub inner: I,
|
||||
/// The dimension against which the item was matched (as a string).
|
||||
pub matched_string: String,
|
||||
/// The indices of the matched characters.
|
||||
pub match_indices: Vec<(u32, u32)>,
|
||||
}
|
||||
|
||||
/// The status of the fuzzy matcher.
|
||||
///
|
||||
/// This currently only contains a boolean indicating whether the matcher is
|
||||
/// running in the background.
|
||||
/// This mostly serves as a way to communicate the status of the matcher to the
|
||||
/// front-end and display a loading indicator.
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
pub struct Status {
|
||||
/// Whether the matcher is currently running.
|
||||
pub running: bool,
|
||||
@ -44,125 +32,6 @@ impl From<nucleo::Status> for Status {
|
||||
}
|
||||
}
|
||||
|
||||
/// The configuration of the fuzzy matcher.
|
||||
///
|
||||
/// This contains the number of threads to use, whether to ignore case, whether
|
||||
/// to prefer prefix matches, and whether to optimize for matching paths.
|
||||
///
|
||||
/// The default configuration uses the default configuration of the `Nucleo`
|
||||
/// fuzzy matcher, e.g. case-insensitive matching, no preference for prefix
|
||||
/// matches, and no optimization for matching paths as well as using the
|
||||
/// default number of threads (which corresponds to the number of available logical
|
||||
/// cores on the current machine).
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Config {
|
||||
/// The number of threads to use for the fuzzy matcher.
|
||||
pub n_threads: Option<usize>,
|
||||
/// Whether to ignore case when matching.
|
||||
pub ignore_case: bool,
|
||||
/// Whether to prefer prefix matches.
|
||||
pub prefer_prefix: bool,
|
||||
/// Whether to optimize for matching paths.
|
||||
pub match_paths: bool,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
n_threads: None,
|
||||
ignore_case: true,
|
||||
prefer_prefix: false,
|
||||
match_paths: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Set the number of threads to use.
|
||||
pub fn n_threads(mut self, n_threads: usize) -> Self {
|
||||
self.n_threads = Some(n_threads);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to ignore case.
|
||||
pub fn ignore_case(mut self, ignore_case: bool) -> Self {
|
||||
self.ignore_case = ignore_case;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to prefer prefix matches.
|
||||
pub fn prefer_prefix(mut self, prefer_prefix: bool) -> Self {
|
||||
self.prefer_prefix = prefer_prefix;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to optimize for matching paths.
|
||||
pub fn match_paths(mut self, match_paths: bool) -> Self {
|
||||
self.match_paths = match_paths;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Config> for nucleo::Config {
|
||||
fn from(config: &Config) -> Self {
|
||||
let mut matcher_config = nucleo::Config::DEFAULT;
|
||||
matcher_config.ignore_case = config.ignore_case;
|
||||
matcher_config.prefer_prefix = config.prefer_prefix;
|
||||
if config.match_paths {
|
||||
matcher_config = matcher_config.match_paths();
|
||||
}
|
||||
matcher_config
|
||||
}
|
||||
}
|
||||
|
||||
/// An injector that can be used to push items of type `I` into the fuzzy matcher.
|
||||
///
|
||||
/// This is a wrapper around the `Injector` type from the `Nucleo` fuzzy matcher.
|
||||
///
|
||||
/// The `push` method takes an item of type `I` and a closure that produces the
|
||||
/// string to match against based on the item.
|
||||
#[derive(Clone)]
|
||||
pub struct Injector<I>
|
||||
where
|
||||
I: Sync + Send + Clone + 'static,
|
||||
{
|
||||
/// The inner `Injector` from the `Nucleo` fuzzy matcher.
|
||||
inner: nucleo::Injector<I>,
|
||||
}
|
||||
|
||||
impl<I> Injector<I>
|
||||
where
|
||||
I: Sync + Send + Clone + 'static,
|
||||
{
|
||||
pub fn new(inner: nucleo::Injector<I>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
/// Push an item into the fuzzy matcher.
|
||||
///
|
||||
/// The closure `f` should produce the string to match against based on the
|
||||
/// item.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// let config = Config::default();
|
||||
/// let matcher = Matcher::new(config);
|
||||
///
|
||||
/// let injector = matcher.injector();
|
||||
/// injector.push(
|
||||
/// ("some string", 3, "some other string"),
|
||||
/// // Say we want to match against the third element of the tuple
|
||||
/// |s, cols| cols[0] = s.2.into()
|
||||
/// );
|
||||
/// ```
|
||||
pub fn push<F>(&self, item: I, f: F)
|
||||
where
|
||||
F: FnOnce(&I, &mut [nucleo::Utf32String]),
|
||||
{
|
||||
self.inner.push(item, f);
|
||||
}
|
||||
}
|
||||
|
||||
/// A fuzzy matcher that can be used to match items of type `I`.
|
||||
///
|
||||
/// `I` should be `Sync`, `Send`, `Clone`, and `'static`.
|
||||
@ -220,6 +89,8 @@ where
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use television_fuzzy::matcher::{Config, Matcher};
|
||||
///
|
||||
/// let config = Config::default();
|
||||
/// let matcher = Matcher::new(config);
|
||||
/// let injector = matcher.injector();
|
||||
@ -268,8 +139,10 @@ where
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use television_fuzzy::matcher::{Config, Matcher};
|
||||
///
|
||||
/// let config = Config::default();
|
||||
/// let matcher = Matcher::new(config);
|
||||
/// let mut matcher: Matcher<String> = Matcher::new(config);
|
||||
/// matcher.find("some pattern");
|
||||
///
|
||||
/// let results = matcher.results(10, 0);
|
||||
@ -322,12 +195,13 @@ where
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use television_fuzzy::matcher::{Config, Matcher};
|
||||
///
|
||||
/// let config = Config::default();
|
||||
/// let matcher = Matcher::new(config);
|
||||
/// let mut matcher: Matcher<String> = Matcher::new(config);
|
||||
/// matcher.find("some pattern");
|
||||
///
|
||||
/// if let Some(item) = matcher.get_result(0) {
|
||||
/// println!("{:?}", item);
|
||||
/// // Do something with the matched item
|
||||
/// // ...
|
||||
/// }
|
Loading…
x
Reference in New Issue
Block a user