Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 20 additions & 20 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 30 additions & 5 deletions libixx/src/string_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,52 @@ impl Display for StringView<'_, '_> {
impl StringView<'_, '_> {
pub fn matches(&self, search: &[Vec<&[u8]>]) -> Result<bool, IxxError> {
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 {
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);
}
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;
}
}

Expand Down
67 changes: 67 additions & 0 deletions libixx/src/test/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,70 @@ 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.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.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.enable", 10).unwrap(),
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![]
);
}
Loading