From e2822f35a8467a9d294a0a79d85052831089a51c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Thu, 18 Jun 2026 19:51:04 +0200 Subject: [PATCH 1/4] Bump everything --- Cargo.lock | 40 ++++++++++++++++++++-------------------- flake.lock | 6 +++--- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0794a3d..a32aca5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,9 +120,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" dependencies = [ "hybrid-array", ] @@ -141,9 +141,9 @@ checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" [[package]] name = "bytes" -version = "1.11.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" [[package]] name = "cast" @@ -153,9 +153,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.63" +version = "1.2.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" +checksum = "dad887fd958be91b5098c0248def011f4523ab786cd411be668777e55063501f" dependencies = [ "find-msvc-tools", "shlex", @@ -658,9 +658,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" [[package]] name = "num-traits" @@ -794,9 +794,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.3" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" dependencies = [ "aho-corasick", "memchr", @@ -817,9 +817,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "rustversion" @@ -905,9 +905,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "stable_deref_trait" @@ -929,9 +929,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.117" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -1238,18 +1238,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.50" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" +checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.50" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" +checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" dependencies = [ "proc-macro2", "quote", diff --git a/flake.lock b/flake.lock index 96f37ec..225d4a9 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1780243769, - "narHash": "sha256-x5UQuRsH3MqI0U9afaXSNqzTPSeZlRLvFAav2Ux1pNw=", + "lastModified": 1781577229, + "narHash": "sha256-lrp67w8AulE9Ks53n27I45ADSzbOCn4H+CNW1Ck8B+8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "331800de5053fcebacf6813adb5db9c9dca22a0c", + "rev": "567a49d1913ce81ac6e9582e3553dd90a955875f", "type": "github" }, "original": { From b05104e767337c1e817d16c93cee846933e97f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Thu, 18 Jun 2026 19:54:33 +0200 Subject: [PATCH 2/4] Add regression test for https://github.com/NuschtOS/search/issues/339 --- libixx/src/test/search.rs | 56 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/libixx/src/test/search.rs b/libixx/src/test/search.rs index 36253dc..abc4e8c 100644 --- a/libixx/src/test/search.rs +++ b/libixx/src/test/search.rs @@ -73,3 +73,59 @@ fn test() { assert_eq!(index.get_idx_by_name(1, "home.enableDebugInfo"), Some(12)); } + +#[test] +fn test_exact_search() { + let index = Index::build( + vec![ + ("programs.neovim.enable", 0), + ("programs.nixvim.enable", 0), + ("programs.vim.enable", 0), + ] + .as_slice(), + ); + + assert_eq!( + index.search(Some(0), "programs.neovim", 10).unwrap(), + vec![(0, 0, "programs.neovim.enable".to_string())] + ); + assert_eq!( + index.search(Some(0), "programs.neovim*", 10).unwrap(), + vec![(0, 0, "programs.neovim.enable".to_string())] + ); + assert_eq!( + index.search(Some(0), "programs.neovim.enable", 10).unwrap(), + vec![(0, 0, "programs.neovim.enable".to_string())] + ); + + assert_eq!( + index.search(Some(0), "programs.nixvim*", 10).unwrap(), + vec![(1, 0, "programs.nixvim.enable".to_string())] + ); + assert_eq!( + index.search(Some(0), "programs.nixvim", 10).unwrap(), + vec![(1, 0, "programs.nixvim.enable".to_string())] + ); + assert_eq!( + index.search(Some(0), "programs.nixvim.enable", 10).unwrap(), + vec![(1, 0, "programs.nixvim.enable".to_string())] + ); + + assert_eq!( + index.search(Some(0), "programs.vim*", 10).unwrap(), + vec![(2, 0, "programs.vim.enable".to_string())] + ); + assert_eq!( + index.search(Some(0), "programs.vim", 10).unwrap(), + vec![(2, 0, "programs.vim.enable".to_string())] + ); + assert_eq!( + index.search(Some(0), "programs.vim.enable", 10).unwrap(), + vec![(2, 0, "programs.vim.enable".to_string())] + ); + + assert_eq!( + index.search(Some(0), "programs.*vim.enable", 10).unwrap(), + vec![(2, 0, "programs.vim.enable".to_string())] + ); +} From d425e722a0fbc180f640e088c9a0529f9c685150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Thu, 18 Jun 2026 22:24:34 +0200 Subject: [PATCH 3/4] Fix exact-search --- libixx/src/string_view.rs | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/libixx/src/string_view.rs b/libixx/src/string_view.rs index 4a62ade..c0587f3 100644 --- a/libixx/src/string_view.rs +++ b/libixx/src/string_view.rs @@ -35,27 +35,49 @@ impl Display for StringView<'_, '_> { impl StringView<'_, '_> { pub fn matches(&self, search: &[Vec<&[u8]>]) -> Result { let mut self_parts_start = 0; + // byte offset into self.parts[self_parts_start] to resume from let mut self_parts_start_str_idx = 0; + // single-part matches leave self_parts_start on the matched label, + // a subsequent multi-part segment needs to start at the next label + let mut prev_was_single_part = false; for segment in search { - for part in segment { + // for eg: "programs.vim" each dot-component matches a full label exactly + if segment.len() > 1 { + if prev_was_single_part { + self_parts_start += 1; + self_parts_start_str_idx = 0; + + prev_was_single_part = false; + } + for part in segment { + let self_part = self.index.resolve_reference(self.parts[self_parts_start])?; + if !eq_ignore_ascii_case(&self_part.data, part) { + return Ok(false); + } + self_parts_start += 1; + } + } else { + // bare word or trailing wildcard: substring should match across remaining labels + let part = &segment[0]; 'outer: { for (self_part_idx, self_part) in self.parts[self_parts_start..].iter().enumerate() { let self_part = self.index.resolve_reference(*self_part)?; if let Some(idx) = ascii_ignore_case_find(&self_part.data[self_parts_start_str_idx..], part) { self_parts_start += self_part_idx; - if self_part_idx == 0 { - self_parts_start_str_idx += idx; + self_parts_start_str_idx = if self_part_idx == 0 { + self_parts_start_str_idx + idx } else { - self_parts_start_str_idx = 0; - } + idx + }; break 'outer; } self_parts_start_str_idx = 0; } return Ok(false); } + prev_was_single_part = true; } } From 2adb84177617ca711209e910d3923509c1b0118d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Fri, 19 Jun 2026 00:01:09 +0200 Subject: [PATCH 4/4] Fix exact match when segment count exceeds max available segments --- libixx/src/string_view.rs | 3 +++ libixx/src/test/search.rs | 35 +++++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/libixx/src/string_view.rs b/libixx/src/string_view.rs index c0587f3..00a7853 100644 --- a/libixx/src/string_view.rs +++ b/libixx/src/string_view.rs @@ -51,6 +51,9 @@ impl StringView<'_, '_> { prev_was_single_part = false; } for part in segment { + if self_parts_start >= self.parts.len() { + return Ok(false); + } let self_part = self.index.resolve_reference(self.parts[self_parts_start])?; if !eq_ignore_ascii_case(&self_part.data, part) { return Ok(false); diff --git a/libixx/src/test/search.rs b/libixx/src/test/search.rs index abc4e8c..7351145 100644 --- a/libixx/src/test/search.rs +++ b/libixx/src/test/search.rs @@ -89,19 +89,11 @@ fn test_exact_search() { index.search(Some(0), "programs.neovim", 10).unwrap(), vec![(0, 0, "programs.neovim.enable".to_string())] ); - assert_eq!( - index.search(Some(0), "programs.neovim*", 10).unwrap(), - vec![(0, 0, "programs.neovim.enable".to_string())] - ); assert_eq!( index.search(Some(0), "programs.neovim.enable", 10).unwrap(), vec![(0, 0, "programs.neovim.enable".to_string())] ); - assert_eq!( - index.search(Some(0), "programs.nixvim*", 10).unwrap(), - vec![(1, 0, "programs.nixvim.enable".to_string())] - ); assert_eq!( index.search(Some(0), "programs.nixvim", 10).unwrap(), vec![(1, 0, "programs.nixvim.enable".to_string())] @@ -111,10 +103,6 @@ fn test_exact_search() { vec![(1, 0, "programs.nixvim.enable".to_string())] ); - assert_eq!( - index.search(Some(0), "programs.vim*", 10).unwrap(), - vec![(2, 0, "programs.vim.enable".to_string())] - ); assert_eq!( index.search(Some(0), "programs.vim", 10).unwrap(), vec![(2, 0, "programs.vim.enable".to_string())] @@ -124,8 +112,31 @@ fn test_exact_search() { vec![(2, 0, "programs.vim.enable".to_string())] ); + // regression tests that wildcard matching also works as expected + assert_eq!( + index.search(Some(0), "programs.vim*", 10).unwrap(), + vec![(2, 0, "programs.vim.enable".to_string())] + ); assert_eq!( index.search(Some(0), "programs.*vim.enable", 10).unwrap(), vec![(2, 0, "programs.vim.enable".to_string())] ); + assert_eq!( + index.search(Some(0), "programs.neovim*", 10).unwrap(), + vec![(0, 0, "programs.neovim.enable".to_string())] + ); + assert_eq!( + index.search(Some(0), "programs.nixvim*", 10).unwrap(), + vec![(1, 0, "programs.nixvim.enable".to_string())] + ); + + // regression test that no out of bounds happen + assert_eq!( + index.search(Some(0), "programs.vim.enable.extra", 10).unwrap(), + vec![] + ); + assert_eq!( + index.search(Some(0), "programs*vim.enable.extra", 10).unwrap(), + vec![] + ); }