themes/shortcuts: preserve order of keys

memfd
Manos Pitsidianakis 2020-08-17 15:53:59 +03:00
parent 8a6bf3b217
commit bb4754e38a
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
4 changed files with 32 additions and 37 deletions

View File

@ -46,15 +46,13 @@ pub mod svg;
use std::fmt; use std::fmt;
use std::fmt::{Debug, Display}; use std::fmt::{Debug, Display};
use std::collections::HashMap; use indexmap::IndexMap;
use uuid::Uuid; use uuid::Uuid;
use super::{Key, StatusEvent, UIEvent};
pub type ComponentId = Uuid; pub type ComponentId = Uuid;
pub type ShortcutMap = HashMap<&'static str, Key>; pub type ShortcutMap = IndexMap<&'static str, Key>;
pub type ShortcutMaps = HashMap<&'static str, ShortcutMap>; pub type ShortcutMaps = IndexMap<&'static str, ShortcutMap>;
/// Types implementing this Trait can draw on the terminal and receive events. /// 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 /// If a type wants to skip drawing if it has not changed anything, it can hold some flag in its

View File

@ -610,7 +610,7 @@ impl Component for Pager {
self.dirty = value; self.dirty = value;
} }
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps { 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(); let mut ret: ShortcutMaps = Default::default();
ret.insert(Pager::DESCRIPTION, config_map); ret.insert(Pager::DESCRIPTION, config_map);
ret ret
@ -1438,9 +1438,7 @@ impl Component for Tabbed {
let mut max_width = let mut max_width =
"Press ? to close, use COMMAND \"search\" to find shortcuts".len() + 3; "Press ? to close, use COMMAND \"search\" to find shortcuts".len() + 3;
let mut shortcuts = children_maps.iter().collect::<Vec<_>>(); for (desc, shortcuts) in children_maps.iter() {
shortcuts.sort_by_key(|(k, _)| *k);
for (desc, shortcuts) in shortcuts.iter() {
max_length += shortcuts.len() + 3; max_length += shortcuts.len() + 3;
max_width = std::cmp::max( max_width = std::cmp::max(
max_width, max_width,
@ -1508,7 +1506,7 @@ impl Component for Tabbed {
); );
} }
let mut idx = 2; let mut idx = 2;
for (desc, shortcuts) in shortcuts.iter() { for (desc, shortcuts) in children_maps.iter() {
write_string_to_grid( write_string_to_grid(
desc, desc,
&mut self.help_content, &mut self.help_content,
@ -1519,8 +1517,6 @@ impl Component for Tabbed {
None, None,
); );
idx += 2; idx += 2;
let mut shortcuts = shortcuts.iter().collect::<Vec<_>>();
shortcuts.sort_unstable_by_key(|(ref k, _)| *k);
for (k, v) in shortcuts { for (k, v) in shortcuts {
debug!(&(k, v)); debug!(&(k, v));
let (x, y) = write_string_to_grid( let (x, y) = write_string_to_grid(

View File

@ -21,8 +21,8 @@
use super::DotAddressable; use super::DotAddressable;
use crate::terminal::Key; use crate::terminal::Key;
use indexmap::IndexMap;
use melib::{MeliError, Result}; use melib::{MeliError, Result};
use std::collections::HashMap;
#[macro_export] #[macro_export]
macro_rules! shortcut { macro_rules! shortcut {
@ -121,7 +121,7 @@ macro_rules! shortcut_key_values {
} }
} }
/// Returns a hashmap of all shortcuts and their 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()),)* $((stringify!($fname),(self.$fname).clone()),)*
].iter().cloned().collect() ].iter().cloned().collect()

View File

@ -30,11 +30,12 @@
use crate::terminal::{Attr, Color}; use crate::terminal::{Attr, Color};
use crate::Context; use crate::Context;
use indexmap::IndexMap;
use melib::{MeliError, Result}; use melib::{MeliError, Result};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::{HashMap, HashSet}; use std::collections::HashSet;
#[inline(always)] #[inline(always)]
pub fn value(context: &Context, key: &'static str) -> ThemeAttribute { pub fn value(context: &Context, key: &'static str) -> ThemeAttribute {
@ -486,16 +487,16 @@ impl<'de> Deserialize<'de> for ThemeValue<Color> {
pub struct Themes { pub struct Themes {
pub light: Theme, pub light: Theme,
pub dark: Theme, pub dark: Theme,
pub other_themes: HashMap<String, Theme>, pub other_themes: IndexMap<String, Theme>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Theme { pub struct Theme {
color_aliases: HashMap<Cow<'static, str>, ThemeValue<Color>>, color_aliases: IndexMap<Cow<'static, str>, ThemeValue<Color>>,
attr_aliases: HashMap<Cow<'static, str>, ThemeValue<Attr>>, attr_aliases: IndexMap<Cow<'static, str>, ThemeValue<Attr>>,
#[cfg(feature = "regexp")] #[cfg(feature = "regexp")]
text_format_regexps: HashMap<Cow<'static, str>, SmallVec<[TextFormatterSetting; 32]>>, text_format_regexps: IndexMap<Cow<'static, str>, SmallVec<[TextFormatterSetting; 32]>>,
pub keys: HashMap<Cow<'static, str>, ThemeAttributeInner>, pub keys: IndexMap<Cow<'static, str>, ThemeAttributeInner>,
} }
#[cfg(feature = "regexp")] #[cfg(feature = "regexp")]
@ -734,14 +735,14 @@ mod regexp {
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
impl Deref for Theme { impl Deref for Theme {
type Target = HashMap<Cow<'static, str>, ThemeAttributeInner>; type Target = IndexMap<Cow<'static, str>, ThemeAttributeInner>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.keys &self.keys
} }
} }
impl DerefMut for Theme { impl DerefMut for Theme {
fn deref_mut(&mut self) -> &mut HashMap<Cow<'static, str>, ThemeAttributeInner> { fn deref_mut(&mut self) -> &mut IndexMap<Cow<'static, str>, ThemeAttributeInner> {
&mut self.keys &mut self.keys
} }
} }
@ -766,19 +767,19 @@ impl<'de> Deserialize<'de> for Themes {
#[serde(default)] #[serde(default)]
dark: ThemeOptions, dark: ThemeOptions,
#[serde(flatten, default)] #[serde(flatten, default)]
other_themes: HashMap<String, ThemeOptions>, other_themes: IndexMap<String, ThemeOptions>,
} }
#[derive(Deserialize, Default)] #[derive(Deserialize, Default)]
struct ThemeOptions { struct ThemeOptions {
#[serde(default)] #[serde(default)]
color_aliases: HashMap<Cow<'static, str>, ThemeValue<Color>>, color_aliases: IndexMap<Cow<'static, str>, ThemeValue<Color>>,
#[serde(default)] #[serde(default)]
attr_aliases: HashMap<Cow<'static, str>, ThemeValue<Attr>>, attr_aliases: IndexMap<Cow<'static, str>, ThemeValue<Attr>>,
#[cfg(feature = "regexp")] #[cfg(feature = "regexp")]
#[serde(default)] #[serde(default)]
text_format_regexps: HashMap<Cow<'static, str>, HashMap<String, RegexpOptions>>, text_format_regexps: IndexMap<Cow<'static, str>, IndexMap<String, RegexpOptions>>,
#[serde(flatten, default)] #[serde(flatten, default)]
keys: HashMap<Cow<'static, str>, ThemeAttributeInnerOptions>, keys: IndexMap<Cow<'static, str>, ThemeAttributeInnerOptions>,
} }
#[cfg(feature = "regexp")] #[cfg(feature = "regexp")]
#[derive(Deserialize, Default)] #[derive(Deserialize, Default)]
@ -1284,9 +1285,9 @@ impl Themes {
impl Default for Themes { impl Default for Themes {
fn default() -> Themes { fn default() -> Themes {
let mut light = HashMap::default(); let mut light = IndexMap::default();
let mut dark = HashMap::default(); let mut dark = IndexMap::default();
let other_themes = HashMap::default(); let other_themes = IndexMap::default();
macro_rules! add { macro_rules! add {
($key:literal, $($theme:ident={ $($name:ident : $val:expr),*$(,)? }),*$(,)?) => { ($key:literal, $($theme:ident={ $($name:ident : $val:expr),*$(,)? }),*$(,)?) => {
@ -1684,9 +1685,9 @@ impl Serialize for Themes {
where where
S: Serializer, S: Serializer,
{ {
let mut dark: HashMap<Cow<'static, str>, ThemeAttribute> = Default::default(); let mut dark: IndexMap<Cow<'static, str>, ThemeAttribute> = Default::default();
let mut light: HashMap<Cow<'static, str>, ThemeAttribute> = Default::default(); let mut light: IndexMap<Cow<'static, str>, ThemeAttribute> = Default::default();
let mut other_themes: HashMap<String, _> = Default::default(); let mut other_themes: IndexMap<String, _> = Default::default();
for k in self.dark.keys() { for k in self.dark.keys() {
dark.insert( dark.insert(
@ -1711,7 +1712,7 @@ impl Serialize for Themes {
} }
for (name, t) in self.other_themes.iter() { for (name, t) in self.other_themes.iter() {
let mut new_map: HashMap<Cow<'static, str>, ThemeAttribute> = Default::default(); let mut new_map: IndexMap<Cow<'static, str>, ThemeAttribute> = Default::default();
for k in t.keys() { for k in t.keys() {
new_map.insert( new_map.insert(
@ -1746,8 +1747,8 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
fn is_cyclic_util<'a>( fn is_cyclic_util<'a>(
course: Course, course: Course,
k: &'a Cow<'static, str>, k: &'a Cow<'static, str>,
visited: &mut HashMap<(&'a Cow<'static, str>, Course), bool>, visited: &mut IndexMap<(&'a Cow<'static, str>, Course), bool>,
stack: &mut HashMap<(&'a Cow<'static, str>, Course), bool>, stack: &mut IndexMap<(&'a Cow<'static, str>, Course), bool>,
path: &mut SmallVec<[(&'a Cow<'static, str>, Course); 16]>, path: &mut SmallVec<[(&'a Cow<'static, str>, Course); 16]>,
theme: &'a Theme, theme: &'a Theme,
) -> bool { ) -> bool {
@ -1954,7 +1955,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
.keys() .keys()
.map(|k| ((k, Course::AttrAlias), false)), .map(|k| ((k, Course::AttrAlias), false)),
) )
.collect::<HashMap<(&Cow<'static, str>, Course), bool>>(); .collect::<IndexMap<(&Cow<'static, str>, Course), bool>>();
let mut stack = visited.clone(); let mut stack = visited.clone();
for k in theme.keys() { for k in theme.keys() {