mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-05-19 09:40:22 -07:00
This brings the code in line with my current style. It also inlines the dozen or so lines of code for FNV hashing instead of bringing in a micro-crate for it. Finally, it drops the dependency on regex in favor of using regex-syntax and regex-automata directly.
130 lines
4.0 KiB
Rust
130 lines
4.0 KiB
Rust
use std::borrow::Cow;
|
|
|
|
use bstr::{ByteSlice, ByteVec};
|
|
|
|
/// The final component of the path, if it is a normal file.
|
|
///
|
|
/// If the path terminates in `.`, `..`, or consists solely of a root of
|
|
/// prefix, file_name will return None.
|
|
pub(crate) fn file_name<'a>(path: &Cow<'a, [u8]>) -> Option<Cow<'a, [u8]>> {
|
|
if path.last_byte().map_or(true, |b| b == b'.') {
|
|
return None;
|
|
}
|
|
let last_slash = path.rfind_byte(b'/').map(|i| i + 1).unwrap_or(0);
|
|
Some(match *path {
|
|
Cow::Borrowed(path) => Cow::Borrowed(&path[last_slash..]),
|
|
Cow::Owned(ref path) => {
|
|
let mut path = path.clone();
|
|
path.drain_bytes(..last_slash);
|
|
Cow::Owned(path)
|
|
}
|
|
})
|
|
}
|
|
|
|
/// Return a file extension given a path's file name.
|
|
///
|
|
/// Note that this does NOT match the semantics of std::path::Path::extension.
|
|
/// Namely, the extension includes the `.` and matching is otherwise more
|
|
/// liberal. Specifically, the extension is:
|
|
///
|
|
/// * None, if the file name given is empty;
|
|
/// * None, if there is no embedded `.`;
|
|
/// * Otherwise, the portion of the file name starting with the final `.`.
|
|
///
|
|
/// e.g., A file name of `.rs` has an extension `.rs`.
|
|
///
|
|
/// N.B. This is done to make certain glob match optimizations easier. Namely,
|
|
/// a pattern like `*.rs` is obviously trying to match files with a `rs`
|
|
/// extension, but it also matches files like `.rs`, which doesn't have an
|
|
/// extension according to std::path::Path::extension.
|
|
pub(crate) fn file_name_ext<'a>(
|
|
name: &Cow<'a, [u8]>,
|
|
) -> Option<Cow<'a, [u8]>> {
|
|
if name.is_empty() {
|
|
return None;
|
|
}
|
|
let last_dot_at = match name.rfind_byte(b'.') {
|
|
None => return None,
|
|
Some(i) => i,
|
|
};
|
|
Some(match *name {
|
|
Cow::Borrowed(name) => Cow::Borrowed(&name[last_dot_at..]),
|
|
Cow::Owned(ref name) => {
|
|
let mut name = name.clone();
|
|
name.drain_bytes(..last_dot_at);
|
|
Cow::Owned(name)
|
|
}
|
|
})
|
|
}
|
|
|
|
/// Normalizes a path to use `/` as a separator everywhere, even on platforms
|
|
/// that recognize other characters as separators.
|
|
#[cfg(unix)]
|
|
pub(crate) fn normalize_path(path: Cow<'_, [u8]>) -> Cow<'_, [u8]> {
|
|
// UNIX only uses /, so we're good.
|
|
path
|
|
}
|
|
|
|
/// Normalizes a path to use `/` as a separator everywhere, even on platforms
|
|
/// that recognize other characters as separators.
|
|
#[cfg(not(unix))]
|
|
pub(crate) fn normalize_path(mut path: Cow<[u8]>) -> Cow<[u8]> {
|
|
use std::path::is_separator;
|
|
|
|
for i in 0..path.len() {
|
|
if path[i] == b'/' || !is_separator(char::from(path[i])) {
|
|
continue;
|
|
}
|
|
path.to_mut()[i] = b'/';
|
|
}
|
|
path
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use std::borrow::Cow;
|
|
|
|
use bstr::{ByteVec, B};
|
|
|
|
use super::{file_name_ext, normalize_path};
|
|
|
|
macro_rules! ext {
|
|
($name:ident, $file_name:expr, $ext:expr) => {
|
|
#[test]
|
|
fn $name() {
|
|
let bs = Vec::from($file_name);
|
|
let got = file_name_ext(&Cow::Owned(bs));
|
|
assert_eq!($ext.map(|s| Cow::Borrowed(B(s))), got);
|
|
}
|
|
};
|
|
}
|
|
|
|
ext!(ext1, "foo.rs", Some(".rs"));
|
|
ext!(ext2, ".rs", Some(".rs"));
|
|
ext!(ext3, "..rs", Some(".rs"));
|
|
ext!(ext4, "", None::<&str>);
|
|
ext!(ext5, "foo", None::<&str>);
|
|
|
|
macro_rules! normalize {
|
|
($name:ident, $path:expr, $expected:expr) => {
|
|
#[test]
|
|
fn $name() {
|
|
let bs = Vec::from_slice($path);
|
|
let got = normalize_path(Cow::Owned(bs));
|
|
assert_eq!($expected.to_vec(), got.into_owned());
|
|
}
|
|
};
|
|
}
|
|
|
|
normalize!(normal1, b"foo", b"foo");
|
|
normalize!(normal2, b"foo/bar", b"foo/bar");
|
|
#[cfg(unix)]
|
|
normalize!(normal3, b"foo\\bar", b"foo\\bar");
|
|
#[cfg(not(unix))]
|
|
normalize!(normal3, b"foo\\bar", b"foo/bar");
|
|
#[cfg(unix)]
|
|
normalize!(normal4, b"foo\\bar/baz", b"foo\\bar/baz");
|
|
#[cfg(not(unix))]
|
|
normalize!(normal4, b"foo\\bar/baz", b"foo/bar/baz");
|
|
}
|