dankeyy il y a 2 ans
Parent
commit
b853d273fa
2 fichiers modifiés avec 57 ajouts et 4 suppressions
  1. 12 2
      src/options/file_name.rs
  2. 45 2
      src/output/file_name.rs

+ 12 - 2
src/options/file_name.rs

@@ -2,15 +2,16 @@ use crate::options::{flags, OptionsError, NumberSource};
 use crate::options::parser::MatchedFlags;
 use crate::options::parser::MatchedFlags;
 use crate::options::vars::{self, Vars};
 use crate::options::vars::{self, Vars};
 
 
-use crate::output::file_name::{Options, Classify, ShowIcons};
+use crate::output::file_name::{Options, Classify, ShowIcons, EmbedHyperlinks};
 
 
 
 
 impl Options {
 impl Options {
     pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
     pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
         let classify = Classify::deduce(matches)?;
         let classify = Classify::deduce(matches)?;
         let show_icons = ShowIcons::deduce(matches, vars)?;
         let show_icons = ShowIcons::deduce(matches, vars)?;
+        let embed_hyperlinks = EmbedHyperlinks::deduce(matches)?;
 
 
-        Ok(Self { classify, show_icons })
+        Ok(Self { classify, show_icons, embed_hyperlinks })
     }
     }
 }
 }
 
 
@@ -44,3 +45,12 @@ impl ShowIcons {
         }
         }
     }
     }
 }
 }
+
+impl EmbedHyperlinks {
+    fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
+        let flagged = matches.has(&flags::HYPERLINK)?;
+
+        if flagged { Ok(Self::On) }
+              else { Ok(Self::Off) }
+    }
+}

+ 45 - 2
src/output/file_name.rs

@@ -19,6 +19,9 @@ pub struct Options {
 
 
     /// Whether to prepend icon characters before file names.
     /// Whether to prepend icon characters before file names.
     pub show_icons: ShowIcons,
     pub show_icons: ShowIcons,
+    
+    /// Whether to make file names hyperlinks.
+    pub embed_hyperlinks: EmbedHyperlinks,
 }
 }
 
 
 impl Options {
 impl Options {
@@ -84,6 +87,13 @@ pub enum ShowIcons {
     On(u32),
     On(u32),
 }
 }
 
 
+/// Whether to embed hyperlinks.
+#[derive(PartialEq, Eq, Debug, Copy, Clone)]
+pub enum EmbedHyperlinks{
+    
+    Off,
+    On,
+}
 
 
 /// A **file name** holds all the information necessary to display the name
 /// A **file name** holds all the information necessary to display the name
 /// of the given file. This is used in all of the views.
 /// of the given file. This is used in all of the views.
@@ -171,6 +181,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
                         let target_options = Options {
                         let target_options = Options {
                             classify: Classify::JustFilenames,
                             classify: Classify::JustFilenames,
                             show_icons: ShowIcons::Off,
                             show_icons: ShowIcons::Off,
+                            embed_hyperlinks: EmbedHyperlinks::Off,
                         };
                         };
 
 
                         let target_name = FileName {
                         let target_name = FileName {
@@ -276,6 +287,39 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
         }
         }
     }
     }
 
 
+    pub fn escape(&self, bits: &mut Vec<ANSIString<'_>>, good: Style, bad: Style) {
+        let string = self.file.name.to_owned();
+
+        if string.chars().all(|c| c >= 0x20 as char && c != 0x7f as char) {
+            let painted = good.paint(string);
+
+            let adjusted_filename = if let EmbedHyperlinks::On = self.options.embed_hyperlinks {
+                ANSIString::from(format!("\x1B]8;;{}\x1B\x5C{}\x1B]8;;\x1B\x5C", self.file.path.display(), painted))
+            } else {
+                painted
+            };
+            bits.push(adjusted_filename);
+            return;
+        }
+
+        for c in string.chars() {
+            // The `escape_default` method on `char` is *almost* what we want here, but
+            // it still escapes non-ASCII UTF-8 characters, which are still printable.
+
+            if c >= 0x20 as char && c != 0x7f as char {
+                // TODO: This allocates way too much,
+                // hence the `all` check above.
+                let mut s = String::new();
+                s.push(c);
+                bits.push(good.paint(s));
+            }
+            else {
+                let s = c.escape_default().collect::<String>();
+                bits.push(bad.paint(s));
+            }
+        }
+    }
+
     /// Returns at least one ANSI-highlighted string representing this file’s
     /// Returns at least one ANSI-highlighted string representing this file’s
     /// name using the given set of colours.
     /// name using the given set of colours.
     ///
     ///
@@ -290,8 +334,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
         let file_style = self.style();
         let file_style = self.style();
         let mut bits = Vec::new();
         let mut bits = Vec::new();
 
 
-        escape(
-            self.file.name.clone(),
+        self.escape(
             &mut bits,
             &mut bits,
             file_style,
             file_style,
             self.colours.control_char(),
             self.colours.control_char(),