Skip to content

Commit 65a4e78

Browse files
committed
feat: add str::precompose_bstr() for convenience
1 parent 9cd6d64 commit 65a4e78

File tree

5 files changed

+54
-6
lines changed

5 files changed

+54
-6
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gix-pathspec/src/search/matching.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ impl Search {
129129
///
130130
/// This is useful if `relative_path` is a directory leading up to the item that is going to be matched in full later.
131131
/// Note that it should not end with `/` to indicate it's a directory, rather, use `is_dir` to indicate this.
132-
/// `is_dir` is `true` if `relative_path` is a directory, or assumed `false` if `None`.
132+
/// `is_dir` is `true` if `relative_path` is a directory. If `None`, the fact that a pathspec might demand a directory match
133+
/// is ignored.
133134
/// Returns `false` if this pathspec has no chance of ever matching `relative_path`.
134135
pub fn can_match_relative_path(&self, relative_path: &BStr, is_dir: Option<bool>) -> bool {
135136
if self.patterns.is_empty() {
@@ -163,7 +164,9 @@ impl Search {
163164
if is_match {
164165
is_match = if common_len < max_usable_pattern_len {
165166
pattern.path.get(common_len) == Some(&b'/')
166-
} else if relative_path.len() > max_usable_pattern_len {
167+
} else if relative_path.len() > max_usable_pattern_len
168+
&& mapping.pattern.first_wildcard_pos.is_none()
169+
{
167170
relative_path.get(common_len) == Some(&b'/')
168171
} else {
169172
is_match

gix-pathspec/tests/search/mod.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,31 @@ fn simplified_search_wildcards() -> crate::Result {
218218
Ok(())
219219
}
220220

221+
#[test]
222+
fn simplified_search_wildcards_simple() -> crate::Result {
223+
let search = gix_pathspec::Search::from_specs(pathspecs(&["dir/*"]), None, Path::new(""))?;
224+
for is_dir in [None, Some(false), Some(true)] {
225+
assert!(
226+
!search.can_match_relative_path("a".into(), is_dir),
227+
"definitely out of bound"
228+
);
229+
assert!(
230+
!search.can_match_relative_path("di".into(), is_dir),
231+
"prefix is not enough"
232+
);
233+
assert!(
234+
search.can_match_relative_path("dir".into(), is_dir),
235+
"directories can match"
236+
);
237+
assert!(
238+
search.can_match_relative_path("dir/file".into(), is_dir),
239+
"substrings can also match"
240+
);
241+
}
242+
243+
Ok(())
244+
}
245+
221246
#[test]
222247
fn simplified_search_handles_nil() -> crate::Result {
223248
let search = gix_pathspec::Search::from_specs(pathspecs(&[":"]), None, Path::new(""))?;

gix-utils/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ include = ["src/**/*", "LICENSE-*"]
1212
[lib]
1313
doctest = false
1414

15+
[features]
16+
bstr = ["dep:bstr"]
17+
1518
[dependencies]
1619
fastrand = "2.0.0"
20+
bstr = { version = "1.5.0", default-features = false, features = ["std"], optional = true }
1721
unicode-normalization = { version = "0.1.19", default-features = false }
1822

gix-utils/src/str.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,26 @@ pub fn precompose_path(path: Cow<'_, Path>) -> Cow<'_, Path> {
4242
/// Return the precomposed version of `name`, or `name` itself if it contained illformed unicode,
4343
/// or if the unicode version didn't contains decomposed unicode.
4444
/// Otherwise, similar to [`precompose()`]
45-
pub fn precompose_os_string(path: Cow<'_, OsStr>) -> Cow<'_, OsStr> {
46-
match path.to_str() {
47-
None => path,
45+
pub fn precompose_os_string(name: Cow<'_, OsStr>) -> Cow<'_, OsStr> {
46+
match name.to_str() {
47+
None => name,
4848
Some(maybe_decomposed) => match precompose(maybe_decomposed.into()) {
49-
Cow::Borrowed(_) => path,
49+
Cow::Borrowed(_) => name,
50+
Cow::Owned(precomposed) => Cow::Owned(precomposed.into()),
51+
},
52+
}
53+
}
54+
55+
/// Return the precomposed version of `s`, or `s` itself if it contained illformed unicode,
56+
/// or if the unicode version didn't contains decomposed unicode.
57+
/// Otherwise, similar to [`precompose()`]
58+
#[cfg(feature = "bstr")]
59+
pub fn precompose_bstr(s: Cow<'_, bstr::BStr>) -> Cow<'_, bstr::BStr> {
60+
use bstr::ByteSlice;
61+
match s.to_str().ok() {
62+
None => s,
63+
Some(maybe_decomposed) => match precompose(maybe_decomposed.into()) {
64+
Cow::Borrowed(_) => s,
5065
Cow::Owned(precomposed) => Cow::Owned(precomposed.into()),
5166
},
5267
}

0 commit comments

Comments
 (0)