1
1
mirror of https://github.com/wez/wezterm.git synced 2025-01-08 07:01:35 +03:00

charselect: switch to nucleo fuzzy matcher

This has more intuitive sorting; eg: `line` used to show the first match
as `linux_endeavour` but now matches `LINEAR B IDEOGRAM VESSEL B212`
first, which feels more relevant (has an exact prefix match).

refs: https://github.com/wez/wezterm/issues/5532
This commit is contained in:
Wez Furlong 2024-07-14 10:39:20 -07:00
parent 30ecc426ca
commit 6b5edad360
No known key found for this signature in database
GPG Key ID: 7A7F66A31EC9B387
4 changed files with 42 additions and 13 deletions

11
Cargo.lock generated
View File

@ -3374,6 +3374,16 @@ dependencies = [
"winapi",
]
[[package]]
name = "nucleo-matcher"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf33f538733d1a5a3494b836ba913207f14d9d4a1d3cd67030c5061bdd2cac85"
dependencies = [
"memchr",
"unicode-segmentation",
]
[[package]]
name = "num"
version = "0.4.3"
@ -6323,6 +6333,7 @@ dependencies = [
"mlua",
"mux",
"mux-lua",
"nucleo-matcher",
"once_cell",
"ordered-float",
"parking_lot 0.12.3",

View File

@ -34,6 +34,8 @@ As features stabilize some brief notes about them will accumulate here.
drawing glyphs. See
[custom_block_glyphs](config/lua/config/custom_block_glyphs.md) for more
details. Thanks to @stribor14! #5051 #5169
* Switched to the [nucleo](https://github.com/helix-editor/nucleo) fuzzy
matcher for `CharSelect`. #5532
#### New
* [wezterm.serde](config/lua/wezterm.serde/index.md) module for serialization

View File

@ -54,6 +54,7 @@ finl_unicode = "1.2"
frecency = { path = "../frecency" }
futures = "0.3"
fuzzy-matcher = "0.3"
nucleo-matcher = "0.3"
hdrhistogram = "7.1"
http_req = "0.11"
image = "0.25"

View File

@ -13,8 +13,7 @@ use config::keyassignment::{
use config::Dimension;
use emojis::{Emoji, Group};
use frecency::Frecency;
use fuzzy_matcher::skim::SkimMatcherV2;
use fuzzy_matcher::FuzzyMatcher;
use nucleo_matcher::{Matcher, Utf32Str};
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
@ -244,18 +243,18 @@ fn build_aliases() -> Vec<Alias> {
#[derive(Debug, Copy, Clone)]
struct MatchResult {
row_idx: usize,
score: i64,
score: u32,
}
impl MatchResult {
fn new(row_idx: usize, score: i64, selection: &str, aliases: &[Alias]) -> Self {
fn new(row_idx: usize, score: u32, selection: &str, aliases: &[Alias]) -> Self {
Self {
row_idx,
score: if aliases[row_idx].name == selection {
// Pump up the score for an exact match, otherwise
// the order may be undesirable if there are a lot
// of candidates with the same score
i64::max_value()
u32::max_value()
} else {
score
},
@ -272,7 +271,11 @@ fn compute_matches(selection: &str, aliases: &[Alias], group: CharSelectGroup) -
.map(|(idx, _a)| idx)
.collect()
} else {
let matcher = SkimMatcherV2::default();
let pattern = nucleo_matcher::pattern::Pattern::parse(
selection,
nucleo_matcher::pattern::CaseMatching::Ignore,
nucleo_matcher::pattern::Normalization::Smart,
);
let numeric_selection = if selection.chars().all(|c| c.is_ascii_hexdigit()) {
// Make this uppercase so that eg: `e1` matches `U+E1` rather
@ -285,14 +288,24 @@ fn compute_matches(selection: &str, aliases: &[Alias], group: CharSelectGroup) -
None
};
let start = std::time::Instant::now();
let all_matches: Vec<(String, MatchResult)> = aliases
.par_iter()
.enumerate()
.filter_map(|(row_idx, entry)| {
thread_local! {
static MATCHER: RefCell<Matcher> = RefCell::new(Matcher::new(nucleo_matcher::Config::DEFAULT));
}
let glyph = entry.glyph();
let alias_result = matcher
.fuzzy_match(&entry.name, selection)
.map(|score| MatchResult::new(row_idx, score, selection, aliases));
let alias_result = MATCHER.with_borrow_mut(|matcher| {
let mut buf = vec![];
pattern
.score(Utf32Str::new(&entry.name, &mut buf), matcher)
.map(|score| MatchResult::new(row_idx, score , selection, aliases))
});
match &numeric_selection {
Some(sel) => {
let codepoints = entry.codepoints();
@ -301,13 +314,15 @@ fn compute_matches(selection: &str, aliases: &[Alias], group: CharSelectGroup) -
glyph,
MatchResult {
row_idx,
score: i64::max_value(),
score: u32::max_value(),
},
))
} else {
let number_result = matcher
.fuzzy_match(&codepoints, &sel)
.map(|score| MatchResult::new(row_idx, score, sel, aliases));
let number_result = MATCHER.with_borrow_mut(|matcher| {
let mut buf = vec![];
pattern
.score(Utf32Str::new(&codepoints, &mut buf), matcher)
.map(|score| MatchResult::new(row_idx, score , selection, aliases))});
match (alias_result, number_result) {
(