From bb4754e38ae80aad628bab3163d43a69883ba883 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Mon, 17 Aug 2020 15:53:59 +0300 Subject: [PATCH] themes/shortcuts: preserve order of keys --- src/components.rs | 8 +++---- src/components/utilities.rs | 10 +++----- src/conf/shortcuts.rs | 4 ++-- src/conf/themes.rs | 47 +++++++++++++++++++------------------ 4 files changed, 32 insertions(+), 37 deletions(-) diff --git a/src/components.rs b/src/components.rs index 8ec0085d..da367348 100644 --- a/src/components.rs +++ b/src/components.rs @@ -46,15 +46,13 @@ pub mod svg; use std::fmt; use std::fmt::{Debug, Display}; -use std::collections::HashMap; +use indexmap::IndexMap; use uuid::Uuid; -use super::{Key, StatusEvent, UIEvent}; - pub type ComponentId = Uuid; -pub type ShortcutMap = HashMap<&'static str, Key>; -pub type ShortcutMaps = HashMap<&'static str, ShortcutMap>; +pub type ShortcutMap = IndexMap<&'static str, Key>; +pub type ShortcutMaps = IndexMap<&'static str, ShortcutMap>; /// Types implementing this Trait can draw on the terminal and receive events. /// If a type wants to skip drawing if it has not changed anything, it can hold some flag in its diff --git a/src/components/utilities.rs b/src/components/utilities.rs index c3eab524..eab4aef9 100644 --- a/src/components/utilities.rs +++ b/src/components/utilities.rs @@ -610,7 +610,7 @@ impl Component for Pager { self.dirty = value; } fn get_shortcuts(&self, context: &Context) -> ShortcutMaps { - let config_map: HashMap<&'static str, Key> = context.settings.shortcuts.pager.key_values(); + let config_map: IndexMap<&'static str, Key> = context.settings.shortcuts.pager.key_values(); let mut ret: ShortcutMaps = Default::default(); ret.insert(Pager::DESCRIPTION, config_map); ret @@ -1438,9 +1438,7 @@ impl Component for Tabbed { let mut max_width = "Press ? to close, use COMMAND \"search\" to find shortcuts".len() + 3; - let mut shortcuts = children_maps.iter().collect::>(); - shortcuts.sort_by_key(|(k, _)| *k); - for (desc, shortcuts) in shortcuts.iter() { + for (desc, shortcuts) in children_maps.iter() { max_length += shortcuts.len() + 3; max_width = std::cmp::max( max_width, @@ -1508,7 +1506,7 @@ impl Component for Tabbed { ); } let mut idx = 2; - for (desc, shortcuts) in shortcuts.iter() { + for (desc, shortcuts) in children_maps.iter() { write_string_to_grid( desc, &mut self.help_content, @@ -1519,8 +1517,6 @@ impl Component for Tabbed { None, ); idx += 2; - let mut shortcuts = shortcuts.iter().collect::>(); - shortcuts.sort_unstable_by_key(|(ref k, _)| *k); for (k, v) in shortcuts { debug!(&(k, v)); let (x, y) = write_string_to_grid( diff --git a/src/conf/shortcuts.rs b/src/conf/shortcuts.rs index 21b222e7..5478e563 100644 --- a/src/conf/shortcuts.rs +++ b/src/conf/shortcuts.rs @@ -21,8 +21,8 @@ use super::DotAddressable; use crate::terminal::Key; +use indexmap::IndexMap; use melib::{MeliError, Result}; -use std::collections::HashMap; #[macro_export] macro_rules! shortcut { @@ -121,7 +121,7 @@ macro_rules! shortcut_key_values { } } /// Returns a hashmap of all shortcuts and their values - pub fn key_values(&self) -> HashMap<&'static str, Key> { + pub fn key_values(&self) -> IndexMap<&'static str, Key> { [ $((stringify!($fname),(self.$fname).clone()),)* ].iter().cloned().collect() diff --git a/src/conf/themes.rs b/src/conf/themes.rs index a00d878b..1c83262d 100644 --- a/src/conf/themes.rs +++ b/src/conf/themes.rs @@ -30,11 +30,12 @@ use crate::terminal::{Attr, Color}; use crate::Context; +use indexmap::IndexMap; use melib::{MeliError, Result}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use smallvec::SmallVec; use std::borrow::Cow; -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; #[inline(always)] pub fn value(context: &Context, key: &'static str) -> ThemeAttribute { @@ -486,16 +487,16 @@ impl<'de> Deserialize<'de> for ThemeValue { pub struct Themes { pub light: Theme, pub dark: Theme, - pub other_themes: HashMap, + pub other_themes: IndexMap, } #[derive(Debug, Clone)] pub struct Theme { - color_aliases: HashMap, ThemeValue>, - attr_aliases: HashMap, ThemeValue>, + color_aliases: IndexMap, ThemeValue>, + attr_aliases: IndexMap, ThemeValue>, #[cfg(feature = "regexp")] - text_format_regexps: HashMap, SmallVec<[TextFormatterSetting; 32]>>, - pub keys: HashMap, ThemeAttributeInner>, + text_format_regexps: IndexMap, SmallVec<[TextFormatterSetting; 32]>>, + pub keys: IndexMap, ThemeAttributeInner>, } #[cfg(feature = "regexp")] @@ -734,14 +735,14 @@ mod regexp { use std::ops::{Deref, DerefMut}; impl Deref for Theme { - type Target = HashMap, ThemeAttributeInner>; + type Target = IndexMap, ThemeAttributeInner>; fn deref(&self) -> &Self::Target { &self.keys } } impl DerefMut for Theme { - fn deref_mut(&mut self) -> &mut HashMap, ThemeAttributeInner> { + fn deref_mut(&mut self) -> &mut IndexMap, ThemeAttributeInner> { &mut self.keys } } @@ -766,19 +767,19 @@ impl<'de> Deserialize<'de> for Themes { #[serde(default)] dark: ThemeOptions, #[serde(flatten, default)] - other_themes: HashMap, + other_themes: IndexMap, } #[derive(Deserialize, Default)] struct ThemeOptions { #[serde(default)] - color_aliases: HashMap, ThemeValue>, + color_aliases: IndexMap, ThemeValue>, #[serde(default)] - attr_aliases: HashMap, ThemeValue>, + attr_aliases: IndexMap, ThemeValue>, #[cfg(feature = "regexp")] #[serde(default)] - text_format_regexps: HashMap, HashMap>, + text_format_regexps: IndexMap, IndexMap>, #[serde(flatten, default)] - keys: HashMap, ThemeAttributeInnerOptions>, + keys: IndexMap, ThemeAttributeInnerOptions>, } #[cfg(feature = "regexp")] #[derive(Deserialize, Default)] @@ -1284,9 +1285,9 @@ impl Themes { impl Default for Themes { fn default() -> Themes { - let mut light = HashMap::default(); - let mut dark = HashMap::default(); - let other_themes = HashMap::default(); + let mut light = IndexMap::default(); + let mut dark = IndexMap::default(); + let other_themes = IndexMap::default(); macro_rules! add { ($key:literal, $($theme:ident={ $($name:ident : $val:expr),*$(,)? }),*$(,)?) => { @@ -1684,9 +1685,9 @@ impl Serialize for Themes { where S: Serializer, { - let mut dark: HashMap, ThemeAttribute> = Default::default(); - let mut light: HashMap, ThemeAttribute> = Default::default(); - let mut other_themes: HashMap = Default::default(); + let mut dark: IndexMap, ThemeAttribute> = Default::default(); + let mut light: IndexMap, ThemeAttribute> = Default::default(); + let mut other_themes: IndexMap = Default::default(); for k in self.dark.keys() { dark.insert( @@ -1711,7 +1712,7 @@ impl Serialize for Themes { } for (name, t) in self.other_themes.iter() { - let mut new_map: HashMap, ThemeAttribute> = Default::default(); + let mut new_map: IndexMap, ThemeAttribute> = Default::default(); for k in t.keys() { new_map.insert( @@ -1746,8 +1747,8 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> { fn is_cyclic_util<'a>( course: Course, k: &'a Cow<'static, str>, - visited: &mut HashMap<(&'a Cow<'static, str>, Course), bool>, - stack: &mut HashMap<(&'a Cow<'static, str>, Course), bool>, + visited: &mut IndexMap<(&'a Cow<'static, str>, Course), bool>, + stack: &mut IndexMap<(&'a Cow<'static, str>, Course), bool>, path: &mut SmallVec<[(&'a Cow<'static, str>, Course); 16]>, theme: &'a Theme, ) -> bool { @@ -1954,7 +1955,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> { .keys() .map(|k| ((k, Course::AttrAlias), false)), ) - .collect::, Course), bool>>(); + .collect::, Course), bool>>(); let mut stack = visited.clone(); for k in theme.keys() {