Create nu_glob::is_glob function (#14717)

# Description

Adds an `is_glob` function to the nu-glob crate that takes a string
pattern and returns whether or not it's a glob that would be expanded by
nu-glob. Right now, this just means checking if it contains `*`, `?`, or
`[`.

Previously, this same code was duplicated in the following places:
- `ls`: Determining whether to read a folder's contents or expand a glob
- `run_external.rs` in nu-command: Arguments to externals only have
n-dots and tilde expansion applied if they weren't globs
- `glob_from` in nu-engine:
  - `glob_from` can get the prefix in a simpler way for non-globs
- If the canonical path for a non-glob path contains glob
metacharacters, it needs to be escaped
- `completion_common.rs` in nu-cli: File/folder completions containing
glob metacharacters need to be wrapped in quotes

All of these locations can use `nu_glob::is_glob` now instead of rolling
their own checks. This does mean that nu-cli now has a dependency on
nu-glob.

# User-Facing Changes

Users of nu-glob will now be able to check if a given pattern is a glob
expanded by nu-glob.

For users of Nushell, completion suggestions for files containing `]`
will no longer be wrapped in quotes if they contain no other glob
metacharacters. This is because unmatched `]`s are ignored by nu-glob,
but we used to consider such file completions contaminated anyway.

# Tests + Formatting

This is a very basic function, so I just added some doctests.

# After Submitting

This is meant to be used in
https://github.com/nushell/nushell/pull/14674.
This commit is contained in:
Yash Thakur
2025-01-01 19:04:17 -05:00
committed by GitHub
parent f69b22f00b
commit 62bd6fe08b
7 changed files with 31 additions and 15 deletions

View File

@ -6,8 +6,6 @@ use std::{
path::{Component, Path, PathBuf},
};
const GLOB_CHARS: &[char] = &['*', '?', '['];
/// This function is like `nu_glob::glob` from the `glob` crate, except it is relative to a given cwd.
///
/// It returns a tuple of two values: the first is an optional prefix that the expanded filenames share.
@ -29,7 +27,7 @@ pub fn glob_from(
ShellError,
> {
let no_glob_for_pattern = matches!(pattern.item, NuGlob::DoNotExpand(_));
let (prefix, pattern) = if pattern.item.as_ref().contains(GLOB_CHARS) {
let (prefix, pattern) = if nu_glob::is_glob(pattern.item.as_ref()) {
// Pattern contains glob, split it
let mut p = PathBuf::new();
let path = PathBuf::from(&pattern.item.as_ref());
@ -38,7 +36,7 @@ pub fn glob_from(
for c in components {
if let Component::Normal(os) = c {
if os.to_string_lossy().contains(GLOB_CHARS) {
if nu_glob::is_glob(os.to_string_lossy().as_ref()) {
break;
}
}
@ -73,8 +71,8 @@ pub fn glob_from(
(path.parent().map(|parent| parent.to_path_buf()), path)
} else {
let path = if let Ok(p) = canonicalize_with(path.clone(), cwd) {
if p.to_string_lossy().contains(GLOB_CHARS) {
// our path might contains GLOB_CHARS too
if nu_glob::is_glob(p.to_string_lossy().as_ref()) {
// our path might contain glob metacharacters too.
// in such case, we need to escape our path to make
// glob work successfully
PathBuf::from(nu_glob::Pattern::escape(&p.to_string_lossy()))