Repository: lsd-rs/lsd (language: rust)

Issue:
lsd uses many deprecated features of clap
- os: --
- `lsd --version`: lsd 0.23.1
- `echo $TERM`: --
- `echo $LS_COLORS`: --

lsd uses version clap v3.2.17 to parse command line arguments, but it also uses some deprecated features of clap. Many of these deprecated features have already been removed in the latest version of clap, v4. I suggest avoiding the use of these deprecated features for future security risks and ease of maintenance.

I have already written code that does not use any deprecated features, but I have found that there have been more changes than I expected (24 changed files with 339 additions and 302 deletions). If there are no problems, I will submit a pull request.





Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dc5980e73..922c2a9dc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
   based on the file extension: `exe`, `msi`, `bat` and `ps1`.
   [`LS_COLORS`](README.md#Colors) can be used to customize.
 - Handle dereference (-L) with broken symlink from [r3dArch](https://github.com/r3dArch)
+- Avoid using Clap's deprecated structs and functions [sudame](https://github.com/sudame)
 
 ## [0.23.1] - 2022-09-13
 
diff --git a/src/app.rs b/src/app.rs
index 137a5e6d6..e4098f917 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -1,178 +1,173 @@
-use clap::{App, Arg, ValueHint};
+use clap::{Arg, ArgAction, Command, ValueHint};
 
-pub fn build() -> App<'static> {
-    App::new("lsd")
+pub fn build() -> Command<'static> {
+    Command::new("lsd")
         .version(env!("CARGO_PKG_VERSION"))
         .about(env!("CARGO_PKG_DESCRIPTION"))
         .arg(
-            Arg::with_name("FILE")
-                .multiple(true)
+            Arg::new("FILE")
+                .action(ArgAction::Append)
+                .multiple_values(true)
                 .default_value(".")
                 .value_hint(ValueHint::AnyPath),
         )
         .arg(
-            Arg::with_name("all")
+            Arg::new("all")
                 .short('a')
                 .overrides_with("almost-all")
                 .long("all")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .help("Do not ignore entries starting with ."),
         )
         .arg(
-            Arg::with_name("almost-all")
+            Arg::new("almost-all")
                 .short('A')
                 .overrides_with("all")
                 .long("almost-all")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .help("Do not list implied . and .."),
         )
         .arg(
-            Arg::with_name("color")
+            Arg::new("color")
                 .long("color")
-                .possible_value("always")
-                .possible_value("auto")
-                .possible_value("never")
+                .value_parser(["always", "auto", "never"])
                 .default_value("auto")
-                .multiple_occurrences(true)
+                .action(ArgAction::Append)
                 .takes_value(true)
                 .number_of_values(1)
                 .help("When to use terminal colours"),
         )
         .arg(
-            Arg::with_name("icon")
+            Arg::new("icon")
                 .long("icon")
-                .possible_value("always")
-                .possible_value("auto")
-                .possible_value("never")
+                .value_parser(["always", "auto", "never"])
                 .default_value("auto")
-                .multiple_occurrences(true)
+                .action(ArgAction::Append)
                 .takes_value(true)
                 .number_of_values(1)
                 .help("When to print the icons"),
         )
         .arg(
-            Arg::with_name("icon-theme")
+            Arg::new("icon-theme")
                 .long("icon-theme")
                 .default_value("fancy")
-                .possible_value("fancy")
-                .possible_value("unicode")
-                .multiple_occurrences(true)
+                .value_parser(["fancy", "unicode"])
+                .action(ArgAction::Append)
                 .takes_value(true)
                 .number_of_values(1)
                 .help("Whether to use fancy or unicode icons"),
         )
         .arg(
-            Arg::with_name("indicators")
+            Arg::new("indicators")
                 .short('F')
                 .long("classify")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .help("Append indicator (one of */=>@|) at the end of the file names"),
         )
         .arg(
-            Arg::with_name("long")
+            Arg::new("long")
                 .short('l')
                 .long("long")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .help("Display extended file metadata as a table"),
         )
         .arg(
-            Arg::with_name("ignore-config")
+            Arg::new("ignore-config")
                 .long("ignore-config")
+                .action(ArgAction::SetTrue)
                 .help("Ignore the configuration file"),
         )
         .arg(
-            Arg::with_name("config-file")
+            Arg::new("config-file")
                 .long("config-file")
                 .help("Provide a custom lsd configuration file")
                 .value_name("config-file")
                 .takes_value(true)
         )
         .arg(
-            Arg::with_name("oneline")
+            Arg::new("oneline")
                 .short('1')
                 .long("oneline")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .help("Display one entry per line"),
         )
         .arg(
-            Arg::with_name("recursive")
+            Arg::new("recursive")
                 .short('R')
                 .long("recursive")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .conflicts_with("tree")
                 .help("Recurse into directories"),
         )
         .arg(
-            Arg::with_name("human_readable")
+            Arg::new("human_readable")
                 .short('h')
                 .long("human-readable")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .help("For ls compatibility purposes ONLY, currently set by default"),
         )
         .arg(
-            Arg::with_name("tree")
+            Arg::new("tree")
                 .long("tree")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .conflicts_with("recursive")
                 .help("Recurse into directories and present the result as a tree"),
         )
         .arg(
-            Arg::with_name("depth")
+            Arg::new("depth")
                 .long("depth")
-                .multiple_occurrences(true)
+                .action(ArgAction::Append)
                 .takes_value(true)
                 .value_name("num")
                 .help("Stop recursing into directories after reaching specified depth"),
         )
         .arg(
-            Arg::with_name("directory-only")
+            Arg::new("directory-only")
                 .short('d')
                 .long("directory-only")
+                .action(ArgAction::SetTrue)
                 .conflicts_with("depth")
                 .conflicts_with("recursive")
                 .help("Display directories themselves, and not their contents (recursively when used with --tree)"),
         )
         .arg(
-            Arg::with_name("permission")
+            Arg::new("permission")
                 .long("permission")
                 .default_value("rwx")
-                .possible_value("rwx")
-                .possible_value("octal")
-                .multiple_occurrences(true)
+                .value_parser(["rwx", "octal"])
+                .action(ArgAction::Append)
                 .takes_value(true)
                 .number_of_values(1)
                 .help("How to display permissions"),
         )
         .arg(
-            Arg::with_name("size")
+            Arg::new("size")
                 .long("size")
-                .possible_value("default")
-                .possible_value("short")
-                .possible_value("bytes")
+                .value_parser(["default", "short", "bytes"])
                 .default_value("default")
-                .multiple_occurrences(true)
+                .action(ArgAction::Append)
                 .takes_value(true)
                 .number_of_values(1)
                 .help("How to display size"),
         )
         .arg(
-            Arg::with_name("total-size")
+            Arg::new("total-size")
                 .long("total-size")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .help("Display the total size of directories"),
         )
         .arg(
-            Arg::with_name("date")
+            Arg::new("date")
                 .long("date")
-                .validator(validate_date_argument)
+                .value_parser(validate_date_argument)
                 .default_value("date")
-                .multiple_occurrences(true)
+                .action(ArgAction::Append)
                 .takes_value(true)
                 .number_of_values(1)
                 .help("How to display date [possible values: date, relative, +date-time-format]"),
         )
         .arg(
-            Arg::with_name("timesort")
+            Arg::new("timesort")
                 .short('t')
                 .long("timesort")
                 .overrides_with("sizesort")
@@ -180,11 +175,11 @@ pub fn build() -> App<'static> {
                 .overrides_with("versionsort")
                 .overrides_with("sort")
                 .overrides_with("no-sort")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .help("Sort by time modified"),
         )
         .arg(
-            Arg::with_name("sizesort")
+            Arg::new("sizesort")
                 .short('S')
                 .long("sizesort")
                 .overrides_with("timesort")
@@ -192,11 +187,11 @@ pub fn build() -> App<'static> {
                 .overrides_with("versionsort")
                 .overrides_with("sort")
                 .overrides_with("no-sort")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .help("Sort by size"),
         )
         .arg(
-            Arg::with_name("extensionsort")
+            Arg::new("extensionsort")
                 .short('X')
                 .long("extensionsort")
                 .overrides_with("sizesort")
@@ -204,14 +199,14 @@ pub fn build() -> App<'static> {
                 .overrides_with("versionsort")
                 .overrides_with("sort")
                 .overrides_with("no-sort")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .help("Sort by file extension"),
         )
         .arg(
-            Arg::with_name("versionsort")
+            Arg::new("versionsort")
                 .short('v')
                 .long("versionsort")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .overrides_with("timesort")
                 .overrides_with("sizesort")
                 .overrides_with("extensionsort")
@@ -220,10 +215,10 @@ pub fn build() -> App<'static> {
                 .help("Natural sort of (version) numbers within text"),
         )
         .arg(
-            Arg::with_name("sort")
+            Arg::new("sort")
                 .long("sort")
-                .multiple_occurrences(true)
-                .possible_values(&["size", "time", "version", "extension", "none"])
+                .action(ArgAction::Append)
+                .value_parser(["size", "time", "version", "extension", "none"])
                 .takes_value(true)
                 .value_name("WORD")
                 .overrides_with("timesort")
@@ -234,10 +229,10 @@ pub fn build() -> App<'static> {
                 .help("sort by WORD instead of name")
         )
         .arg(
-            Arg::with_name("no-sort")
+            Arg::new("no-sort")
             .short('U')
             .long("no-sort")
-            .multiple_occurrences(true)
+            .action(ArgAction::SetTrue)
             .overrides_with("timesort")
             .overrides_with("sizesort")
             .overrides_with("extensionsort")
@@ -246,36 +241,35 @@ pub fn build() -> App<'static> {
             .help("Do not sort. List entries in directory order")
         )
         .arg(
-            Arg::with_name("reverse")
+            Arg::new("reverse")
                 .short('r')
                 .long("reverse")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .help("Reverse the order of the sort"),
         )
         .arg(
-            Arg::with_name("group-dirs")
+            Arg::new("group-dirs")
                 .long("group-dirs")
-                .possible_value("none")
-                .possible_value("first")
-                .possible_value("last")
-                .multiple_occurrences(true)
+                .value_parser(["none", "first", "last"])
+                .action(ArgAction::Append)
                 .number_of_values(1)
                 .help("Sort the directories then the files"),
         )
         .arg(
-            Arg::with_name("group-directories-first")
+            Arg::new("group-directories-first")
                 .long("group-directories-first")
+                .action(ArgAction::SetTrue)
                 .help("Groups the directories at the top before the files. Same as --group-dirs=first")
         )
         .arg(
-            Arg::with_name("blocks")
+            Arg::new("blocks")
                 .long("blocks")
-                .multiple_occurrences(true)
+                .action(ArgAction::Append)
                 .multiple_values(true)
                 .takes_value(true)
                 .use_value_delimiter(true)
-                .require_delimiter(true)
-                .possible_values(&[
+                .require_value_delimiter(true)
+                .value_parser([
                     "permission",
                     "user",
                     "group",
@@ -289,84 +283,86 @@ pub fn build() -> App<'static> {
                 .help("Specify the blocks that will be displayed and in what order"),
         )
         .arg(
-            Arg::with_name("classic")
+            Arg::new("classic")
                 .long("classic")
+                .action(ArgAction::SetTrue)
                 .help("Enable classic mode (display output similar to ls)"),
         )
         .arg(
-            Arg::with_name("no-symlink")
+            Arg::new("no-symlink")
                 .long("no-symlink")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .help("Do not display symlink target"),
         )
         .arg(
-            Arg::with_name("ignore-glob")
+            Arg::new("ignore-glob")
                 .short('I')
                 .long("ignore-glob")
-                .multiple_occurrences(true)
+                .action(ArgAction::Append)
                 .number_of_values(1)
                 .value_name("pattern")
                 .default_value("")
                 .help("Do not display files/directories with names matching the glob pattern(s). More than one can be specified by repeating the argument"),
         )
         .arg(
-            Arg::with_name("inode")
+            Arg::new("inode")
                 .short('i')
                 .long("inode")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .help("Display the index number of each file"),
         )
         .arg(
-            Arg::with_name("dereference")
+            Arg::new("dereference")
                 .short('L')
                 .long("dereference")
-                .multiple_occurrences(true)
+                .action(ArgAction::SetTrue)
                 .help("When showing file information for a symbolic link, show information for the file the link references rather than for the link itself"),
         )
         .arg(
-            Arg::with_name("context")
+            Arg::new("context")
                 .short('Z')
                 .long("context")
                 .required(false)
                 .takes_value(false)
+                .action(ArgAction::SetTrue)
                 .help("Print security context (label) of each file"),
         )
         .arg(
-            Arg::with_name("hyperlink")
+            Arg::new("hyperlink")
                 .long("hyperlink")
-                .possible_value("always")
-                .possible_value("auto")
-                .possible_value("never")
+                .value_parser(["always", "auto", "never"])
                 .default_value("never")
-                .multiple_occurrences(true)
+                .action(ArgAction::Append)
                 .takes_value(true)
                 .number_of_values(1)
                 .help("Attach hyperlink to filenames"),
         )
         .arg(
-            Arg::with_name("header")
+            Arg::new("header")
                 .long("header")
+                .action(ArgAction::SetTrue)
                 .help("Display block headers"),
         )
         .arg(
-            Arg::with_name("system-protected")
+            Arg::new("system-protected")
                 .long("system-protected")
+                .action(ArgAction::SetTrue)
                 .help("Includes files with the windows system protection flag set. This is the same as --all on other platforms")
                 .hide(!cfg!(windows)),
         )
 }
 
-fn validate_date_argument(arg: &str) -> Result<(), String> {
+fn validate_date_argument(arg: &str) -> Result<String, String> {
     if arg.starts_with('+') {
         validate_time_format(arg)
     } else if arg == "date" || arg == "relative" {
-        Result::Ok(())
+        Result::Ok(arg.to_owned())
     } else {
         Result::Err("possible values: date, relative, +date-time-format".to_owned())
     }
 }
 
-pub fn validate_time_format(formatter: &str) -> Result<(), String> {
+pub fn validate_time_format(formatter: &str) -> Result<String, String> {
     let mut chars = formatter.chars();
     loop {
         match chars.next() {
@@ -412,5 +408,5 @@ pub fn validate_time_format(formatter: &str) -> Result<(), String> {
             _ => continue,
         }
     }
-    Ok(())
+    Ok(formatter.to_owned())
 }
diff --git a/src/display.rs b/src/display.rs
index c57b3f60d..e55bebeaf 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -635,7 +635,7 @@ mod tests {
     #[test]
     fn test_display_tree_with_all() {
         let argv = ["lsd", "--tree", "--all"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let flags = Flags::configure_from(&matches, &Config::with_none()).unwrap();
 
         let dir = assert_fs::TempDir::new().unwrap();
@@ -668,7 +668,7 @@ mod tests {
     #[test]
     fn test_tree_align_subfolder() {
         let argv = ["lsd", "--tree", "--blocks", "size,name"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let flags = Flags::configure_from(&matches, &Config::with_none()).unwrap();
 
         let dir = assert_fs::TempDir::new().unwrap();
@@ -708,7 +708,7 @@ mod tests {
     #[cfg(unix)]
     fn test_tree_size_first_without_name() {
         let argv = ["lsd", "--tree", "--blocks", "size,permission"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let flags = Flags::configure_from(&matches, &Config::with_none()).unwrap();
 
         let dir = assert_fs::TempDir::new().unwrap();
@@ -747,7 +747,7 @@ mod tests {
     #[test]
     fn test_tree_edge_before_name() {
         let argv = ["lsd", "--tree", "--long"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let flags = Flags::configure_from(&matches, &Config::with_none()).unwrap();
 
         let dir = assert_fs::TempDir::new().unwrap();
@@ -777,7 +777,7 @@ mod tests {
             "--blocks",
             "permission,user,group,size,date,name,inode,links",
         ];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let flags = Flags::configure_from(&matches, &Config::with_none()).unwrap();
 
         let dir = assert_fs::TempDir::new().unwrap();
@@ -811,7 +811,7 @@ mod tests {
     #[test]
     fn test_grid_no_header_with_empty_meta() {
         let argv = ["lsd", "--header", "-l"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let flags = Flags::configure_from(&matches, &Config::with_none()).unwrap();
 
         let dir = assert_fs::TempDir::new().unwrap();
diff --git a/src/flags/blocks.rs b/src/flags/blocks.rs
index c3558362e..dc2e2c656 100644
--- a/src/flags/blocks.rs
+++ b/src/flags/blocks.rs
@@ -81,13 +81,13 @@ impl Configurable<Self> for Blocks {
     /// `Blocks` does not contain a [Block] of variant [INode](Block::INode) yet, one is prepended
     /// to the returned value.
     fn configure_from(matches: &ArgMatches, config: &Config) -> Self {
-        let mut blocks = if matches.is_present("long") {
+        let mut blocks = if matches.get_one("long") == Some(&true) {
             Self::long()
         } else {
             Default::default()
         };
 
-        if matches.is_present("long") {
+        if matches.get_one("long") == Some(&true) {
             if let Some(value) = Self::from_config(config) {
                 blocks = value;
             }
@@ -97,10 +97,10 @@ impl Configurable<Self> for Blocks {
             blocks = value;
         }
 
-        if matches.is_present("context") {
+        if matches.get_one("context") == Some(&true) {
             blocks.optional_insert_context();
         }
-        if matches.is_present("inode") {
+        if matches.get_one("inode") == Some(&true) {
             blocks.optional_prepend_inode();
         }
 
@@ -113,11 +113,14 @@ impl Configurable<Self> for Blocks {
     /// values in a [Some]. Otherwise if the "long" argument is passed, this returns
     /// [Blocks::long]. Finally if none of the previous happened, this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.occurrences_of("blocks") == 0 {
+        if matches.get_many::<String>("blocks")?.len() == 0 {
             return None;
         }
 
-        if let Some(values) = matches.values_of("blocks") {
+        if let Some(values) = matches
+            .get_many::<String>("blocks")
+            .map(|values| values.map(String::as_str))
+        {
             let mut blocks: Vec<Block> = Vec::with_capacity(values.len());
             for value in values {
                 blocks.push(Block::try_from(value).unwrap_or_else(|_| {
@@ -229,7 +232,7 @@ mod test_blocks {
         let argv = ["lsd"];
         let target = Blocks::default();
 
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let result = Blocks::configure_from(&matches, &Config::with_none());
 
         assert_eq!(result, target);
@@ -240,7 +243,7 @@ mod test_blocks {
         let argv = ["lsd", "--long"];
         let target = Blocks::long();
 
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let result = Blocks::configure_from(&matches, &Config::with_none());
 
         assert_eq!(result, target);
@@ -251,7 +254,7 @@ mod test_blocks {
         let argv = ["lsd", "--blocks", "permission"];
         let target = Blocks(vec![Block::Permission]);
 
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let result = Blocks::configure_from(&matches, &Config::with_none());
 
         assert_eq!(result, target);
@@ -262,7 +265,7 @@ mod test_blocks {
         let argv = ["lsd", "--long", "--blocks", "permission"];
         let target = Blocks(vec![Block::Permission]);
 
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let result = Blocks::configure_from(&matches, &Config::with_none());
 
         assert_eq!(result, target);
@@ -273,7 +276,7 @@ mod test_blocks {
         let argv = ["lsd", "--inode"];
         let target = Blocks(vec![Block::INode, Block::Name]);
 
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let result = Blocks::configure_from(&matches, &Config::with_none());
 
         assert_eq!(result, target);
@@ -284,7 +287,7 @@ mod test_blocks {
         let argv = ["lsd", "--blocks", "permission", "--inode"];
         let target = Blocks(vec![Block::INode, Block::Permission]);
 
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let result = Blocks::configure_from(&matches, &Config::with_none());
 
         assert_eq!(result, target);
@@ -295,7 +298,7 @@ mod test_blocks {
         let argv = ["lsd", "--long", "--blocks", "permission", "--inode"];
         let target = Blocks(vec![Block::INode, Block::Permission]);
 
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let result = Blocks::configure_from(&matches, &Config::with_none());
 
         assert_eq!(result, target);
@@ -306,7 +309,7 @@ mod test_blocks {
         let argv = ["lsd", "--blocks", "permission,inode", "--inode"];
         let target = Blocks(vec![Block::Permission, Block::INode]);
 
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let result = Blocks::configure_from(&matches, &Config::with_none());
 
         assert_eq!(result, target);
@@ -317,7 +320,7 @@ mod test_blocks {
         let argv = ["lsd", "--long", "--blocks", "permission,inode", "--inode"];
         let target = Blocks(vec![Block::Permission, Block::INode]);
 
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let result = Blocks::configure_from(&matches, &Config::with_none());
 
         assert_eq!(result, target);
@@ -326,14 +329,14 @@ mod test_blocks {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert!(matches!(Blocks::from_arg_matches(&matches), None));
     }
 
     #[test]
     fn test_from_arg_matches_one() {
         let argv = ["lsd", "--blocks", "permission"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let test_blocks = Blocks(vec![Block::Permission]);
         assert_eq!(Blocks::from_arg_matches(&matches), Some(test_blocks));
     }
@@ -341,7 +344,7 @@ mod test_blocks {
     #[test]
     fn test_from_arg_matches_multi_occurences() {
         let argv = ["lsd", "--blocks", "permission", "--blocks", "name"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let test_blocks = Blocks(vec![Block::Permission, Block::Name]);
         assert_eq!(Blocks::from_arg_matches(&matches), Some(test_blocks));
     }
@@ -349,7 +352,7 @@ mod test_blocks {
     #[test]
     fn test_from_arg_matches_multi_values() {
         let argv = ["lsd", "--blocks", "permission,name"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let test_blocks = Blocks(vec![Block::Permission, Block::Name]);
         assert_eq!(Blocks::from_arg_matches(&matches), Some(test_blocks));
     }
@@ -357,7 +360,7 @@ mod test_blocks {
     #[test]
     fn test_from_arg_matches_reversed_default() {
         let argv = ["lsd", "--blocks", "name,date,size,group,user,permission"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let test_blocks = Blocks(vec![
             Block::Name,
             Block::Date,
@@ -372,7 +375,7 @@ mod test_blocks {
     #[test]
     fn test_from_arg_matches_every_second_one() {
         let argv = ["lsd", "--blocks", "permission,group,date"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let test_blocks = Blocks(vec![Block::Permission, Block::Group, Block::Date]);
         assert_eq!(Blocks::from_arg_matches(&matches), Some(test_blocks));
     }
@@ -433,7 +436,7 @@ mod test_blocks {
     #[test]
     fn test_context_not_present_on_cli() {
         let argv = ["lsd", "--long"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let parsed_blocks = Blocks::configure_from(&matches, &Config::with_none());
         let it = parsed_blocks.0.iter();
         assert_eq!(it.filter(|&x| *x == Block::Context).count(), 0);
@@ -442,7 +445,7 @@ mod test_blocks {
     #[test]
     fn test_context_present_if_context_on() {
         let argv = ["lsd", "--context"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let parsed_blocks = Blocks::configure_from(&matches, &Config::with_none());
         let it = parsed_blocks.0.iter();
         assert_eq!(it.filter(|&x| *x == Block::Context).count(), 1);
@@ -456,7 +459,7 @@ mod test_blocks {
             "--blocks",
             "name,date,size,context,group,user,permission",
         ];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let test_blocks = Blocks(vec![
             Block::Name,
             Block::Date,
diff --git a/src/flags/color.rs b/src/flags/color.rs
index 3e7a1270b..eac9c3f39 100644
--- a/src/flags/color.rs
+++ b/src/flags/color.rs
@@ -5,7 +5,7 @@ use super::Configurable;
 
 use crate::config_file::Config;
 
-use clap::ArgMatches;
+use clap::{ArgMatches, ValueSource};
 use serde::de::{self, Deserializer, Visitor};
 use serde::Deserialize;
 use std::env;
@@ -115,10 +115,14 @@ impl Configurable<Self> for ColorOption {
     /// a [Some]. Otherwise if the argument is passed, this returns the variant corresponding to
     /// its parameter in a [Some]. Otherwise this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("classic") {
+        if matches.get_one("classic") == Some(&true) {
             Some(Self::Never)
-        } else if matches.occurrences_of("color") > 0 {
-            matches.values_of("color")?.last().map(Self::from_arg_str)
+        } else if matches.value_source("color") == Some(ValueSource::CommandLine) {
+            matches
+                .get_many::<String>("color")?
+                .last()
+                .map(String::as_str)
+                .map(Self::from_arg_str)
         } else {
             None
         }
@@ -159,14 +163,14 @@ mod test_color_option {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, ColorOption::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_always() {
         let argv = ["lsd", "--color", "always"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(ColorOption::Always),
             ColorOption::from_arg_matches(&matches)
@@ -176,7 +180,7 @@ mod test_color_option {
     #[test]
     fn test_from_arg_matches_auto() {
         let argv = ["lsd", "--color", "auto"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(ColorOption::Auto),
             ColorOption::from_arg_matches(&matches)
@@ -186,7 +190,7 @@ mod test_color_option {
     #[test]
     fn test_from_arg_matches_never() {
         let argv = ["lsd", "--color", "never"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(ColorOption::Never),
             ColorOption::from_arg_matches(&matches)
@@ -202,7 +206,7 @@ mod test_color_option {
     #[test]
     fn test_from_arg_matches_classic_mode() {
         let argv = ["lsd", "--color", "always", "--classic"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(ColorOption::Never),
             ColorOption::from_arg_matches(&matches)
@@ -212,7 +216,7 @@ mod test_color_option {
     #[test]
     fn test_from_arg_matches_color_multiple() {
         let argv = ["lsd", "--color", "always", "--color", "never"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(ColorOption::Never),
             ColorOption::from_arg_matches(&matches)
diff --git a/src/flags/date.rs b/src/flags/date.rs
index e4e0a8eed..0409e0125 100644
--- a/src/flags/date.rs
+++ b/src/flags/date.rs
@@ -7,7 +7,7 @@ use crate::app;
 use crate::config_file::Config;
 use crate::print_error;
 
-use clap::ArgMatches;
+use clap::{ArgMatches, ValueSource};
 
 /// The flag showing which kind of time stamps to display.
 #[derive(Clone, Debug, PartialEq, Eq, Default)]
@@ -52,10 +52,14 @@ impl Configurable<Self> for DateFlag {
     /// [Some]. Otherwise if the argument is passed, this returns the variant corresponding to its
     /// parameter in a [Some]. Otherwise this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("classic") {
+        if matches.get_one("classic") == Some(&true) {
             Some(Self::Date)
-        } else if matches.occurrences_of("date") > 0 {
-            matches.values_of("date")?.last().and_then(Self::from_str)
+        } else if matches.value_source("date") == Some(ValueSource::CommandLine) {
+            matches
+                .get_many("date")?
+                .last()
+                .map(String::as_str)
+                .and_then(Self::from_str)
         } else {
             None
         }
@@ -105,21 +109,21 @@ mod test {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, DateFlag::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_date() {
         let argv = ["lsd", "--date", "date"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(DateFlag::Date), DateFlag::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_relative() {
         let argv = ["lsd", "--date", "relative"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(DateFlag::Relative),
             DateFlag::from_arg_matches(&matches)
@@ -129,7 +133,7 @@ mod test {
     #[test]
     fn test_from_arg_matches_format() {
         let argv = ["lsd", "--date", "+%F"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(DateFlag::Formatted("%F".to_string())),
             DateFlag::from_arg_matches(&matches)
@@ -140,21 +144,21 @@ mod test {
     #[should_panic(expected = "invalid format specifier: %J")]
     fn test_from_arg_matches_format_invalid() {
         let argv = ["lsd", "--date", "+%J"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         DateFlag::from_arg_matches(&matches);
     }
 
     #[test]
     fn test_from_arg_matches_classic_mode() {
         let argv = ["lsd", "--date", "date", "--classic"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(DateFlag::Date), DateFlag::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_date_multi() {
         let argv = ["lsd", "--date", "relative", "--date", "date"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(DateFlag::Date), DateFlag::from_arg_matches(&matches));
     }
 
@@ -252,7 +256,7 @@ mod test {
     fn test_parsing_order_arg() {
         std::env::set_var("TIME_STYLE", "+%R");
         let argv = ["lsd", "--date", "+%F"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let mut config = Config::with_none();
         config.date = Some("+%c".into());
         assert_eq!(
@@ -266,7 +270,7 @@ mod test {
     fn test_parsing_order_env() {
         std::env::set_var("TIME_STYLE", "+%R");
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let mut config = Config::with_none();
         config.date = Some("+%c".into());
         assert_eq!(
@@ -280,7 +284,7 @@ mod test {
     fn test_parsing_order_config() {
         std::env::set_var("TIME_STYLE", "");
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let mut config = Config::with_none();
         config.date = Some("+%c".into());
         assert_eq!(
diff --git a/src/flags/dereference.rs b/src/flags/dereference.rs
index 7e6de97c2..26baa54f8 100644
--- a/src/flags/dereference.rs
+++ b/src/flags/dereference.rs
@@ -17,7 +17,7 @@ impl Configurable<Self> for Dereference {
     /// If the "dereference" argument is passed, this returns a `Dereference` with value `true` in
     /// a [Some]. Otherwise this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("dereference") {
+        if matches.get_one("dereference") == Some(&true) {
             Some(Self(true))
         } else {
             None
@@ -44,14 +44,14 @@ mod test {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, Dereference::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_true() {
         let argv = ["lsd", "--dereference"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(Dereference(true)),
             Dereference::from_arg_matches(&matches)
diff --git a/src/flags/display.rs b/src/flags/display.rs
index 2ac5f69bc..050adcb16 100644
--- a/src/flags/display.rs
+++ b/src/flags/display.rs
@@ -28,13 +28,13 @@ impl Configurable<Self> for Display {
     /// corresponding `Display` variant in a [Some]. If neither of them is passed, this returns
     /// [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("directory-only") {
+        if matches.get_one("directory-only") == Some(&true) {
             Some(Self::DirectoryOnly)
-        } else if matches.is_present("almost-all") {
+        } else if matches.get_one("almost-all") == Some(&true) {
             Some(Self::AlmostAll)
-        } else if matches.is_present("all") {
+        } else if matches.get_one::<bool>("all") == Some(&true) {
             Some(Self::All)
-        } else if matches.is_present("system-protected") {
+        } else if matches.get_one("system-protected") == Some(&true) {
             #[cfg(windows)]
             return Some(Self::SystemProtected);
 
@@ -67,14 +67,14 @@ mod test {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, Display::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_system_protected() {
         let argv = ["lsd", "--system-protected"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         #[cfg(windows)]
         assert_eq!(
             Some(Display::SystemProtected),
@@ -88,14 +88,14 @@ mod test {
     #[test]
     fn test_from_arg_matches_all() {
         let argv = ["lsd", "--all"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(Display::All), Display::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_almost_all() {
         let argv = ["lsd", "--almost-all"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(Display::AlmostAll),
             Display::from_arg_matches(&matches)
@@ -105,7 +105,7 @@ mod test {
     #[test]
     fn test_from_arg_matches_directory_only() {
         let argv = ["lsd", "--directory-only"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(Display::DirectoryOnly),
             Display::from_arg_matches(&matches)
diff --git a/src/flags/header.rs b/src/flags/header.rs
index 2991df409..7ea0d5e57 100644
--- a/src/flags/header.rs
+++ b/src/flags/header.rs
@@ -17,7 +17,7 @@ impl Configurable<Self> for Header {
     /// If the "header" argument is passed, this returns a `Header` with value `true` in a
     /// [Some]. Otherwise this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("header") {
+        if matches.get_one("header") == Some(&true) {
             Some(Self(true))
         } else {
             None
@@ -45,14 +45,14 @@ mod test {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, Header::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_true() {
         let argv = ["lsd", "--header"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(Header(true)), Header::from_arg_matches(&matches));
     }
 
diff --git a/src/flags/hyperlink.rs b/src/flags/hyperlink.rs
index bc9a706f0..215a3770e 100644
--- a/src/flags/hyperlink.rs
+++ b/src/flags/hyperlink.rs
@@ -5,7 +5,7 @@ use super::Configurable;
 
 use crate::config_file::Config;
 
-use clap::ArgMatches;
+use clap::{ArgMatches, ValueSource};
 use serde::Deserialize;
 
 /// The flag showing when to use hyperlink in the output.
@@ -37,12 +37,13 @@ impl Configurable<Self> for HyperlinkOption {
     /// a [Some]. Otherwise if the argument is passed, this returns the variant corresponding to
     /// its parameter in a [Some]. Otherwise this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("classic") {
+        if matches.get_one("classic") == Some(&true) {
             Some(Self::Never)
-        } else if matches.occurrences_of("hyperlink") > 0 {
+        } else if matches.value_source("hyperlink") == Some(ValueSource::CommandLine) {
             matches
-                .values_of("hyperlink")?
+                .get_many::<String>("hyperlink")?
                 .last()
+                .map(String::as_str)
                 .map(Self::from_arg_str)
         } else {
             None
@@ -75,14 +76,14 @@ mod test_hyperlink_option {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, HyperlinkOption::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_always() {
         let argv = ["lsd", "--hyperlink", "always"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(HyperlinkOption::Always),
             HyperlinkOption::from_arg_matches(&matches)
@@ -92,7 +93,7 @@ mod test_hyperlink_option {
     #[test]
     fn test_from_arg_matches_auto() {
         let argv = ["lsd", "--hyperlink", "auto"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(HyperlinkOption::Auto),
             HyperlinkOption::from_arg_matches(&matches)
@@ -102,7 +103,7 @@ mod test_hyperlink_option {
     #[test]
     fn test_from_arg_matches_never() {
         let argv = ["lsd", "--hyperlink", "never"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(HyperlinkOption::Never),
             HyperlinkOption::from_arg_matches(&matches)
@@ -112,7 +113,7 @@ mod test_hyperlink_option {
     #[test]
     fn test_from_arg_matches_classic_mode() {
         let argv = ["lsd", "--hyperlink", "always", "--classic"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(HyperlinkOption::Never),
             HyperlinkOption::from_arg_matches(&matches)
@@ -122,7 +123,7 @@ mod test_hyperlink_option {
     #[test]
     fn test_from_arg_matches_hyperlink_when_multi() {
         let argv = ["lsd", "--hyperlink", "always", "--hyperlink", "never"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(HyperlinkOption::Never),
             HyperlinkOption::from_arg_matches(&matches)
diff --git a/src/flags/icons.rs b/src/flags/icons.rs
index 5f1a746da..364e0b19d 100644
--- a/src/flags/icons.rs
+++ b/src/flags/icons.rs
@@ -5,7 +5,7 @@ use super::Configurable;
 
 use crate::config_file::Config;
 
-use clap::ArgMatches;
+use clap::{ArgMatches, ValueSource};
 use serde::Deserialize;
 
 /// A collection of flags on how to use icons.
@@ -65,10 +65,14 @@ impl Configurable<Self> for IconOption {
     /// a [Some]. Otherwise if the argument is passed, this returns the variant corresponding to
     /// its parameter in a [Some]. Otherwise this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("classic") {
+        if matches.get_one("classic") == Some(&true) {
             Some(Self::Never)
-        } else if matches.occurrences_of("icon") > 0 {
-            matches.values_of("icon")?.last().map(Self::from_arg_str)
+        } else if matches.value_source("icon") == Some(ValueSource::CommandLine) {
+            matches
+                .get_many::<String>("icon")?
+                .last()
+                .map(String::as_str)
+                .map(Self::from_arg_str)
         } else {
             None
         }
@@ -115,10 +119,11 @@ impl Configurable<Self> for IconTheme {
     /// If the argument is passed, this returns the variant corresponding to its parameter in a
     /// [Some]. Otherwise this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.occurrences_of("icon-theme") > 0 {
+        if matches.value_source("icon-theme") == Some(ValueSource::CommandLine) {
             matches
-                .values_of("icon-theme")?
+                .get_many::<String>("icon-theme")?
                 .last()
+                .map(String::as_str)
                 .map(Self::from_arg_str)
         } else {
             None
@@ -180,14 +185,14 @@ mod test_icon_option {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, IconOption::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_always() {
         let argv = ["lsd", "--icon", "always"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(IconOption::Always),
             IconOption::from_arg_matches(&matches)
@@ -197,7 +202,7 @@ mod test_icon_option {
     #[test]
     fn test_from_arg_matches_auto() {
         let argv = ["lsd", "--icon", "auto"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(IconOption::Auto),
             IconOption::from_arg_matches(&matches)
@@ -207,7 +212,7 @@ mod test_icon_option {
     #[test]
     fn test_from_arg_matches_never() {
         let argv = ["lsd", "--icon", "never"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(IconOption::Never),
             IconOption::from_arg_matches(&matches)
@@ -217,7 +222,7 @@ mod test_icon_option {
     #[test]
     fn test_from_arg_matches_classic_mode() {
         let argv = ["lsd", "--icon", "always", "--classic"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(IconOption::Never),
             IconOption::from_arg_matches(&matches)
@@ -227,7 +232,7 @@ mod test_icon_option {
     #[test]
     fn test_from_arg_matches_icon_when_multi() {
         let argv = ["lsd", "--icon", "always", "--icon", "never"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(IconOption::Never),
             IconOption::from_arg_matches(&matches)
@@ -296,14 +301,14 @@ mod test_icon_theme {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, IconTheme::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_fancy() {
         let argv = ["lsd", "--icon-theme", "fancy"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(IconTheme::Fancy),
             IconTheme::from_arg_matches(&matches)
@@ -313,7 +318,7 @@ mod test_icon_theme {
     #[test]
     fn test_from_arg_matches_unicode() {
         let argv = ["lsd", "--icon-theme", "unicode"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(IconTheme::Unicode),
             IconTheme::from_arg_matches(&matches)
@@ -323,7 +328,7 @@ mod test_icon_theme {
     #[test]
     fn test_from_arg_matches_icon_multi() {
         let argv = ["lsd", "--icon-theme", "fancy", "--icon-theme", "unicode"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(IconTheme::Unicode),
             IconTheme::from_arg_matches(&matches)
diff --git a/src/flags/ignore_globs.rs b/src/flags/ignore_globs.rs
index ac6e2d406..3b23db1ba 100644
--- a/src/flags/ignore_globs.rs
+++ b/src/flags/ignore_globs.rs
@@ -3,7 +3,7 @@
 
 use crate::config_file::Config;
 
-use clap::{ArgMatches, Error, ErrorKind};
+use clap::{ArgMatches, Error, ErrorKind, ValueSource};
 use globset::{Glob, GlobSet, GlobSetBuilder};
 
 /// The struct holding a [GlobSet] and methods to build it.
@@ -38,11 +38,11 @@ impl IgnoreGlobs {
     /// either the built [IgnoreGlobs] or an [Error], if any error was encountered while creating the
     /// [IgnoreGlobs]. If the argument has not been passed, this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Result<Self, Error>> {
-        if matches.occurrences_of("ignore-glob") == 0 {
+        if matches.value_source("ignore-glob") != Some(ValueSource::CommandLine) {
             return None;
         }
 
-        let values = matches.values_of("ignore-glob")?;
+        let values = matches.get_many::<String>("ignore-glob")?;
         let mut glob_set_builder = GlobSetBuilder::new();
 
         for value in values {
@@ -120,7 +120,7 @@ mod test {
     #[test]
     fn test_configuration_from_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert!(matches!(
             IgnoreGlobs::configure_from(&matches, &Config::with_none()),
             Ok(..)
@@ -130,7 +130,7 @@ mod test {
     #[test]
     fn test_configuration_from_args() {
         let argv = ["lsd", "--ignore-glob", ".git"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert!(matches!(
             IgnoreGlobs::configure_from(&matches, &Config::with_none()),
             Ok(..)
@@ -140,7 +140,7 @@ mod test {
     #[test]
     fn test_configuration_from_config() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         let mut c = Config::with_none();
         c.ignore_globs = Some(vec![".git".into()]);
         assert!(matches!(IgnoreGlobs::configure_from(&matches, &c), Ok(..)));
@@ -149,7 +149,7 @@ mod test {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert!(matches!(IgnoreGlobs::from_arg_matches(&matches), None));
     }
 
diff --git a/src/flags/indicators.rs b/src/flags/indicators.rs
index f07cd2e7e..337dac83a 100644
--- a/src/flags/indicators.rs
+++ b/src/flags/indicators.rs
@@ -17,7 +17,7 @@ impl Configurable<Self> for Indicators {
     /// If the "indicators" argument is passed, this returns an `Indicators` with value `true` in a
     /// [Some]. Otherwise this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("indicators") {
+        if matches.get_one("indicators") == Some(&true) {
             Some(Self(true))
         } else {
             None
@@ -45,14 +45,14 @@ mod test {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, Indicators::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_true() {
         let argv = ["lsd", "--classify"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(Indicators(true)),
             Indicators::from_arg_matches(&matches)
diff --git a/src/flags/layout.rs b/src/flags/layout.rs
index ecddb9392..c9dbbff38 100644
--- a/src/flags/layout.rs
+++ b/src/flags/layout.rs
@@ -26,13 +26,13 @@ impl Configurable<Layout> for Layout {
     /// arguments is greater than 1, this also returns the [OneLine](Layout::OneLine) variant.
     /// Finally if neither of them is passed, this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("tree") {
+        if matches.get_one("tree") == Some(&true) {
             Some(Self::Tree)
-        } else if matches.is_present("long")
-            || matches.is_present("oneline")
-            || matches.is_present("inode")
-            || matches.is_present("context")
-            || matches!(matches.values_of("blocks"), Some(values) if values.len() > 1)
+        } else if matches.get_one("long") == Some(&true)
+            || matches.get_one("oneline") == Some(&true)
+            || matches.get_one("inode") == Some(&true)
+            || matches.get_one("context") == Some(&true)
+            || matches!(matches.get_many::<String>("blocks"), Some(values) if values.len() > 1)
         // TODO: handle this differently
         {
             Some(Self::OneLine)
@@ -62,35 +62,35 @@ mod test {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, Layout::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_tree() {
         let argv = ["lsd", "--tree"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(Layout::Tree), Layout::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_oneline() {
         let argv = ["lsd", "--oneline"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(Layout::OneLine), Layout::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_oneline_through_long() {
         let argv = ["lsd", "--long"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(Layout::OneLine), Layout::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_oneline_through_blocks() {
         let argv = ["lsd", "--blocks", "permission,name"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(Layout::OneLine), Layout::from_arg_matches(&matches));
     }
 
diff --git a/src/flags/permission.rs b/src/flags/permission.rs
index 26333d7dc..ba6d98b3f 100644
--- a/src/flags/permission.rs
+++ b/src/flags/permission.rs
@@ -5,7 +5,7 @@ use super::Configurable;
 
 use crate::config_file::Config;
 
-use clap::ArgMatches;
+use clap::{ArgMatches, ValueSource};
 use serde::Deserialize;
 
 /// The flag showing which file permissions units to use.
@@ -38,12 +38,13 @@ impl Configurable<Self> for PermissionFlag {
     /// this returns [None].
     /// Sets permissions to rwx if classic flag is enabled.
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("classic") {
+        if matches.get_one("classic") == Some(&true) {
             Some(Self::Rwx)
-        } else if matches.occurrences_of("permission") > 0 {
+        } else if matches.value_source("permission") == Some(ValueSource::CommandLine) {
             matches
-                .values_of("permission")?
+                .get_many::<String>("permission")?
                 .last()
+                .map(String::as_str)
                 .map(Self::from_arg_str)
         } else {
             None
@@ -81,14 +82,14 @@ mod test {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, PermissionFlag::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_default() {
         let argv = ["lsd", "--permission", "rwx"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(PermissionFlag::Rwx),
             PermissionFlag::from_arg_matches(&matches)
@@ -98,7 +99,7 @@ mod test {
     #[test]
     fn test_from_arg_matches_short() {
         let argv = ["lsd", "--permission", "octal"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(PermissionFlag::Octal),
             PermissionFlag::from_arg_matches(&matches)
@@ -109,12 +110,12 @@ mod test {
     #[should_panic]
     fn test_from_arg_matches_unknown() {
         let argv = ["lsd", "--permission", "unknown"];
-        let _ = app::build().get_matches_from_safe(argv).unwrap();
+        let _ = app::build().try_get_matches_from(argv).unwrap();
     }
     #[test]
     fn test_from_arg_matches_permissions_multi() {
         let argv = ["lsd", "--permission", "octal", "--permission", "rwx"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(PermissionFlag::Rwx),
             PermissionFlag::from_arg_matches(&matches)
@@ -124,7 +125,7 @@ mod test {
     #[test]
     fn test_from_arg_matches_permissions_classic() {
         let argv = ["lsd", "--permission", "rwx", "--classic"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(PermissionFlag::Rwx),
             PermissionFlag::from_arg_matches(&matches)
diff --git a/src/flags/recursion.rs b/src/flags/recursion.rs
index 27b031179..4d9b891d5 100644
--- a/src/flags/recursion.rs
+++ b/src/flags/recursion.rs
@@ -52,7 +52,7 @@ impl Recursion {
     /// If the "recursive" argument is passed, this returns `true` in a [Some]. Otherwise this
     /// returns [None].
     fn enabled_from_arg_matches(matches: &ArgMatches) -> Option<bool> {
-        if matches.is_present("recursive") {
+        if matches.get_one("recursive") == Some(&true) {
             Some(true)
         } else {
             None
@@ -98,7 +98,7 @@ impl Recursion {
     /// If the parameter to the "depth" argument can not be parsed, this returns an [Error] in a
     /// [Some].
     fn depth_from_arg_matches(matches: &ArgMatches) -> Option<Result<usize, Error>> {
-        let depth = match matches.values_of("depth") {
+        let depth = match matches.get_many::<String>("depth") {
             Some(d) => d.last(),
             None => None,
         };
@@ -139,14 +139,14 @@ mod test {
     #[test]
     fn test_enabled_from_arg_matches_empty() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, Recursion::enabled_from_arg_matches(&matches));
     }
 
     #[test]
     fn test_enabled_from_arg_matches_true() {
         let argv = ["lsd", "--recursive"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(true), Recursion::enabled_from_arg_matches(&matches));
     }
 
@@ -154,7 +154,7 @@ mod test {
     fn test_enabled_from_empty_matches_and_config() {
         let argv = ["lsd"];
         assert!(!Recursion::enabled_from(
-            &app::build().get_matches_from_safe(argv).unwrap(),
+            &app::build().try_get_matches_from(argv).unwrap(),
             &Config::with_none()
         ));
     }
@@ -168,7 +168,7 @@ mod test {
             depth: None,
         });
         assert!(Recursion::enabled_from(
-            &app::build().get_matches_from_safe(argv).unwrap(),
+            &app::build().try_get_matches_from(argv).unwrap(),
             &c
         ));
     }
@@ -182,7 +182,7 @@ mod test {
             depth: None,
         });
         assert!(!Recursion::enabled_from(
-            &app::build().get_matches_from_safe(argv).unwrap(),
+            &app::build().try_get_matches_from(argv).unwrap(),
             &c
         ));
     }
@@ -193,14 +193,14 @@ mod test {
     #[test]
     fn test_depth_from_arg_matches_empty() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert!(matches!(Recursion::depth_from_arg_matches(&matches), None));
     }
 
     #[test]
     fn test_depth_from_arg_matches_integer() {
         let argv = ["lsd", "--depth", "42"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert!(
             matches!(Recursion::depth_from_arg_matches(&matches), Some(Ok(value)) if value == 42)
         );
@@ -209,7 +209,7 @@ mod test {
     #[test]
     fn test_depth_from_arg_matches_depth_multi() {
         let argv = ["lsd", "--depth", "4", "--depth", "2"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert!(
             matches!(Recursion::depth_from_arg_matches(&matches), Some(Ok(value)) if value == 2)
         );
@@ -218,18 +218,18 @@ mod test {
     #[test]
     fn test_depth_from_arg_matches_neg_int() {
         let argv = ["lsd", "--depth", "\\-42"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert!(
-            matches!(Recursion::depth_from_arg_matches(&matches), Some(Err(e)) if e.kind == ErrorKind::ValueValidation)
+            matches!(Recursion::depth_from_arg_matches(&matches), Some(Err(e)) if e.kind() == ErrorKind::ValueValidation)
         );
     }
 
     #[test]
     fn test_depth_from_arg_matches_non_int() {
         let argv = ["lsd", "--depth", "foo"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert!(
-            matches!(Recursion::depth_from_arg_matches(&matches), Some(Err(e)) if e.kind == ErrorKind::ValueValidation)
+            matches!(Recursion::depth_from_arg_matches(&matches), Some(Err(e)) if e.kind() == ErrorKind::ValueValidation)
         );
     }
 
@@ -239,7 +239,7 @@ mod test {
         assert_eq!(
             usize::MAX,
             Recursion::depth_from(
-                &app::build().get_matches_from_safe(argv).unwrap(),
+                &app::build().try_get_matches_from(argv).unwrap(),
                 &Config::with_none()
             )
             .unwrap()
@@ -256,7 +256,7 @@ mod test {
         });
         assert_eq!(
             42,
-            Recursion::depth_from(&app::build().get_matches_from_safe(argv).unwrap(), &c).unwrap()
+            Recursion::depth_from(&app::build().try_get_matches_from(argv).unwrap(), &c).unwrap()
         );
     }
 }
diff --git a/src/flags/size.rs b/src/flags/size.rs
index cc1fcb958..10cd7178e 100644
--- a/src/flags/size.rs
+++ b/src/flags/size.rs
@@ -5,7 +5,7 @@ use super::Configurable;
 
 use crate::config_file::Config;
 
-use clap::ArgMatches;
+use clap::{ArgMatches, ValueSource};
 use serde::Deserialize;
 
 /// The flag showing which file size units to use.
@@ -40,10 +40,14 @@ impl Configurable<Self> for SizeFlag {
     /// `SizeFlag` variant is returned in a [Some]. If neither of them is passed, this returns
     /// [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("classic") {
+        if matches.get_one("classic") == Some(&true) {
             Some(Self::Bytes)
-        } else if matches.occurrences_of("size") > 0 {
-            matches.values_of("size")?.last().map(Self::from_arg_str)
+        } else if matches.value_source("size") == Some(ValueSource::CommandLine) {
+            matches
+                .get_many::<String>("size")?
+                .last()
+                .map(String::as_str)
+                .map(Self::from_arg_str)
         } else {
             None
         }
@@ -79,14 +83,14 @@ mod test {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, SizeFlag::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_default() {
         let argv = ["lsd", "--size", "default"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(SizeFlag::Default),
             SizeFlag::from_arg_matches(&matches)
@@ -96,14 +100,14 @@ mod test {
     #[test]
     fn test_from_arg_matches_short() {
         let argv = ["lsd", "--size", "short"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(SizeFlag::Short), SizeFlag::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_bytes() {
         let argv = ["lsd", "--size", "bytes"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(SizeFlag::Bytes), SizeFlag::from_arg_matches(&matches));
     }
 
@@ -111,19 +115,19 @@ mod test {
     #[should_panic]
     fn test_from_arg_matches_unknown() {
         let argv = ["lsd", "--size", "unknown"];
-        let _ = app::build().get_matches_from_safe(argv).unwrap();
+        let _ = app::build().try_get_matches_from(argv).unwrap();
     }
     #[test]
     fn test_from_arg_matches_size_multi() {
         let argv = ["lsd", "--size", "bytes", "--size", "short"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(SizeFlag::Short), SizeFlag::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_size_classic() {
         let argv = ["lsd", "--size", "short", "--classic"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(SizeFlag::Bytes), SizeFlag::from_arg_matches(&matches));
     }
 
diff --git a/src/flags/sorting.rs b/src/flags/sorting.rs
index 76b0b47bb..84904e70d 100644
--- a/src/flags/sorting.rs
+++ b/src/flags/sorting.rs
@@ -5,7 +5,7 @@ use super::Configurable;
 
 use crate::config_file::Config;
 
-use clap::ArgMatches;
+use clap::{ArgMatches, ValueSource};
 use serde::Deserialize;
 
 /// A collection of flags on how to sort the output.
@@ -52,17 +52,19 @@ impl Configurable<Self> for SortColumn {
     /// If either the "timesort" or "sizesort" arguments are passed, this returns the corresponding
     /// `SortColumn` variant in a [Some]. Otherwise this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        let sort = matches.values_of("sort").and_then(|s| s.last());
+        let sort = matches
+            .get_many::<String>("sort")
+            .and_then(|s| s.last().map(String::as_str));
 
-        if matches.is_present("timesort") || sort == Some("time") {
+        if matches.get_one("timesort") == Some(&true) || sort == Some("time") {
             Some(Self::Time)
-        } else if matches.is_present("sizesort") || sort == Some("size") {
+        } else if matches.get_one("sizesort") == Some(&true) || sort == Some("size") {
             Some(Self::Size)
-        } else if matches.is_present("extensionsort") || sort == Some("extension") {
+        } else if matches.get_one("extensionsort") == Some(&true) || sort == Some("extension") {
             Some(Self::Extension)
-        } else if matches.is_present("versionsort") || sort == Some("version") {
+        } else if matches.get_one("versionsort") == Some(&true) || sort == Some("version") {
             Some(Self::Version)
-        } else if matches.is_present("no-sort") || sort == Some("none") {
+        } else if matches.get_one("no-sort") == Some(&true) || sort == Some("none") {
             Some(Self::None)
         } else {
             None
@@ -93,7 +95,7 @@ impl Configurable<Self> for SortOrder {
     /// If the "reverse" argument is passed, this returns [SortOrder::Reverse] in a [Some].
     /// Otherwise this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("reverse") {
+        if matches.get_one("reverse") == Some(&true) {
             Some(Self::Reverse)
         } else {
             None
@@ -143,18 +145,19 @@ impl Configurable<Self> for DirGrouping {
     /// [Some]. Otherwise if the argument is passed, this returns the variant corresponding to its
     /// parameter in a [Some]. Otherwise this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("classic") {
+        if matches.get_one("classic") == Some(&true) {
             return Some(Self::None);
         }
 
-        if matches.is_present("group-directories-first") {
+        if matches.get_one("group-directories-first") == Some(&true) {
             return Some(Self::First);
         }
 
-        if matches.occurrences_of("group-dirs") > 0 {
+        if matches.value_source("group-dirs") == Some(ValueSource::CommandLine) {
             return matches
-                .values_of("group-dirs")?
+                .get_many::<String>("group-dirs")?
                 .last()
+                .map(String::as_str)
                 .map(Self::from_arg_str);
         }
 
@@ -188,14 +191,14 @@ mod test_sort_column {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, SortColumn::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_extension() {
         let argv = ["lsd", "--extensionsort"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(SortColumn::Extension),
             SortColumn::from_arg_matches(&matches)
@@ -205,7 +208,7 @@ mod test_sort_column {
     #[test]
     fn test_from_arg_matches_time() {
         let argv = ["lsd", "--timesort"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(SortColumn::Time),
             SortColumn::from_arg_matches(&matches)
@@ -215,7 +218,7 @@ mod test_sort_column {
     #[test]
     fn test_from_arg_matches_size() {
         let argv = ["lsd", "--sizesort"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(SortColumn::Size),
             SortColumn::from_arg_matches(&matches)
@@ -225,7 +228,7 @@ mod test_sort_column {
     #[test]
     fn test_from_arg_matches_version() {
         let argv = ["lsd", "--versionsort"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(SortColumn::Version),
             SortColumn::from_arg_matches(&matches)
@@ -235,7 +238,7 @@ mod test_sort_column {
     #[test]
     fn test_from_arg_matches_no_sort() {
         let argv = ["lsd", "--no-sort"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(SortColumn::None),
             SortColumn::from_arg_matches(&matches)
@@ -245,35 +248,35 @@ mod test_sort_column {
     #[test]
     fn test_from_arg_matches_sort() {
         let argv = ["lsd", "--sort", "time"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(SortColumn::Time),
             SortColumn::from_arg_matches(&matches)
         );
 
         let argv = ["lsd", "--sort", "size"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(SortColumn::Size),
             SortColumn::from_arg_matches(&matches)
         );
 
         let argv = ["lsd", "--sort", "extension"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(SortColumn::Extension),
             SortColumn::from_arg_matches(&matches)
         );
 
         let argv = ["lsd", "--sort", "version"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(SortColumn::Version),
             SortColumn::from_arg_matches(&matches)
         );
 
         let argv = ["lsd", "--sort", "none"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(SortColumn::None),
             SortColumn::from_arg_matches(&matches)
@@ -283,7 +286,7 @@ mod test_sort_column {
     #[test]
     fn test_multi_sort() {
         let argv = ["lsd", "--sort", "size", "--sort", "time"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(SortColumn::Time),
             SortColumn::from_arg_matches(&matches)
@@ -293,7 +296,7 @@ mod test_sort_column {
     #[test]
     fn test_multi_sort_use_last() {
         let argv = ["lsd", "--sort", "size", "-t", "-S", "-X", "--sort", "time"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(SortColumn::Time),
             SortColumn::from_arg_matches(&matches)
@@ -384,14 +387,14 @@ mod test_sort_order {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, SortOrder::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_reverse() {
         let argv = ["lsd", "--reverse"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(SortOrder::Reverse),
             SortOrder::from_arg_matches(&matches)
@@ -462,14 +465,14 @@ mod test_dir_grouping {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, DirGrouping::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_first() {
         let argv = ["lsd", "--group-dirs", "first"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(DirGrouping::First),
             DirGrouping::from_arg_matches(&matches)
@@ -479,7 +482,7 @@ mod test_dir_grouping {
     #[test]
     fn test_from_arg_matches_last() {
         let argv = ["lsd", "--group-dirs", "last"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(DirGrouping::Last),
             DirGrouping::from_arg_matches(&matches)
@@ -489,7 +492,7 @@ mod test_dir_grouping {
     #[test]
     fn test_from_arg_matches_explicit_none() {
         let argv = ["lsd", "--group-dirs", "none"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(DirGrouping::None),
             DirGrouping::from_arg_matches(&matches)
@@ -499,7 +502,7 @@ mod test_dir_grouping {
     #[test]
     fn test_from_arg_matches_classic_mode() {
         let argv = ["lsd", "--group-dirs", "first", "--classic"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(DirGrouping::None),
             DirGrouping::from_arg_matches(&matches)
@@ -509,7 +512,7 @@ mod test_dir_grouping {
     #[test]
     fn test_from_arg_matches_group_dirs_multi() {
         let argv = ["lsd", "--group-dirs", "first", "--group-dirs", "last"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(DirGrouping::Last),
             DirGrouping::from_arg_matches(&matches)
@@ -519,7 +522,7 @@ mod test_dir_grouping {
     #[test]
     fn test_from_arg_matches_group_directories_first() {
         let argv = ["lsd", "--group-directories-first"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             Some(DirGrouping::First),
             DirGrouping::from_arg_matches(&matches)
diff --git a/src/flags/symlink_arrow.rs b/src/flags/symlink_arrow.rs
index b42379ada..feee6ddf6 100644
--- a/src/flags/symlink_arrow.rs
+++ b/src/flags/symlink_arrow.rs
@@ -61,11 +61,11 @@ mod test {
 
     #[test]
     fn test_symlink_arrow_from_args_none() {
-        use clap::App;
+        use clap::Command;
         let empty_args: [String; 0] = [];
         assert_eq!(
             None,
-            SymlinkArrow::from_arg_matches(&App::new("lsd").get_matches_from(empty_args))
+            SymlinkArrow::from_arg_matches(&Command::new("lsd").get_matches_from(empty_args))
         );
     }
 
diff --git a/src/flags/symlinks.rs b/src/flags/symlinks.rs
index 6afc5c497..101c809b4 100644
--- a/src/flags/symlinks.rs
+++ b/src/flags/symlinks.rs
@@ -17,7 +17,7 @@ impl Configurable<Self> for NoSymlink {
     /// If the "no-symlink" argument is passed, this returns a `NoSymlink` with value `true` in a
     /// [Some]. Otherwise this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("no-symlink") {
+        if matches.get_one("no-symlink") == Some(&true) {
             Some(Self(true))
         } else {
             None
@@ -45,14 +45,14 @@ mod test {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, NoSymlink::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_true() {
         let argv = ["lsd", "--no-symlink"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(NoSymlink(true)), NoSymlink::from_arg_matches(&matches));
     }
 
diff --git a/src/flags/total_size.rs b/src/flags/total_size.rs
index 76370529e..8a1931cc0 100644
--- a/src/flags/total_size.rs
+++ b/src/flags/total_size.rs
@@ -17,7 +17,7 @@ impl Configurable<Self> for TotalSize {
     /// If the "total-size" argument is passed, this returns a `TotalSize` with value `true` in a
     /// [Some]. Otherwise this returns [None].
     fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
-        if matches.is_present("total-size") {
+        if matches.get_one("total-size") == Some(&true) {
             Some(Self(true))
         } else {
             None
@@ -45,14 +45,14 @@ mod test {
     #[test]
     fn test_from_arg_matches_none() {
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(None, TotalSize::from_arg_matches(&matches));
     }
 
     #[test]
     fn test_from_arg_matches_true() {
         let argv = ["lsd", "--total-size"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(Some(TotalSize(true)), TotalSize::from_arg_matches(&matches));
     }
 
diff --git a/src/main.rs b/src/main.rs
index a0f54f03f..f6d2530f1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -38,6 +38,8 @@ mod meta;
 mod sort;
 mod theme;
 
+use clap::ValueSource;
+
 use crate::config_file::Config;
 use crate::core::Core;
 use crate::flags::Flags;
@@ -112,16 +114,16 @@ fn main() {
     // * to all files matched
     // '*' remain as '*'
     let inputs = matches
-        .values_of("FILE")
+        .get_many::<String>("FILE")
         .expect("failed to retrieve cli value")
         .map(PathBuf::from)
         .collect();
 
-    let config = if matches.is_present("ignore-config") {
+    let config = if matches.get_one("ignore-config") == Some(&true) {
         Config::with_none()
-    } else if matches.is_present("config-file") {
+    } else if matches.value_source("config-file") == Some(ValueSource::CommandLine) {
         let path = matches
-            .value_of("config-file")
+            .get_one::<String>("config-file")
             .expect("Invalid config file path");
 
         Config::from_file(path).expect("Provided file path is invalid")
diff --git a/src/meta/symlink.rs b/src/meta/symlink.rs
index 224d4fc4c..f7b296b5f 100644
--- a/src/meta/symlink.rs
+++ b/src/meta/symlink.rs
@@ -87,7 +87,7 @@ mod tests {
             valid: true,
         };
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             format!("{}", " ⇒ /target"),
             link.render(
@@ -105,7 +105,7 @@ mod tests {
             valid: false,
         };
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             format!("{}", " ⇒ /target"),
             link.render(
@@ -123,7 +123,7 @@ mod tests {
             valid: false,
         };
         let argv = ["lsd"];
-        let matches = app::build().get_matches_from_safe(argv).unwrap();
+        let matches = app::build().try_get_matches_from(argv).unwrap();
         assert_eq!(
             format!("{}", " ⇒ \u{1b}[38;5;124m/target\u{1b}[39m"),
             link.render(


Test patch:
diff --git a/tests/integration.rs b/tests/integration.rs
index 37747925c..c2d9cca5c 100644
--- a/tests/integration.rs
+++ b/tests/integration.rs
@@ -769,3 +769,16 @@ fn test_all_directory() {
         .assert()
         .stdout(predicate::str::is_match(".").unwrap());
 }
+
+#[test]
+fn test_multiple_files() {
+    let dir = tempdir();
+    dir.child("one").touch().unwrap();
+    dir.child("two").touch().unwrap();
+
+    cmd()
+        .arg(dir.path().join("one"))
+        .arg(dir.path().join("two"))
+        .assert()
+        .stdout(predicate::str::is_match(".").unwrap());
+}