From 63b7b2219f4595973225a13e6e664fc836ee305c Mon Sep 17 00:00:00 2001 From: Liam Dyer Date: Mon, 21 Oct 2024 18:00:19 -0400 Subject: [PATCH] feat: expose typo resistance, update frizbee --- Cargo.lock | 30 +++++++++++++------------- flake.nix | 2 +- lua/blink/cmp/config.lua | 4 ++++ lua/blink/cmp/fuzzy/fuzzy.rs | 42 +++++++++++++++++++++++++----------- lua/blink/cmp/fuzzy/init.lua | 5 +++-- 5 files changed, 53 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc7d5aa7..c1491a03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,9 +65,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.29" +version = "1.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e804ac3194a48bb129643eb1d62fcc20d18c6b8c181704489353d13120bcd1" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" dependencies = [ "shlex", ] @@ -114,7 +114,7 @@ dependencies = [ [[package]] name = "frizbee" version = "0.1.0" -source = "git+https://github.com/saghen/frizbee#d910bec53b867ce06702520c7e05f9862bf78dd9" +source = "git+https://github.com/saghen/frizbee#005e4438b21a8c1d87967cae8eda4774729d0589" dependencies = [ "memchr", "smith_waterman_macro", @@ -182,9 +182,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "lmdb-master-sys" @@ -236,7 +236,7 @@ checksum = "09697a6cec88e7f58a02c7ab5c18c611c6907c8654613df9cc0192658a4fb859" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -300,7 +300,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -320,9 +320,9 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" dependencies = [ "unicode-ident", ] @@ -409,14 +409,14 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -439,7 +439,7 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "smith_waterman_macro" version = "0.1.0" -source = "git+https://github.com/saghen/frizbee#d910bec53b867ce06702520c7e05f9862bf78dd9" +source = "git+https://github.com/saghen/frizbee#005e4438b21a8c1d87967cae8eda4774729d0589" dependencies = [ "proc-macro2", "quote", @@ -459,9 +459,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ "proc-macro2", "quote", diff --git a/flake.nix b/flake.nix index ede60a96..fac7651c 100644 --- a/flake.nix +++ b/flake.nix @@ -51,7 +51,7 @@ lockFile = ./Cargo.lock; outputHashes = { "frizbee-0.1.0" = - "sha256-zO2S282DVCjnALMXu3GxmAfjCXsPNUZ7+xgiqITfGmU="; + "sha256-/O+XLuRc1/a7FQLnLV8peQ4BfSXoiHvcEGLGE6rbegc="; }; }; }; diff --git a/lua/blink/cmp/config.lua b/lua/blink/cmp/config.lua index 0436bf46..6e2fc3dd 100644 --- a/lua/blink/cmp/config.lua +++ b/lua/blink/cmp/config.lua @@ -71,6 +71,7 @@ --- @field forceVersion? string | nil --- @class blink.cmp.FuzzyConfig +--- @field use_typo_resistance? boolean --- @field use_frecency? boolean --- @field use_proximity? boolean --- @field max_items? number @@ -218,6 +219,9 @@ local config = { }, fuzzy = { + -- when enabled, allows for a number of typos relative to the length of the query + -- disabling this matches the behavior of fzf + use_typo_resistance = false, -- frencency tracks the most recently/frequently used items and boosts the score of the item use_frecency = true, -- proximity bonus boosts the score of items with a value in the buffer diff --git a/lua/blink/cmp/fuzzy/fuzzy.rs b/lua/blink/cmp/fuzzy/fuzzy.rs index 2b5c1855..5dc9eb69 100644 --- a/lua/blink/cmp/fuzzy/fuzzy.rs +++ b/lua/blink/cmp/fuzzy/fuzzy.rs @@ -58,7 +58,9 @@ pub struct MatchedLspItem { #[derive(Clone, Serialize, Deserialize, Hash)] pub struct FuzzyOptions { + use_typo_resistance: bool, use_frecency: bool, + use_proximity: bool, nearby_words: Option>, min_score: u16, max_items: u32, @@ -68,14 +70,18 @@ pub struct FuzzyOptions { impl FromLua<'_> for FuzzyOptions { fn from_lua(value: LuaValue<'_>, _lua: &'_ Lua) -> LuaResult { if let Some(tab) = value.as_table() { + let use_typo_resistance: bool = tab.get("use_typo_resistance").unwrap_or_default(); let use_frecency: bool = tab.get("use_frecency").unwrap_or_default(); + let use_proximity: bool = tab.get("use_proximity").unwrap_or_default(); let nearby_words: Option> = tab.get("nearby_words").ok(); let min_score: u16 = tab.get("min_score").unwrap_or_default(); let max_items: u32 = tab.get("max_items").unwrap_or_default(); let sorts: Vec = tab.get("sorts").unwrap_or_default(); Ok(FuzzyOptions { + use_typo_resistance, use_frecency, + use_proximity, nearby_words, min_score, max_items, @@ -102,9 +108,16 @@ pub fn fuzzy( // Fuzzy match with fzrs let haystack_labels = haystack .iter() - .map(|s| s.label.as_str()) + .map(|s| { + if let Some(filter_text) = &s.filter_text { + filter_text.as_str() + } else { + s.label.as_str() + } + }) .collect::>(); let options = frizbee::Options { + prefilter: !opts.use_typo_resistance, min_score: opts.min_score, stable_sort: false, ..Default::default() @@ -112,7 +125,6 @@ pub fn fuzzy( let mut matches = frizbee::match_list(&needle, &haystack_labels, options); // Sort by scores - // TODO: boost exact matches let match_scores = matches .iter() .map(|mtch| { @@ -121,10 +133,14 @@ pub fn fuzzy( } else { 0 }; - let nearby_words_score = nearby_words - .get(&haystack[mtch.index_in_haystack].label) - .map(|_| 2) - .unwrap_or(0); + let nearby_words_score = if opts.use_proximity { + nearby_words + .get(&haystack[mtch.index_in_haystack].label) + .map(|_| 2) + .unwrap_or(0) + } else { + 0 + }; let score_offset = haystack[mtch.index_in_haystack].score_offset.unwrap_or(0); (mtch.score as i32) + frecency_score + nearby_words_score + score_offset @@ -132,12 +148,14 @@ pub fn fuzzy( .collect::>(); // Find the highest score and filter out matches that are unreasonably lower than it - let max_score = matches.iter().map(|mtch| mtch.score).max().unwrap_or(0); - let secondary_min_score = max_score.max(16) - 16; - matches = matches - .into_iter() - .filter(|mtch| mtch.score >= secondary_min_score) - .collect::>(); + if opts.use_typo_resistance { + let max_score = matches.iter().map(|mtch| mtch.score).max().unwrap_or(0); + let secondary_min_score = max_score.max(16) - 16; + matches = matches + .into_iter() + .filter(|mtch| mtch.score >= secondary_min_score) + .collect::>(); + } // Sort matches by sort criteria for sort in opts.sorts.iter() { diff --git a/lua/blink/cmp/fuzzy/init.lua b/lua/blink/cmp/fuzzy/init.lua index 3e09b9ad..691674ad 100644 --- a/lua/blink/cmp/fuzzy/init.lua +++ b/lua/blink/cmp/fuzzy/init.lua @@ -26,7 +26,7 @@ function fuzzy.access(item) fuzzy.rust.access(item) end function fuzzy.get_words(lines) return fuzzy.rust.get_words(lines) end ---@param needle string ----@param items blink.cmp.CompletionItem[]? +---@param haystack blink.cmp.CompletionItem[]? ---@return blink.cmp.CompletionItem[] function fuzzy.filter_items(needle, haystack) haystack = haystack or {} @@ -44,8 +44,9 @@ function fuzzy.filter_items(needle, haystack) -- each matching char is worth 4 points and it receives a bonus for capitalization, delimiter and prefix -- so this should generally be good -- TODO: make this configurable - min_score = 6 * needle:len(), + min_score = config.fuzzy.use_typo_resistance and (6 * needle:len()) or 0, max_items = config.fuzzy.max_items, + use_typo_resistance = config.fuzzy.use_typo_resistance, use_frecency = config.fuzzy.use_frecency, use_proximity = config.fuzzy.use_proximity, sorts = config.fuzzy.sorts,