config: 🔨 using target enum and vec string for config options

Signed-off-by: zwPapEr <zw.paper@gmail.com>
This commit is contained in:
zwPapEr 2020-11-21 23:40:24 +08:00 committed by Abin Simon
parent 3ef4ec6e81
commit cf9030cdf7
12 changed files with 167 additions and 187 deletions

View file

@ -1,11 +1,16 @@
///! This module provides methods to handle the program's config files and operations related to
///! this.
use crate::flags::color::ColorOption;
use crate::flags::display::Display;
use crate::flags::icons::IconOption;
use crate::flags::layout::Layout;
use crate::flags::size::SizeFlag;
use crate::flags::sorting::{DirGrouping, SortColumn};
use crate::print_error;
use std::path::PathBuf;
use serde::Deserialize;
use serde_yaml::Sequence;
use std::fs;
@ -15,48 +20,51 @@ const YAML_LONG_EXT: &str = "yaml";
/// A struct to hold an optional file path [String] and an optional [Yaml], and provides methods
/// around error handling in a config file.
#[derive(Debug, Deserialize)]
#[derive(Eq, PartialEq, Debug, Deserialize)]
#[serde(rename_all = "kebab-case")]
#[serde(deny_unknown_fields)]
pub struct Config {
pub classic: Option<bool>,
pub blocks: Option<Sequence>,
pub blocks: Option<Vec<String>>,
pub color: Option<Color>,
pub date: Option<String>, // enum?
pub date: Option<String>,
pub dereference: Option<bool>,
pub display: Option<String>, // enum?
pub display: Option<Display>,
pub icons: Option<Icons>,
pub ignore_globs: Option<Sequence>,
pub ignore_globs: Option<Vec<String>>,
pub indicators: Option<bool>,
pub layout: Option<String>, // enum?
pub layout: Option<Layout>,
pub recursion: Option<Recursion>,
pub size: Option<String>, // enum?
pub size: Option<SizeFlag>,
pub sorting: Option<Sorting>,
pub no_symlink: Option<bool>,
pub total_size: Option<bool>,
pub symlink_arrow: Option<String>,
}
#[derive(Debug, Deserialize)]
#[derive(Eq, PartialEq, Debug, Deserialize)]
pub struct Color {
pub when: String, // enum?
pub when: ColorOption,
}
#[derive(Debug, Deserialize)]
#[derive(Eq, PartialEq, Debug, Deserialize)]
pub struct Icons {
pub when: Option<String>, // enum?
pub when: Option<IconOption>,
pub theme: Option<String>,
}
#[derive(Debug, Deserialize)]
#[derive(Eq, PartialEq, Debug, Deserialize)]
pub struct Recursion {
pub enabled: Option<bool>,
pub depth: Option<usize>,
}
#[derive(Debug, Deserialize)]
#[derive(Eq, PartialEq, Debug, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Sorting {
pub column: Option<String>, // enum?
pub column: Option<SortColumn>,
pub reverse: Option<bool>,
pub dir_grouping: Option<String>, // enum?
pub dir_grouping: Option<DirGrouping>,
}
impl Config {
@ -98,7 +106,7 @@ impl Config {
/// This constructs a Config struct with a passed [Yaml] str.
fn with_yaml(yaml: &str) -> Option<Self> {
match serde_yaml::from_str(yaml) {
match serde_yaml::from_str::<Self>(yaml) {
Ok(c) => Some(c),
Err(e) => {
print_error!("configuration file format error, {}\n\n", e);
@ -145,8 +153,11 @@ impl Default for Config {
return c;
}
}
Self::with_yaml(
r#"---
Self::with_yaml(DEFAULT_CONFIG).unwrap()
}
}
const DEFAULT_CONFIG: &str = r#"---
# == Classic ==
# This is a shorthand to override some of the options to be backwards compatible
# with `ls`. It affects the "color"->"when", "sorting"->"dir-grouping", "date"
@ -256,26 +267,76 @@ total-size: false
# == Symlink arrow ==
# Specifies how the symlink arrow display, chars in both ascii and utf8
symlink-arrow: "#,
)
.unwrap()
}
}
symlink-arrow:
"#;
#[cfg(test)]
mod tests {
use super::Config;
use crate::config_file;
use crate::flags::color::ColorOption;
use crate::flags::icons::IconOption;
use crate::flags::layout::Layout;
use crate::flags::size::SizeFlag;
use crate::flags::sorting::{DirGrouping, SortColumn};
#[test]
fn test_read_default() {
let c = Config::with_yaml(config_file::DEFAULT_CONFIG).unwrap();
assert_eq!(
Config {
classic: Some(false),
blocks: Some(
vec![
"permission".into(),
"user".into(),
"group".into(),
"size".into(),
"date".into(),
"name".into(),
]
.into()
),
color: Some(config_file::Color {
when: ColorOption::Auto,
}),
date: Some("date".into()),
dereference: Some(false),
display: None,
icons: Some(config_file::Icons {
when: Some(IconOption::Auto),
theme: Some("fancy".into()),
}),
ignore_globs: None,
indicators: Some(false),
layout: Some(Layout::Grid),
recursion: Some(config_file::Recursion {
enabled: Some(false),
depth: None,
}),
size: Some(SizeFlag::Default),
sorting: Some(config_file::Sorting {
column: Some(SortColumn::Name),
reverse: Some(false),
dir_grouping: Some(DirGrouping::None),
}),
no_symlink: Some(false),
total_size: Some(false),
symlink_arrow: Some("".into()),
},
c
);
}
#[test]
fn test_read_config_ok() {
let c = Config::with_yaml("classic: true").unwrap();
println!("{:?}", c);
assert!(c.classic.unwrap())
}
#[test]
fn test_read_config_bad_bool() {
let c = Config::with_yaml("classic: notbool");
println!("{:?}", c);
assert!(c.is_none())
}
@ -284,4 +345,9 @@ mod tests {
let c = Config::with_file("not-existed".to_string());
assert!(c.is_none())
}
#[test]
fn test_read_bad_display() {
assert!(Config::with_yaml("display: bad").is_none())
}
}

View file

@ -95,7 +95,7 @@ impl Core {
};
let recurse =
self.flags.layout == Layout::Tree || self.flags.display != Display::DirectoryItself;
self.flags.layout == Layout::Tree || self.flags.display != Display::DirectoryOnly;
if recurse {
match meta.recurse_into(depth, &self.flags) {
Ok(content) => {

View file

@ -61,7 +61,7 @@ fn inner_display_grid(
// The first iteration (depth == 0) corresponds to the inputs given by the
// user. We defer displaying directories given by the user unless we've been
// asked to display the directory itself (rather than its contents).
let skip_dirs = (depth == 0) && (flags.display != Display::DirectoryItself);
let skip_dirs = (depth == 0) && (flags.display != Display::DirectoryOnly);
// print the files first.
for meta in metas {

View file

@ -97,16 +97,16 @@ impl Blocks {
/// Get a potential `Blocks` struct from a [Config].
///
/// of its [String](Yaml::String) values is returned in a `Blocks` in a [Some]. Otherwise it
/// of its [String]values is returned in a `Blocks` in a [Some]. Otherwise it
/// returns [None].
/// Config make sure blocks are Strings, we can unwrap here without panic
fn from_config(config: &Config) -> Option<Self> {
if let Some(c) = &config.blocks {
let mut blocks: Vec<Block> = vec![];
for b in c.iter() {
match Block::try_from(b.as_str().unwrap()) {
match Block::try_from(b.as_str()) {
Ok(block) => blocks.push(block),
Err(err) => print_error!("bad blocks: {}", err),
Err(err) => print_error!("{}.", err),
}
}
if blocks.is_empty() {

View file

@ -7,6 +7,7 @@ use crate::config_file::Config;
use crate::print_error;
use clap::ArgMatches;
use serde::Deserialize;
/// A collection of flags on how to use colors.
#[derive(Clone, Debug, Copy, PartialEq, Eq, Default)]
@ -26,7 +27,8 @@ impl Color {
}
/// The flag showing when to use colors in the output.
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
#[derive(Clone, Debug, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ColorOption {
Always,
Auto,
@ -84,7 +86,7 @@ impl Configurable<Self> for ColorOption {
}
if let Some(color) = &config.color {
Self::from_str(&color.when)
Some(color.when)
} else {
// TODO: maybe return default value?
None
@ -163,7 +165,7 @@ mod test_color_option {
fn test_from_config_always() {
let mut c = Config::with_none();
c.color = Some(config_file::Color {
when: "always".into(),
when: ColorOption::Always,
});
assert_eq!(Some(ColorOption::Always), ColorOption::from_config(&c));
@ -173,7 +175,7 @@ mod test_color_option {
fn test_from_config_auto() {
let mut c = Config::with_none();
c.color = Some(config_file::Color {
when: "auto".into(),
when: ColorOption::Auto,
});
assert_eq!(Some(ColorOption::Auto), ColorOption::from_config(&c));
}
@ -182,7 +184,7 @@ mod test_color_option {
fn test_from_config_never() {
let mut c = Config::with_none();
c.color = Some(config_file::Color {
when: "never".into(),
when: ColorOption::Never,
});
assert_eq!(Some(ColorOption::Never), ColorOption::from_config(&c));
}
@ -191,7 +193,7 @@ mod test_color_option {
fn test_from_config_classic_mode() {
let mut c = Config::with_none();
c.color = Some(config_file::Color {
when: "always".into(),
when: ColorOption::Never,
});
c.classic = Some(true);
assert_eq!(Some(ColorOption::Never), ColorOption::from_config(&c));

View file

@ -4,35 +4,18 @@
use super::Configurable;
use crate::config_file::Config;
use crate::print_error;
use clap::ArgMatches;
use serde::Deserialize;
/// The flag showing which file system nodes to display.
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
#[derive(Clone, Debug, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum Display {
All,
AlmostAll,
DirectoryItself,
DisplayOnlyVisible,
}
impl Display {
/// Get a value from a str
fn from_str(value: &str) -> Option<Self> {
match value {
"all" => Some(Self::All),
"almost-all" => Some(Self::AlmostAll),
"directory-only" => Some(Self::DirectoryItself),
_ => {
print_error!(
"display can only be one of all, almost-all or directory-only, but got {}",
&value
);
None
}
}
}
DirectoryOnly,
VisibleOnly,
}
impl Configurable<Self> for Display {
@ -47,7 +30,7 @@ impl Configurable<Self> for Display {
} else if matches.is_present("almost-all") {
Some(Self::AlmostAll)
} else if matches.is_present("directory-only") {
Some(Self::DirectoryItself)
Some(Self::DirectoryOnly)
} else {
None
}
@ -59,18 +42,14 @@ impl Configurable<Self> for Display {
/// this returns the corresponding `Display` variant in a [Some].
/// Otherwise this returns [None].
fn from_config(config: &Config) -> Option<Self> {
if let Some(disp) = &config.display {
Self::from_str(&disp)
} else {
None
}
config.display
}
}
/// The default value for `Display` is [Display::DisplayOnlyVisible].
impl Default for Display {
fn default() -> Self {
Self::DisplayOnlyVisible
Display::VisibleOnly
}
}
@ -111,7 +90,7 @@ mod test {
let argv = vec!["lsd", "--directory-only"];
let matches = app::build().get_matches_from_safe(argv).unwrap();
assert_eq!(
Some(Display::DirectoryItself),
Some(Display::DirectoryOnly),
Display::from_arg_matches(&matches)
);
}
@ -124,21 +103,21 @@ mod test {
#[test]
fn test_from_config_all() {
let mut c = Config::with_none();
c.display = Some("all".into());
c.display = Some(Display::All);
assert_eq!(Some(Display::All), Display::from_config(&c));
}
#[test]
fn test_from_config_almost_all() {
let mut c = Config::with_none();
c.display = Some("almost-all".into());
c.display = Some(Display::AlmostAll);
assert_eq!(Some(Display::AlmostAll), Display::from_config(&c));
}
#[test]
fn test_from_config_directory_only() {
let mut c = Config::with_none();
c.display = Some("directory-only".into());
assert_eq!(Some(Display::DirectoryItself), Display::from_config(&c));
c.display = Some(Display::DirectoryOnly);
assert_eq!(Some(Display::DirectoryOnly), Display::from_config(&c));
}
}

View file

@ -7,6 +7,7 @@ use crate::config_file::Config;
use crate::print_error;
use clap::ArgMatches;
use serde::Deserialize;
/// A collection of flags on how to use icons.
#[derive(Clone, Debug, Copy, PartialEq, Eq, Default)]
@ -30,31 +31,14 @@ impl Icons {
}
/// The flag showing when to use icons in the output.
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
#[derive(Clone, Debug, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum IconOption {
Always,
Auto,
Never,
}
impl IconOption {
/// Get a value from a str.
fn from_str(value: &str) -> Option<Self> {
match value {
"always" => Some(Self::Always),
"auto" => Some(Self::Auto),
"never" => Some(Self::Never),
_ => {
print_error!(
"icons/when can only be one of auto, always or never, but got {}",
&value
);
None
}
}
}
}
impl Configurable<Self> for IconOption {
/// Get a potential `IconOption` variant from [ArgMatches].
///
@ -88,11 +72,7 @@ impl Configurable<Self> for IconOption {
}
if let Some(icon) = &config.icons {
if let Some(when) = &icon.when {
Self::from_str(&when)
} else {
None
}
icon.when
} else {
None
}
@ -234,7 +214,7 @@ mod test_icon_option {
fn test_from_config_always() {
let mut c = Config::with_none();
c.icons = Some(Icons {
when: Some("always".into()),
when: Some(IconOption::Always),
theme: None,
});
assert_eq!(Some(IconOption::Always), IconOption::from_config(&c));
@ -244,7 +224,7 @@ mod test_icon_option {
fn test_from_config_auto() {
let mut c = Config::with_none();
c.icons = Some(Icons {
when: Some("auto".into()),
when: Some(IconOption::Auto),
theme: None,
});
assert_eq!(Some(IconOption::Auto), IconOption::from_config(&c));
@ -254,7 +234,7 @@ mod test_icon_option {
fn test_from_config_never() {
let mut c = Config::with_none();
c.icons = Some(Icons {
when: Some("never".into()),
when: Some(IconOption::Never),
theme: None,
});
assert_eq!(Some(IconOption::Never), IconOption::from_config(&c));
@ -265,7 +245,7 @@ mod test_icon_option {
let mut c = Config::with_none();
c.classic = Some(true);
c.icons = Some(Icons {
when: Some("always".into()),
when: Some(IconOption::Always),
theme: None,
});
assert_eq!(Some(IconOption::Never), IconOption::from_config(&c));

View file

@ -2,7 +2,6 @@
//! [Default] value, use the [configure_from](IgnoreGlobs::configure_from) method.
use crate::config_file::Config;
use crate::print_error;
use clap::{ArgMatches, Error, ErrorKind};
use globset::{Glob, GlobSet, GlobSetBuilder};
@ -79,23 +78,17 @@ impl IgnoreGlobs {
/// If the `Config::ignore-globs` contains an Array of Strings,
/// each of its values is used to build the [GlobSet]. If the building
/// succeeds, the [GlobSet] is returned in the [Result] in a [Some]. If any error is
/// encountered while building, an [Error] is returned in the Result instead. If the Yaml does
/// encountered while building, an [Error] is returned in the Result instead. If the Config does
/// not contain such a key, this returns [None].
fn from_config(config: &Config) -> Option<Result<GlobSet, Error>> {
if let Some(globs) = &config.ignore_globs {
let mut glob_set_builder = GlobSetBuilder::new();
for glob in globs.iter() {
match glob.as_str() {
Some(glob) => match Self::create_glob(glob) {
Ok(glob) => {
glob_set_builder.add(glob);
}
Err(err) => return Some(Err(err)),
},
None => {
print_error!("ignore-globs must be a string");
continue;
match Self::create_glob(glob) {
Ok(glob) => {
glob_set_builder.add(glob);
}
Err(err) => return Some(Err(err)),
}
}
Some(Self::create_glob_set(&glob_set_builder))

View file

@ -2,14 +2,15 @@
//! [Default] value, use its [configure_from](Configurable::configure_from) method.
use crate::config_file::Config;
use crate::print_error;
use super::Configurable;
use clap::ArgMatches;
use serde::Deserialize;
/// The flag showing which output layout to print.
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
#[derive(Clone, Debug, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Layout {
Grid,
Tree,
@ -44,22 +45,7 @@ impl Configurable<Layout> for Layout {
/// this returns the corresponding `Layout` variant in a [Some].
/// Otherwise this returns [None].
fn from_config(config: &Config) -> Option<Self> {
if let Some(layout) = &config.layout {
match layout.as_ref() {
"tree" => Some(Self::Tree),
"oneline" => Some(Self::OneLine),
"grid" => Some(Self::Grid),
_ => {
print_error!(
"layout can only be one of tree, oneline or grid, but got {}",
&layout
);
None
}
}
} else {
None
}
config.layout
}
}
@ -121,21 +107,21 @@ mod test {
#[test]
fn test_from_config_tree() {
let mut c = Config::with_none();
c.layout = Some("tree".into());
c.layout = Some(Layout::Tree);
assert_eq!(Some(Layout::Tree), Layout::from_config(&c));
}
#[test]
fn test_from_config_oneline() {
let mut c = Config::with_none();
c.layout = Some("oneline".into());
c.layout = Some(Layout::OneLine);
assert_eq!(Some(Layout::OneLine), Layout::from_config(&c));
}
#[test]
fn test_from_config_grid() {
let mut c = Config::with_none();
c.layout = Some("grid".into());
c.layout = Some(Layout::Grid);
assert_eq!(Some(Layout::Grid), Layout::from_config(&c));
}
}

View file

@ -7,9 +7,11 @@ use crate::config_file::Config;
use crate::print_error;
use clap::ArgMatches;
use serde::Deserialize;
/// The flag showing which file size units to use.
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
#[derive(Clone, Debug, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum SizeFlag {
/// The variant to show file size with SI unit prefix and a B for bytes.
Default,
@ -57,10 +59,7 @@ impl Configurable<Self> for SizeFlag {
/// this returns the corresponding `SizeFlag` variant in a [Some].
/// Otherwise this returns [None].
fn from_config(config: &Config) -> Option<Self> {
if let Some(size) = &config.size {
return Self::from_str(size);
}
None
config.size
}
}
@ -118,21 +117,21 @@ mod test {
#[test]
fn test_from_config_default() {
let mut c = Config::with_none();
c.size = Some("default".into());
c.size = Some(SizeFlag::Default);
assert_eq!(Some(SizeFlag::Default), SizeFlag::from_config(&c));
}
#[test]
fn test_from_config_short() {
let mut c = Config::with_none();
c.size = Some("short".into());
c.size = Some(SizeFlag::Short);
assert_eq!(Some(SizeFlag::Short), SizeFlag::from_config(&c));
}
#[test]
fn test_from_config_bytes() {
let mut c = Config::with_none();
c.size = Some("bytes".into());
c.size = Some(SizeFlag::Bytes);
assert_eq!(Some(SizeFlag::Bytes), SizeFlag::from_config(&c));
}
}

View file

@ -4,9 +4,9 @@
use super::Configurable;
use crate::config_file::Config;
use crate::print_error;
use clap::ArgMatches;
use serde::Deserialize;
/// A collection of flags on how to sort the output.
#[derive(Clone, Debug, Copy, PartialEq, Eq, Default)]
@ -34,7 +34,8 @@ impl Sorting {
}
/// The flag showing which column to use for sorting.
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
#[derive(Clone, Debug, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum SortColumn {
Extension,
Name,
@ -70,25 +71,7 @@ impl Configurable<Self> for SortColumn {
/// Otherwise this returns [None].
fn from_config(config: &Config) -> Option<Self> {
if let Some(sort) = &config.sorting {
if let Some(column) = &sort.column {
match column.as_ref() {
"extension" => Some(Self::Extension),
"name" => Some(Self::Name),
"size" => Some(Self::Size),
"time" => Some(Self::Time),
"version" => Some(Self::Version),
_ => {
print_error!(
"sorting/column can only be one of \
extension, name, size, time or version, but got {}",
&column
);
None
}
}
} else {
None
}
sort.column
} else {
None
}
@ -153,7 +136,8 @@ impl Default for SortOrder {
}
/// The flag showing where to place directories.
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
#[derive(Clone, Debug, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum DirGrouping {
None,
First,
@ -201,9 +185,7 @@ impl Configurable<Self> for DirGrouping {
return Some(Self::None);
}
if let Some(sort) = &config.sorting {
if let Some(group) = &sort.dir_grouping {
return Self::from_str(group);
}
return sort.dir_grouping;
}
None
}
@ -329,23 +311,11 @@ mod test_sort_column {
assert_eq!(None, SortColumn::from_config(&c));
}
#[test]
fn test_from_config_invalid() {
let mut c = Config::with_none();
c.sorting = Some(Sorting {
column: Some("foo".into()),
reverse: None,
dir_grouping: None,
});
assert_eq!(None, SortColumn::from_config(&c));
}
#[test]
fn test_from_config_extension() {
let mut c = Config::with_none();
c.sorting = Some(Sorting {
column: Some("extension".into()),
column: Some(SortColumn::Extension),
reverse: None,
dir_grouping: None,
});
@ -356,7 +326,7 @@ mod test_sort_column {
fn test_from_config_name() {
let mut c = Config::with_none();
c.sorting = Some(Sorting {
column: Some("name".into()),
column: Some(SortColumn::Name),
reverse: None,
dir_grouping: None,
});
@ -367,7 +337,7 @@ mod test_sort_column {
fn test_from_config_time() {
let mut c = Config::with_none();
c.sorting = Some(Sorting {
column: Some("time".into()),
column: Some(SortColumn::Time),
reverse: None,
dir_grouping: None,
});
@ -378,7 +348,7 @@ mod test_sort_column {
fn test_from_config_size() {
let mut c = Config::with_none();
c.sorting = Some(Sorting {
column: Some("size".into()),
column: Some(SortColumn::Size),
reverse: None,
dir_grouping: None,
});
@ -389,7 +359,7 @@ mod test_sort_column {
fn test_from_config_version() {
let mut c = Config::with_none();
c.sorting = Some(Sorting {
column: Some("version".into()),
column: Some(SortColumn::Version),
reverse: None,
dir_grouping: None,
});
@ -529,7 +499,7 @@ mod test_dir_grouping {
c.sorting = Some(Sorting {
column: None,
reverse: None,
dir_grouping: Some("first".into()),
dir_grouping: Some(DirGrouping::First),
});
assert_eq!(Some(DirGrouping::First), DirGrouping::from_config(&c));
}
@ -540,7 +510,7 @@ mod test_dir_grouping {
c.sorting = Some(Sorting {
column: None,
reverse: None,
dir_grouping: Some("last".into()),
dir_grouping: Some(DirGrouping::Last),
});
assert_eq!(Some(DirGrouping::Last), DirGrouping::from_config(&c));
}
@ -559,6 +529,11 @@ mod test_dir_grouping {
#[test]
fn test_from_config_classic_mode() {
let mut c = Config::with_none();
c.sorting = Some(Sorting {
column: None,
reverse: None,
dir_grouping: Some(DirGrouping::Last),
});
c.classic = Some(true);
assert_eq!(Some(DirGrouping::None), DirGrouping::from_config(&c));
}

View file

@ -54,7 +54,7 @@ impl Meta {
return Ok(None);
}
if flags.display == Display::DirectoryItself && flags.layout != Layout::Tree {
if flags.display == Display::DirectoryOnly && flags.layout != Layout::Tree {
return Ok(None);
}
@ -103,7 +103,7 @@ impl Meta {
continue;
}
if let Display::DisplayOnlyVisible = flags.display {
if let Display::VisibleOnly = flags.display {
if name.to_string_lossy().starts_with('.') {
continue;
}
@ -119,7 +119,7 @@ impl Meta {
// skip files for --tree -d
if flags.layout == Layout::Tree {
if let Display::DirectoryItself = flags.display {
if let Display::DirectoryOnly = flags.display {
if !entry.file_type()?.is_dir() {
continue;
}