diff --git a/src/commands/ls.rs b/src/commands/ls.rs index b108a53c0c..6bc2daa28d 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -8,6 +8,7 @@ pub struct LS; #[derive(Deserialize)] pub struct LsArgs { path: Option>, + full: bool, } impl WholeStreamCommand for LS { @@ -16,11 +17,13 @@ impl WholeStreamCommand for LS { } fn signature(&self) -> Signature { - Signature::build("ls").optional( - "path", - SyntaxShape::Pattern, - "a path to get the directory contents from", - ) + Signature::build("ls") + .optional( + "path", + SyntaxShape::Pattern, + "a path to get the directory contents from", + ) + .switch("full", "list all available columns for each entry") } fn usage(&self) -> &str { @@ -37,6 +40,6 @@ impl WholeStreamCommand for LS { } } -fn ls(LsArgs { path }: LsArgs, context: RunnableContext) -> Result { - context.shell_manager.ls(path, &context) +fn ls(LsArgs { path, full }: LsArgs, context: RunnableContext) -> Result { + context.shell_manager.ls(path, &context, full) } diff --git a/src/data/files.rs b/src/data/files.rs index 47c6ae093f..1e565ece37 100644 --- a/src/data/files.rs +++ b/src/data/files.rs @@ -13,6 +13,7 @@ pub(crate) fn dir_entry_dict( filename: &std::path::Path, metadata: &std::fs::Metadata, tag: impl Into, + full: bool, ) -> Result, ShellError> { let mut dict = TaggedDictBuilder::new(tag); dict.insert("name", Value::string(filename.to_string_lossy())); @@ -26,10 +27,19 @@ pub(crate) fn dir_entry_dict( }; dict.insert("type", Value::string(format!("{:?}", kind))); - dict.insert( - "readonly", - Value::boolean(metadata.permissions().readonly()), - ); + + if full { + dict.insert( + "readonly", + Value::boolean(metadata.permissions().readonly()), + ); + + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + dict.insert("mode", Value::int(metadata.permissions().mode())); + } + } dict.insert("size", Value::bytes(metadata.len() as u64)); diff --git a/src/parser/hir/baseline_parse/tests.rs b/src/parser/hir/baseline_parse/tests.rs index c930fbe56c..6ca653c1b2 100644 --- a/src/parser/hir/baseline_parse/tests.rs +++ b/src/parser/hir/baseline_parse/tests.rs @@ -1,12 +1,13 @@ use crate::commands::classified::InternalCommand; use crate::commands::ClassifiedCommand; use crate::env::host::BasicHost; -use crate::parser::hir; use crate::parser::hir::syntax_shape::*; use crate::parser::hir::TokensIterator; +use crate::parser::hir::{self, named::NamedValue, NamedArguments}; use crate::parser::parse::token_tree_builder::{CurriedToken, TokenTreeBuilder as b}; use crate::parser::TokenNode; use crate::{HasSpan, Span, SpannedItem, Tag, Text}; +use indexmap::IndexMap; use pretty_assertions::assert_eq; use std::fmt::Debug; @@ -67,6 +68,9 @@ fn test_parse_command() { eprintln!("{:?} {:?} {:?}", bare, pat, bare.until(pat)); + let mut map = IndexMap::new(); + map.insert("full".to_string(), NamedValue::AbsentSwitch); + ClassifiedCommand::Internal(InternalCommand::new( "ls".to_string(), Tag { @@ -76,7 +80,7 @@ fn test_parse_command() { hir::Call { head: Box::new(hir::RawExpression::Command(bare).spanned(bare)), positional: Some(vec![hir::Expression::pattern("*.txt", pat)]), - named: None, + named: Some(NamedArguments { named: map }), } .spanned(bare.until(pat)), )) diff --git a/src/shell/filesystem_shell.rs b/src/shell/filesystem_shell.rs index 60d5135d11..1b8ee3387c 100644 --- a/src/shell/filesystem_shell.rs +++ b/src/shell/filesystem_shell.rs @@ -86,6 +86,7 @@ impl Shell for FilesystemShell { &self, pattern: Option>, context: &RunnableContext, + full: bool, ) -> Result { let cwd = self.path(); let mut full_path = PathBuf::from(self.path()); @@ -136,7 +137,7 @@ impl Shell for FilesystemShell { Path::new(&filepath) }; - let value = dir_entry_dict(filename, &metadata, &name_tag)?; + let value = dir_entry_dict(filename, &metadata, &name_tag, full)?; yield ReturnSuccess::value(value); } } @@ -175,7 +176,7 @@ impl Shell for FilesystemShell { Path::new(&entry) }; - if let Ok(value) = dir_entry_dict(filename, &metadata, &name_tag) { + if let Ok(value) = dir_entry_dict(filename, &metadata, &name_tag, full) { yield ReturnSuccess::value(value); } } diff --git a/src/shell/help_shell.rs b/src/shell/help_shell.rs index 7c0e74bde4..88b4b3f344 100644 --- a/src/shell/help_shell.rs +++ b/src/shell/help_shell.rs @@ -129,6 +129,7 @@ impl Shell for HelpShell { &self, _pattern: Option>, _context: &RunnableContext, + _full: bool, ) -> Result { Ok(self .commands() diff --git a/src/shell/shell.rs b/src/shell/shell.rs index 507fc0517b..6f76838ad4 100644 --- a/src/shell/shell.rs +++ b/src/shell/shell.rs @@ -16,6 +16,7 @@ pub trait Shell: std::fmt::Debug { &self, pattern: Option>, context: &RunnableContext, + full: bool, ) -> Result; fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result; fn cp(&self, args: CopyArgs, name: Tag, path: &str) -> Result; diff --git a/src/shell/shell_manager.rs b/src/shell/shell_manager.rs index 149fdd58d1..247ba6ca5d 100644 --- a/src/shell/shell_manager.rs +++ b/src/shell/shell_manager.rs @@ -127,10 +127,11 @@ impl ShellManager { &self, path: Option>, context: &RunnableContext, + full: bool, ) -> Result { let env = self.shells.lock().unwrap(); - env[self.current_shell()].ls(path, context) + env[self.current_shell()].ls(path, context, full) } pub fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result { diff --git a/src/shell/value_shell.rs b/src/shell/value_shell.rs index 0aa9e341bb..bc057e1e19 100644 --- a/src/shell/value_shell.rs +++ b/src/shell/value_shell.rs @@ -90,6 +90,7 @@ impl Shell for ValueShell { &self, target: Option>, context: &RunnableContext, + _full: bool, ) -> Result { let mut full_path = PathBuf::from(self.path()); let name_tag = context.name.clone();