summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpiegames <git@piegames.de>2021-11-12 18:39:03 +0100
committerAndrew Gallant <jamslam@gmail.com>2023-07-08 18:52:42 -0400
commit4993d29a16b26b016b498765cc5636e73b479367 (patch)
tree260402fd9ed1ddec1f55bc0c1653d3d023aee1a5
parent23adbd6795d4b0a7fbbb606d58fa82e3df0dabc2 (diff)
globset: add 'escape' routine
Fixes #2060, Closes #2061
-rw-r--r--crates/globset/src/glob.rs20
-rw-r--r--crates/globset/src/lib.rs35
2 files changed, 49 insertions, 6 deletions
diff --git a/crates/globset/src/glob.rs b/crates/globset/src/glob.rs
index e025ddf9..cda39cab 100644
--- a/crates/globset/src/glob.rs
+++ b/crates/globset/src/glob.rs
@@ -639,9 +639,9 @@ impl<'a> GlobBuilder<'a> {
}
/// Toggle whether an empty pattern in a list of alternates is accepted.
- ///
+ ///
/// For example, if this is set then the glob `foo{,.txt}` will match both `foo` and `foo.txt`.
- ///
+ ///
/// By default this is false.
pub fn empty_alternates(&mut self, yes: bool) -> &mut GlobBuilder<'a> {
self.opts.empty_alternates = yes;
@@ -1222,12 +1222,20 @@ mod tests {
Options { casei: Some(true), litsep: None, bsesc: None, ealtre: None };
const SLASHLIT: Options =
Options { casei: None, litsep: Some(true), bsesc: None, ealtre: None };
- const NOBSESC: Options =
- Options { casei: None, litsep: None, bsesc: Some(false), ealtre: None };
+ const NOBSESC: Options = Options {
+ casei: None,
+ litsep: None,
+ bsesc: Some(false),
+ ealtre: None,
+ };
const BSESC: Options =
Options { casei: None, litsep: None, bsesc: Some(true), ealtre: None };
- const EALTRE: Options =
- Options { casei: None, litsep: None, bsesc: Some(true), ealtre: Some(true) };
+ const EALTRE: Options = Options {
+ casei: None,
+ litsep: None,
+ bsesc: Some(true),
+ ealtre: Some(true),
+ };
toregex!(re_casei, "a", "(?i)^a$", &CASEI);
diff --git a/crates/globset/src/lib.rs b/crates/globset/src/lib.rs
index dca0f7e0..7a357489 100644
--- a/crates/globset/src/lib.rs
+++ b/crates/globset/src/lib.rs
@@ -880,6 +880,29 @@ impl RequiredExtensionStrategyBuilder {
}
}
+/// Escape meta-characters within the given glob pattern.
+///
+/// The escaping works by surrounding meta-characters with brackets. For
+/// example, `*` becomes `[*]`.
+pub fn escape(s: &str) -> String {
+ let mut escaped = String::with_capacity(s.len());
+ for c in s.chars() {
+ match c {
+ // note that ! does not need escaping because it is only special
+ // inside brackets
+ '?' | '*' | '[' | ']' => {
+ escaped.push('[');
+ escaped.push(c);
+ escaped.push(']');
+ }
+ c => {
+ escaped.push(c);
+ }
+ }
+ }
+ escaped
+}
+
#[cfg(test)]
mod tests {
use super::{GlobSet, GlobSetBuilder};
@@ -919,4 +942,16 @@ mod tests {
assert!(!set.is_match(""));
assert!(!set.is_match("a"));
}
+
+ #[test]
+ fn escape() {
+ use super::escape;
+ assert_eq!("foo", escape("foo"));
+ assert_eq!("foo[*]", escape("foo*"));
+ assert_eq!("[[][]]", escape("[]"));
+ assert_eq!("[*][?]", escape("*?"));
+ assert_eq!("src/[*][*]/[*].rs", escape("src/**/*.rs"));
+ assert_eq!("bar[[]ab[]]baz", escape("bar[ab]baz"));
+ assert_eq!("bar[[]!![]]!baz", escape("bar[!!]!baz"));
+ }
}