Bladeren bron

Stop collecting ls_colors into a hashmap

LSColors used to be built up from an iterator, and then queried later. But because the resulting HashMap gets queried in serial anyway, we might as well pass in a callback instead, saving the allocation.

This is also technically a little faster because styles that don’t map to anything (like `zz`) are no longer parsed.
Benjamin Sago 8 jaren geleden
bovenliggende
commit
504a0dd6b7
2 gewijzigde bestanden met toevoegingen van 86 en 90 verwijderingen
  1. 15 12
      src/options/colours.rs
  2. 71 78
      src/style/lsc.rs

+ 15 - 12
src/options/colours.rs

@@ -76,18 +76,21 @@ impl Colours {
 
         if let Some(lsc) = vars.get(vars::LS_COLORS) {
             let lsc = lsc.to_string_lossy();
-            let lsc = LSColors::parse(lsc.as_ref());
-
-            if let Some(c) = lsc.get("di") { colours.filekinds.directory    = c; }
-            if let Some(c) = lsc.get("ex") { colours.filekinds.executable   = c; }
-            if let Some(c) = lsc.get("fi") { colours.filekinds.normal       = c; }
-            if let Some(c) = lsc.get("pi") { colours.filekinds.pipe         = c; }
-            if let Some(c) = lsc.get("so") { colours.filekinds.socket       = c; }
-            if let Some(c) = lsc.get("bd") { colours.filekinds.block_device = c; }
-            if let Some(c) = lsc.get("cd") { colours.filekinds.char_device  = c; }
-            if let Some(c) = lsc.get("ln") { colours.filekinds.symlink      = c; }
-            if let Some(c) = lsc.get("or") { colours.broken_arrow           = c; }
-            if let Some(c) = lsc.get("mi") { colours.broken_filename        = c; }
+            LSColors(lsc.as_ref()).each_pair(|pair| {
+                match pair.key {
+                    "di" => colours.filekinds.directory    = pair.to_style(),
+                    "ex" => colours.filekinds.executable   = pair.to_style(),
+                    "fi" => colours.filekinds.normal       = pair.to_style(),
+                    "pi" => colours.filekinds.pipe         = pair.to_style(),
+                    "so" => colours.filekinds.socket       = pair.to_style(),
+                    "bd" => colours.filekinds.block_device = pair.to_style(),
+                    "cd" => colours.filekinds.char_device  = pair.to_style(),
+                    "ln" => colours.filekinds.symlink      = pair.to_style(),
+                    "or" => colours.broken_arrow           = pair.to_style(),
+                    "mi" => colours.broken_filename        = pair.to_style(),
+                     _   => {/* don’t change anything */},
+                }
+            })
         }
 
         Ok(colours)

+ 71 - 78
src/style/lsc.rs

@@ -1,69 +1,66 @@
-#![allow(dead_code)]
-
-use std::collections::HashMap;
+use std::ops::FnMut;
 
 use ansi_term::Style;
 use ansi_term::Colour::*;
 
 
-pub struct LSColors<'var> {
-    contents: HashMap<&'var str, &'var str>
-}
+pub struct LSColors<'var>(pub &'var str);
 
 impl<'var> LSColors<'var> {
-    pub fn parse(input: &'var str) -> LSColors<'var> {
-        let contents = input.split(":")
-                            .flat_map(|mapping| {
-
-            let bits = mapping.split("=")
-                              .take(3)
-                              .collect::<Vec<_>>();
-
-            if bits.len() != 2 || bits[0].is_empty() || bits[1].is_empty() { None }
-            else { Some( (bits[0], bits[1]) ) }
-        }).collect();
-        LSColors { contents }
+    pub fn each_pair<C>(&mut self, mut callback: C) where C: FnMut(Pair<'var>) -> () {
+        for next in self.0.split(":") {
+            let bits = next.split("=")
+                           .take(3)
+                           .collect::<Vec<_>>();
+
+            if bits.len() == 2 && !bits[0].is_empty() && !bits[1].is_empty() {
+                callback(Pair { key: bits[0], value: bits[1] });
+            }
+        }
     }
+}
 
-    pub fn get(&self, facet_name: &str) -> Option<Style> {
-        self.contents.get(facet_name).map(ansi_to_style)
-    }
+pub struct Pair<'var> {
+    pub key: &'var str,
+    pub value: &'var str,
 }
 
-fn ansi_to_style(ansi: &&str) -> Style {
-    let mut style = Style::default();
-
-    for num in ansi.split(";") {
-        match num {
-
-            // Bold and italic
-            "1"  => style = style.bold(),
-            "4"  => style = style.underline(),
-
-            // Foreground colours
-            "30" => style = style.fg(Black),
-            "31" => style = style.fg(Red),
-            "32" => style = style.fg(Green),
-            "33" => style = style.fg(Yellow),
-            "34" => style = style.fg(Blue),
-            "35" => style = style.fg(Purple),
-            "36" => style = style.fg(Cyan),
-            "37" => style = style.fg(White),
-
-            // Background colours
-            "40" => style = style.on(Black),
-            "41" => style = style.on(Red),
-            "42" => style = style.on(Green),
-            "43" => style = style.on(Yellow),
-            "44" => style = style.on(Blue),
-            "45" => style = style.on(Purple),
-            "46" => style = style.on(Cyan),
-            "47" => style = style.on(White),
-             _    => {/* ignore the error and do nothing */},
+impl<'var> Pair<'var> {
+    pub fn to_style(&self) -> Style {
+        let mut style = Style::default();
+
+        for num in self.value.split(";") {
+            match num {
+
+                // Bold and italic
+                "1"  => style = style.bold(),
+                "4"  => style = style.underline(),
+
+                // Foreground colours
+                "30" => style = style.fg(Black),
+                "31" => style = style.fg(Red),
+                "32" => style = style.fg(Green),
+                "33" => style = style.fg(Yellow),
+                "34" => style = style.fg(Blue),
+                "35" => style = style.fg(Purple),
+                "36" => style = style.fg(Cyan),
+                "37" => style = style.fg(White),
+
+                // Background colours
+                "40" => style = style.on(Black),
+                "41" => style = style.on(Red),
+                "42" => style = style.on(Green),
+                "43" => style = style.on(Yellow),
+                "44" => style = style.on(Blue),
+                "45" => style = style.on(Purple),
+                "46" => style = style.on(Cyan),
+                "47" => style = style.on(White),
+                 _    => {/* ignore the error and do nothing */},
+            }
         }
-    }
 
-    style
+        style
+    }
 }
 
 
@@ -76,7 +73,7 @@ mod ansi_test {
         ($name:ident: $input:expr => $result:expr) => {
             #[test]
             fn $name() {
-                assert_eq!(ansi_to_style(&$input), $result);
+                assert_eq!(Pair { key: "", value: $input }.to_style(), $result);
             }
         };
     }
@@ -105,44 +102,40 @@ mod test {
     use super::*;
 
     macro_rules! test {
-        ($name:ident: $input:expr, $facet:expr => $result:expr) => {
+        ($name:ident: $input:expr => $result:expr) => {
             #[test]
             fn $name() {
-                let lsc = LSColors::parse($input);
-                assert_eq!(lsc.get($facet), $result.into());
-                assert_eq!(lsc.get(""), None);
+                let mut lscs = Vec::new();
+                LSColors($input).each_pair(|p| lscs.push( (p.key.clone(), p.to_style()) ));
+                assert_eq!(lscs, $result.to_vec());
             }
         };
     }
 
     // Bad parses
-    test!(empty:    "",       "di" => None);
-    test!(jibber:   "blah",   "di" => None);
+    test!(empty:    ""       => []);
+    test!(jibber:   "blah"   => []);
 
-    test!(equals:     "=",    "di" => None);
-    test!(starts:     "=di",  "di" => None);
-    test!(ends:     "id=",    "id" => None);
+    test!(equals:     "="    => []);
+    test!(starts:     "=di"  => []);
+    test!(ends:     "id="    => []);
 
     // Foreground colours
-    test!(red:     "di=31",   "di" => Red.normal());
-    test!(green:   "cb=32",   "cb" => Green.normal());
-    test!(blue:    "la=34",   "la" => Blue.normal());
+    test!(green:   "cb=32"   => [ ("cb", Green.normal()) ]);
+    test!(red:     "di=31"   => [ ("di", Red.normal()) ]);
+    test!(blue:    "la=34"   => [ ("la", Blue.normal()) ]);
 
     // Background colours
-    test!(yellow:  "do=43",   "do" => Style::default().on(Yellow));
-    test!(purple:  "re=45",   "re" => Style::default().on(Purple));
-    test!(cyan:    "mi=46",   "mi" => Style::default().on(Cyan));
+    test!(yellow:  "do=43"   => [ ("do", Style::default().on(Yellow)) ]);
+    test!(purple:  "re=45"   => [ ("re", Style::default().on(Purple)) ]);
+    test!(cyan:    "mi=46"   => [ ("mi", Style::default().on(Cyan)) ]);
 
     // Bold and underline
-    test!(bold:    "fa=1",    "fa" => Style::default().bold());
-    test!(under:   "so=4",    "so" => Style::default().underline());
-    test!(both:    "la=1;4",  "la" => Style::default().bold().underline());
+    test!(bold:    "fa=1"    => [ ("fa", Style::default().bold()) ]);
+    test!(under:   "so=4"    => [ ("so", Style::default().underline()) ]);
+    test!(both:    "la=1;4"  => [ ("la", Style::default().bold().underline()) ]);
 
     // More and many
-    test!(more_1:  "me=43;21;55;34:yu=1;4;1", "me" => Blue.on(Yellow));
-    test!(more_2:  "me=43;21;55;34:yu=1;4;1", "yu" => Style::default().bold().underline());
-
-    test!(many_1:  "red=31:green=32:blue=34", "red"   => Red.normal());
-    test!(many_2:  "red=31:green=32:blue=34", "green" => Green.normal());
-    test!(many_3:  "red=31:green=32:blue=34", "blue"  => Blue.normal());
+    test!(more:  "me=43;21;55;34:yu=1;4;1"  => [ ("me", Blue.on(Yellow)), ("yu", Style::default().bold().underline()) ]);
+    test!(many:  "red=31:green=32:blue=34"  => [ ("red", Red.normal()), ("green", Green.normal()), ("blue", Blue.normal()) ]);
 }