diff --git a/src/commands/ls.rs b/src/commands/ls.rs index 000186ac95..9583ed99ca 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -1,46 +1,73 @@ use crate::errors::ShellError; -use crate::object::{dir_entry_dict, Primitive, Value}; +use crate::object::dir_entry_dict; use crate::prelude::*; use std::path::{Path, PathBuf}; pub fn ls(args: CommandArgs) -> Result { let env = args.env.lock().unwrap(); let path = env.path.to_path_buf(); + let cwd = path.clone(); let mut full_path = PathBuf::from(path); match &args.nth(0) { - Some(Tagged { - item: Value::Primitive(Primitive::String(s)), - .. - }) => full_path.push(Path::new(&s)), + Some(Tagged { item: value, .. }) => full_path.push(Path::new(&value.as_string()?)), _ => {} } - let entries = std::fs::read_dir(&full_path); + let entries = glob::glob(&full_path.to_string_lossy()); - let entries = match entries { - Err(e) => { - if let Some(s) = args.nth(0) { - return Err(ShellError::labeled_error( - e.to_string(), - e.to_string(), - s.span(), - )); - } else { - return Err(ShellError::maybe_labeled_error( - e.to_string(), - e.to_string(), - args.call_info.name_span, - )); - } - } - Ok(o) => o, - }; + if entries.is_err() { + return Err(ShellError::string("Invalid pattern.")); + } let mut shell_entries = VecDeque::new(); + let entries: Vec<_> = entries.unwrap().collect(); - for entry in entries { - let value = dir_entry_dict(&entry?, args.call_info.name_span)?; - shell_entries.push_back(ReturnSuccess::value(value)) + // If this is a single entry, try to display the contents of the entry if it's a directory + if entries.len() == 1 { + if let Ok(entry) = &entries[0] { + if entry.is_dir() { + let entries = std::fs::read_dir(&full_path); + + let entries = match entries { + Err(e) => { + if let Some(s) = args.nth(0) { + return Err(ShellError::labeled_error( + e.to_string(), + e.to_string(), + s.span(), + )); + } else { + return Err(ShellError::maybe_labeled_error( + e.to_string(), + e.to_string(), + args.call_info.name_span, + )); + } + } + Ok(o) => o, + }; + for entry in entries { + let entry = entry?; + let filepath = entry.path(); + let filename = filepath.strip_prefix(&cwd).unwrap(); + let value = + dir_entry_dict(filename, &entry.metadata()?, args.call_info.name_span)?; + shell_entries.push_back(ReturnSuccess::value(value)) + } + return Ok(shell_entries.to_output_stream()); + } + } } + + // Enumerate the entries from the glob and add each + for entry in entries { + if let Ok(entry) = entry { + let filename = entry.strip_prefix(&cwd).unwrap(); + let metadata = std::fs::metadata(&entry)?; + let value = dir_entry_dict(filename, &metadata, args.call_info.name_span)?; + shell_entries.push_back(ReturnSuccess::value(value)) + } + } + Ok(shell_entries.to_output_stream()) } diff --git a/src/object/files.rs b/src/object/files.rs index 94fe1dde3b..8cc7c878d5 100644 --- a/src/object/files.rs +++ b/src/object/files.rs @@ -10,15 +10,13 @@ pub enum FileType { } crate fn dir_entry_dict( - entry: &std::fs::DirEntry, + filename: &std::path::Path, + metadata: &std::fs::Metadata, span: impl Into, ) -> Result, ShellError> { let mut dict = TaggedDictBuilder::new(span); - let filename = entry.file_name(); dict.insert("name", Value::string(filename.to_string_lossy())); - let metadata = entry.metadata()?; - let kind = if metadata.is_dir() { FileType::Directory } else if metadata.is_file() {