From c1f41bf107e5352ac910543cd1b447193af494cd Mon Sep 17 00:00:00 2001 From: Alexandre Pasmantier Date: Sat, 9 Nov 2024 23:32:04 +0100 Subject: [PATCH] refactoring: extract matcher logic into separate crate --- .github/workflows/ci.yml | 11 +- Cargo.lock | 11 +- Cargo.toml | 5 +- Makefile | 2 +- crates/television/channels/alias.rs | 7 +- crates/television/channels/env.rs | 2 +- crates/television/channels/files.rs | 2 +- crates/television/channels/git_repos.rs | 2 +- crates/television/channels/remote_control.rs | 7 +- crates/television/channels/stdin.rs | 2 +- crates/television/channels/text.rs | 23 ++- crates/television/fuzzy.rs | 27 --- crates/television/main.rs | 1 - crates/television/utils/syntax.rs | 2 +- crates/television_fuzzy/Cargo.toml | 19 ++ crates/television_fuzzy/src/lib.rs | 3 + crates/television_fuzzy/src/matcher/config.rs | 70 ++++++++ .../television_fuzzy/src/matcher/injector.rs | 49 ++++++ crates/television_fuzzy/src/matcher/lazy.rs | 91 ++++++++++ .../src/matcher/matched_item.rs | 20 +++ .../src/matcher/mod.rs} | 162 ++---------------- 21 files changed, 310 insertions(+), 208 deletions(-) delete mode 100644 crates/television/fuzzy.rs create mode 100644 crates/television_fuzzy/Cargo.toml create mode 100644 crates/television_fuzzy/src/lib.rs create mode 100644 crates/television_fuzzy/src/matcher/config.rs create mode 100644 crates/television_fuzzy/src/matcher/injector.rs create mode 100644 crates/television_fuzzy/src/matcher/lazy.rs create mode 100644 crates/television_fuzzy/src/matcher/matched_item.rs rename crates/{television/fuzzy/matcher.rs => television_fuzzy/src/matcher/mod.rs} (59%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 10feb2b..e239269 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 diff --git a/Cargo.lock b/Cargo.lock index ebd05e2..995ee36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 83eee73..60fedfe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 = [ diff --git a/Makefile b/Makefile index f98497b..6176518 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION=0.2.13 +VERSION=0.3.13 NAME=television EXEC=tv PREFIX=$(HOME)/.local diff --git a/crates/television/channels/alias.rs b/crates/television/channels/alias.rs index d10153f..74f0d3b 100644 --- a/crates/television/channels/alias.rs +++ b/crates/television/channels/alias.rs @@ -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 { diff --git a/crates/television/channels/env.rs b/crates/television/channels/env.rs index da8977f..ba5b8f9 100644 --- a/crates/television/channels/env.rs +++ b/crates/television/channels/env.rs @@ -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 { diff --git a/crates/television/channels/files.rs b/crates/television/channels/files.rs index e7be2d4..58b93ec 100644 --- a/crates/television/channels/files.rs +++ b/crates/television/channels/files.rs @@ -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, diff --git a/crates/television/channels/git_repos.rs b/crates/television/channels/git_repos.rs index 55e3e85..c5a547b 100644 --- a/crates/television/channels/git_repos.rs +++ b/crates/television/channels/git_repos.rs @@ -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, diff --git a/crates/television/channels/remote_control.rs b/crates/television/channels/remote_control.rs index 7d1b584..08befe4 100644 --- a/crates/television/channels/remote_control.rs +++ b/crates/television/channels/remote_control.rs @@ -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, diff --git a/crates/television/channels/stdin.rs b/crates/television/channels/stdin.rs index 5883d58..3385a88 100644 --- a/crates/television/channels/stdin.rs +++ b/crates/television/channels/stdin.rs @@ -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, diff --git a/crates/television/channels/text.rs b/crates/television/channels/text.rs index bbd3b06..81e96a8 100644 --- a/crates/television/channels/text.rs +++ b/crates/television/channels/text.rs @@ -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 { diff --git a/crates/television/fuzzy.rs b/crates/television/fuzzy.rs deleted file mode 100644 index 6202394..0000000 --- a/crates/television/fuzzy.rs +++ /dev/null @@ -1,27 +0,0 @@ -use parking_lot::Mutex; -use std::ops::DerefMut; - -pub mod matcher; - -pub struct LazyMutex { - inner: Mutex>, - init: fn() -> T, -} - -impl LazyMutex { - pub const fn new(init: fn() -> T) -> Self { - Self { - inner: Mutex::new(None), - init, - } - } - - pub fn lock(&self) -> impl DerefMut + '_ { - parking_lot::MutexGuard::map(self.inner.lock(), |val| { - val.get_or_insert_with(self.init) - }) - } -} - -pub static MATCHER: LazyMutex = - LazyMutex::new(nucleo::Matcher::default); diff --git a/crates/television/main.rs b/crates/television/main.rs index dd8af90..9921e44 100644 --- a/crates/television/main.rs +++ b/crates/television/main.rs @@ -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; diff --git a/crates/television/utils/syntax.rs b/crates/television/utils/syntax.rs index e703b00..33a2408 100644 --- a/crates/television/utils/syntax.rs +++ b/crates/television/utils/syntax.rs @@ -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()) } diff --git a/crates/television_fuzzy/Cargo.toml b/crates/television_fuzzy/Cargo.toml new file mode 100644 index 0000000..a4c754e --- /dev/null +++ b/crates/television_fuzzy/Cargo.toml @@ -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 "] +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" diff --git a/crates/television_fuzzy/src/lib.rs b/crates/television_fuzzy/src/lib.rs new file mode 100644 index 0000000..62db079 --- /dev/null +++ b/crates/television_fuzzy/src/lib.rs @@ -0,0 +1,3 @@ +pub mod matcher; + +pub use matcher::Matcher; diff --git a/crates/television_fuzzy/src/matcher/config.rs b/crates/television_fuzzy/src/matcher/config.rs new file mode 100644 index 0000000..0f6cc08 --- /dev/null +++ b/crates/television_fuzzy/src/matcher/config.rs @@ -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, + /// 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 + } +} diff --git a/crates/television_fuzzy/src/matcher/injector.rs b/crates/television_fuzzy/src/matcher/injector.rs new file mode 100644 index 0000000..9bd42dc --- /dev/null +++ b/crates/television_fuzzy/src/matcher/injector.rs @@ -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 +where + I: Sync + Send + Clone + 'static, +{ + /// The inner `Injector` from the `Nucleo` fuzzy matcher. + inner: nucleo::Injector, +} + +impl Injector +where + I: Sync + Send + Clone + 'static, +{ + pub fn new(inner: nucleo::Injector) -> 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(&self, item: I, f: F) + where + F: FnOnce(&I, &mut [nucleo::Utf32String]), + { + self.inner.push(item, f); + } +} diff --git a/crates/television_fuzzy/src/matcher/lazy.rs b/crates/television_fuzzy/src/matcher/lazy.rs new file mode 100644 index 0000000..9db553f --- /dev/null +++ b/crates/television_fuzzy/src/matcher/lazy.rs @@ -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 = LazyMutex::new(|| { +/// Thing::new() +/// }); +/// ``` +pub struct LazyMutex { + /// The inner value, wrapped in a mutex. + inner: Mutex>, + /// The initialization function. + init: fn() -> T, +} + +impl LazyMutex { + 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 + '_ { + 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 = LazyMutex::new(Matcher::default); diff --git a/crates/television_fuzzy/src/matcher/matched_item.rs b/crates/television_fuzzy/src/matcher/matched_item.rs new file mode 100644 index 0000000..ad9361c --- /dev/null +++ b/crates/television_fuzzy/src/matcher/matched_item.rs @@ -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 +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)>, +} diff --git a/crates/television/fuzzy/matcher.rs b/crates/television_fuzzy/src/matcher/mod.rs similarity index 59% rename from crates/television/fuzzy/matcher.rs rename to crates/television_fuzzy/src/matcher/mod.rs index 8467ba8..9d77d87 100644 --- a/crates/television/fuzzy/matcher.rs +++ b/crates/television_fuzzy/src/matcher/mod.rs @@ -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 -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 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, - /// 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 -where - I: Sync + Send + Clone + 'static, -{ - /// The inner `Injector` from the `Nucleo` fuzzy matcher. - inner: nucleo::Injector, -} - -impl Injector -where - I: Sync + Send + Clone + 'static, -{ - pub fn new(inner: nucleo::Injector) -> 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(&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 = 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 = Matcher::new(config); /// matcher.find("some pattern"); /// /// if let Some(item) = matcher.get_result(0) { - /// println!("{:?}", item); /// // Do something with the matched item /// // ... /// }