forked from extern/nushell
parent
f5519e2a09
commit
0769e9b750
@ -19,6 +19,7 @@ const GLOB_PARAMS: nu_glob::MatchOptions = nu_glob::MatchOptions {
|
||||
case_sensitive: true,
|
||||
require_literal_separator: false,
|
||||
require_literal_leading_dot: false,
|
||||
recursive_match_hidden_dir: true,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -3,6 +3,7 @@ use crate::DirInfo;
|
||||
use chrono::{DateTime, Local, LocalResult, TimeZone, Utc};
|
||||
use nu_engine::env::current_dir;
|
||||
use nu_engine::CallExt;
|
||||
use nu_glob::MatchOptions;
|
||||
use nu_path::expand_to_real_path;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
@ -128,7 +129,15 @@ impl Command for Ls {
|
||||
item: path.display().to_string(),
|
||||
span: p_tag,
|
||||
};
|
||||
let (prefix, paths) = nu_engine::glob_from(&glob_path, &cwd, call_span)?;
|
||||
|
||||
let glob_options = if all {
|
||||
None
|
||||
} else {
|
||||
let mut glob_options = MatchOptions::new();
|
||||
glob_options.recursive_match_hidden_dir = false;
|
||||
Some(glob_options)
|
||||
};
|
||||
let (prefix, paths) = nu_engine::glob_from(&glob_path, &cwd, call_span, glob_options)?;
|
||||
|
||||
let mut paths_peek = paths.peekable();
|
||||
if paths_peek.peek().is_none() {
|
||||
|
@ -14,6 +14,7 @@ const GLOB_PARAMS: nu_glob::MatchOptions = nu_glob::MatchOptions {
|
||||
case_sensitive: true,
|
||||
require_literal_separator: false,
|
||||
require_literal_leading_dot: false,
|
||||
recursive_match_hidden_dir: true,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -24,6 +24,7 @@ const GLOB_PARAMS: nu_glob::MatchOptions = nu_glob::MatchOptions {
|
||||
case_sensitive: true,
|
||||
require_literal_separator: false,
|
||||
require_literal_leading_dot: false,
|
||||
recursive_match_hidden_dir: true,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -14,6 +14,7 @@ const GLOB_PARAMS: MatchOptions = MatchOptions {
|
||||
case_sensitive: true,
|
||||
require_literal_separator: true,
|
||||
require_literal_leading_dot: false,
|
||||
recursive_match_hidden_dir: true,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -417,7 +417,9 @@ impl ExternalCommand {
|
||||
let cwd = PathBuf::from(cwd);
|
||||
|
||||
if arg.item.contains('*') {
|
||||
if let Ok((prefix, matches)) = nu_engine::glob_from(&arg, &cwd, self.name.span) {
|
||||
if let Ok((prefix, matches)) =
|
||||
nu_engine::glob_from(&arg, &cwd, self.name.span, None)
|
||||
{
|
||||
let matches: Vec<_> = matches.collect();
|
||||
|
||||
// FIXME: do we want to special-case this further? We might accidentally expand when they don't
|
||||
|
@ -244,6 +244,42 @@ fn lists_all_hidden_files_when_glob_does_not_contain_dot() {
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
// TODO Remove this cfg value when we have an OS-agnostic way
|
||||
// of creating hidden files using the playground.
|
||||
#[cfg(unix)]
|
||||
fn glob_with_hidden_directory() {
|
||||
Playground::setup("ls_test_8", |dirs, sandbox| {
|
||||
sandbox.within(".dir_b").with_files(vec![
|
||||
EmptyFile("andres.10.txt"),
|
||||
EmptyFile("chicken_not_to_be_picked_up.100.txt"),
|
||||
EmptyFile(".dotfile3"),
|
||||
]);
|
||||
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
ls **/*
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
assert_eq!(actual.out, "");
|
||||
assert!(actual.err.contains("No matches found"));
|
||||
|
||||
// will list files if provide `-a` flag.
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
ls -a **/*
|
||||
| length
|
||||
"#
|
||||
));
|
||||
|
||||
assert_eq!(actual.out, "4");
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn fails_with_ls_to_dir_without_permission() {
|
||||
|
@ -2,6 +2,7 @@
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
|
||||
use nu_glob::MatchOptions;
|
||||
use nu_path::{canonicalize_with, expand_path_with};
|
||||
use nu_protocol::{ShellError, Span, Spanned};
|
||||
|
||||
@ -17,6 +18,7 @@ pub fn glob_from(
|
||||
pattern: &Spanned<String>,
|
||||
cwd: &Path,
|
||||
span: Span,
|
||||
options: Option<MatchOptions>,
|
||||
) -> Result<
|
||||
(
|
||||
Option<PathBuf>,
|
||||
@ -82,8 +84,9 @@ pub fn glob_from(
|
||||
};
|
||||
|
||||
let pattern = pattern.to_string_lossy().to_string();
|
||||
let glob_options = options.unwrap_or_else(MatchOptions::new);
|
||||
|
||||
let glob = nu_glob::glob(&pattern).map_err(|err| {
|
||||
let glob = nu_glob::glob_with(&pattern, glob_options).map_err(|err| {
|
||||
nu_protocol::ShellError::GenericError(
|
||||
"Error extracting glob pattern".into(),
|
||||
err.to_string(),
|
||||
|
@ -49,6 +49,7 @@
|
||||
//! case_sensitive: false,
|
||||
//! require_literal_separator: false,
|
||||
//! require_literal_leading_dot: false,
|
||||
//! recursive_match_hidden_dir: true,
|
||||
//! };
|
||||
//! for entry in glob_with("local/*a*", options).unwrap() {
|
||||
//! if let Ok(path) = entry {
|
||||
@ -376,7 +377,16 @@ impl Iterator for Paths {
|
||||
}
|
||||
|
||||
if is_dir(&path) {
|
||||
// the path is a directory, so it's a match
|
||||
// the path is a directory, check if matched according
|
||||
// to `hidden_dir_recursive` option.
|
||||
if !self.options.recursive_match_hidden_dir
|
||||
&& path
|
||||
.file_name()
|
||||
.map(|name| name.to_string_lossy().starts_with('.'))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// push this directory's contents
|
||||
fill_todo(
|
||||
@ -872,6 +882,10 @@ pub struct MatchOptions {
|
||||
/// conventionally considered hidden on Unix systems and it might be
|
||||
/// desirable to skip them when listing files.
|
||||
pub require_literal_leading_dot: bool,
|
||||
|
||||
/// if given pattern contains `**`, this flag check if `**` matches hidden directory.
|
||||
/// For example: if true, `**` will match `.abcdef/ghi`.
|
||||
pub recursive_match_hidden_dir: bool,
|
||||
}
|
||||
|
||||
impl MatchOptions {
|
||||
@ -886,6 +900,7 @@ impl MatchOptions {
|
||||
/// case_sensitive: true,
|
||||
/// require_literal_separator: false,
|
||||
/// require_literal_leading_dot: false
|
||||
/// recursive_match_hidden_dir: true,
|
||||
/// }
|
||||
/// ```
|
||||
pub fn new() -> Self {
|
||||
@ -893,6 +908,7 @@ impl MatchOptions {
|
||||
case_sensitive: true,
|
||||
require_literal_separator: false,
|
||||
require_literal_leading_dot: false,
|
||||
recursive_match_hidden_dir: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1084,6 +1100,7 @@ mod test {
|
||||
case_sensitive: false,
|
||||
require_literal_separator: false,
|
||||
require_literal_leading_dot: false,
|
||||
recursive_match_hidden_dir: true,
|
||||
};
|
||||
|
||||
assert!(pat.matches_with("aBcDeFg", options));
|
||||
@ -1098,11 +1115,13 @@ mod test {
|
||||
case_sensitive: true,
|
||||
require_literal_separator: true,
|
||||
require_literal_leading_dot: false,
|
||||
recursive_match_hidden_dir: true,
|
||||
};
|
||||
let options_not_require_literal = MatchOptions {
|
||||
case_sensitive: true,
|
||||
require_literal_separator: false,
|
||||
require_literal_leading_dot: false,
|
||||
recursive_match_hidden_dir: true,
|
||||
};
|
||||
|
||||
assert!(Pattern::new("abc/def")
|
||||
@ -1132,11 +1151,13 @@ mod test {
|
||||
case_sensitive: true,
|
||||
require_literal_separator: false,
|
||||
require_literal_leading_dot: true,
|
||||
recursive_match_hidden_dir: true,
|
||||
};
|
||||
let options_not_require_literal_leading_dot = MatchOptions {
|
||||
case_sensitive: true,
|
||||
require_literal_separator: false,
|
||||
require_literal_leading_dot: false,
|
||||
recursive_match_hidden_dir: true,
|
||||
};
|
||||
|
||||
let f = |options| {
|
||||
|
Loading…
Reference in New Issue
Block a user