ui: shortcuts refactoring

jmap
Manos Pitsidianakis 2019-11-18 22:20:18 +02:00
parent 8798d84e43
commit f1588f6002
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
11 changed files with 73 additions and 90 deletions

View File

@ -78,7 +78,7 @@ const _DOUBLE_UP_AND_RIGHT: char = '╚';
type ComponentId = Uuid;
pub type ShortcutMap = FnvHashMap<&'static str, Key>;
pub type ShortcutMaps = FnvHashMap<String, ShortcutMap>;
pub type ShortcutMaps = FnvHashMap<&'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

View File

@ -552,7 +552,7 @@ impl Component for ContactList {
let shortcuts = &self.get_shortcuts(context)[Self::DESCRIPTION];
match *event {
UIEvent::Input(ref key)
if *key == shortcuts["create_contact"] && self.view.is_none() =>
if key == shortcuts["create_contact"] && self.view.is_none() =>
{
let mut manager = ContactManager::default();
manager.set_parent_id(self.id);
@ -565,7 +565,7 @@ impl Component for ContactList {
}
UIEvent::Input(ref key)
if *key == shortcuts["edit_contact"] && self.length > 0 && self.view.is_none() =>
if key == shortcuts["edit_contact"] && self.length > 0 && self.view.is_none() =>
{
let account = &mut context.accounts[self.account_pos];
let book = &mut account.address_book;
@ -580,7 +580,7 @@ impl Component for ContactList {
return true;
}
UIEvent::Input(ref key) if *key == shortcuts["next_account"] && self.view.is_none() => {
UIEvent::Input(ref key) if key == shortcuts["next_account"] && self.view.is_none() => {
let amount = if self.cmd_buf.is_empty() {
1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
@ -612,7 +612,7 @@ impl Component for ContactList {
return true;
}
UIEvent::Input(ref key) if *key == shortcuts["prev_account"] && self.view.is_none() => {
UIEvent::Input(ref key) if key == shortcuts["prev_account"] && self.view.is_none() => {
let amount = if self.cmd_buf.is_empty() {
1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
@ -747,13 +747,7 @@ impl Component for ContactList {
.unwrap_or_default();
let config_map = context.settings.shortcuts.contact_list.key_values();
map.insert(
self.to_string(),
config_map
.into_iter()
.map(|(k, v)| (k, v.clone()))
.collect(),
);
map.insert(Self::DESCRIPTION, config_map);
map
}

View File

@ -1034,10 +1034,8 @@ impl Component for Composer {
Default::default()
};
let mut our_map: ShortcutMap = Default::default();
our_map.insert("Deliver draft to mailer.", Key::Char('s'));
our_map.insert("Edit in $EDITOR", Key::Char('e'));
map.insert(Composer::DESCRIPTION.to_string(), our_map);
let our_map: ShortcutMap = context.settings.shortcuts.composing.key_values();
map.insert(Composer::DESCRIPTION, our_map);
map
}

View File

@ -508,7 +508,7 @@ impl Component for Listing {
self.component.set_movement(PageMovement::Down(amount));
return true;
}
UIEvent::Input(ref key) if *key == shortcuts["prev_page"] => {
UIEvent::Input(ref key) if key == shortcuts["prev_page"] => {
let mult = if self.cmd_buf.is_empty() {
1
} else if let Ok(mult) = self.cmd_buf.parse::<usize>() {
@ -527,7 +527,7 @@ impl Component for Listing {
self.component.set_movement(PageMovement::PageUp(mult));
return true;
}
UIEvent::Input(ref key) if *key == shortcuts["next_page"] => {
UIEvent::Input(ref key) if key == shortcuts["next_page"] => {
let mult = if self.cmd_buf.is_empty() {
1
} else if let Ok(mult) = self.cmd_buf.parse::<usize>() {
@ -564,7 +564,7 @@ impl Component for Listing {
.push_back(UIEvent::Action(Tab(NewDraft(self.cursor_pos.0, None))));
return true;
}
UIEvent::Input(ref key) if *key == shortcuts["search"] => {
UIEvent::Input(ref key) if key == shortcuts["search"] => {
context
.replies
.push_back(UIEvent::ExInput(Key::Paste("filter ".to_string())));
@ -573,7 +573,7 @@ impl Component for Listing {
.push_back(UIEvent::ChangeMode(UIMode::Execute));
return true;
}
UIEvent::Input(ref key) if *key == shortcuts["set_seen"] => {
UIEvent::Input(ref key) if key == shortcuts["set_seen"] => {
let mut event = UIEvent::Action(Action::Listing(ListingAction::SetSeen));
if match self.component {
Plain(ref mut l) => l.process_event(&mut event, context),
@ -647,13 +647,7 @@ impl Component for Listing {
Conversations(ref l) => l.get_shortcuts(context),
};
let config_map = context.settings.shortcuts.listing.key_values();
map.insert(
Listing::DESCRIPTION.to_string(),
config_map
.into_iter()
.map(|(k, v)| (k, v.clone()))
.collect(),
);
map.insert(Listing::DESCRIPTION, config_map);
map
}

View File

@ -1066,7 +1066,7 @@ impl Component for CompactListing {
let shortcuts = &self.get_shortcuts(context)[CompactListing::DESCRIPTION];
if self.length > 0 {
match *event {
UIEvent::Input(ref k) if !self.unfocused && *k == shortcuts["open_thread"] => {
UIEvent::Input(ref k) if !self.unfocused && k == shortcuts["open_thread"] => {
if self.filtered_selection.is_empty() {
self.view = ThreadView::new(self.cursor_pos, None, context);
} else {
@ -1087,7 +1087,7 @@ impl Component for CompactListing {
self.dirty = true;
return true;
}
UIEvent::Input(ref k) if self.unfocused && *k == shortcuts["exit_thread"] => {
UIEvent::Input(ref k) if self.unfocused && k == shortcuts["exit_thread"] => {
self.unfocused = false;
self.dirty = true;
/* If self.row_updates is not empty and we exit a thread, the row_update events
@ -1096,7 +1096,7 @@ impl Component for CompactListing {
self.force_draw = true;
return true;
}
UIEvent::Input(ref key) if !self.unfocused && *key == shortcuts["select_entry"] => {
UIEvent::Input(ref key) if !self.unfocused && key == shortcuts["select_entry"] => {
let thread_hash = self.get_thread_under_cursor(self.cursor_pos.2, context);
self.selection.entry(thread_hash).and_modify(|e| *e = !*e);
}
@ -1306,13 +1306,7 @@ impl Component for CompactListing {
};
let config_map = context.settings.shortcuts.compact_listing.key_values();
map.insert(
CompactListing::DESCRIPTION.to_string(),
config_map
.into_iter()
.map(|(k, v)| (k, v.clone()))
.collect(),
);
map.insert(CompactListing::DESCRIPTION, config_map);
map
}

View File

@ -1013,7 +1013,7 @@ impl Component for ConversationsListing {
let shortcuts = &self.get_shortcuts(context)[ConversationsListing::DESCRIPTION];
if self.length > 0 {
match *event {
UIEvent::Input(ref k) if !self.unfocused && *k == shortcuts["open_thread"] => {
UIEvent::Input(ref k) if !self.unfocused && k == shortcuts["open_thread"] => {
if self.length == 0 {
return true;
}
@ -1039,7 +1039,7 @@ impl Component for ConversationsListing {
self.dirty = true;
return true;
}
UIEvent::Input(ref k) if self.unfocused && *k == shortcuts["exit_thread"] => {
UIEvent::Input(ref k) if self.unfocused && k == shortcuts["exit_thread"] => {
self.unfocused = false;
self.dirty = true;
/* If self.row_updates is not empty and we exit a thread, the row_update events
@ -1048,7 +1048,7 @@ impl Component for ConversationsListing {
self.force_draw = true;
return true;
}
UIEvent::Input(ref key) if !self.unfocused && *key == shortcuts["select_entry"] => {
UIEvent::Input(ref key) if !self.unfocused && key == shortcuts["select_entry"] => {
let thread_hash = self.get_thread_under_cursor(self.cursor_pos.2, context);
self.selection.entry(thread_hash).and_modify(|e| *e = !*e);
return true;
@ -1263,13 +1263,7 @@ impl Component for ConversationsListing {
};
let config_map = context.settings.shortcuts.compact_listing.key_values();
map.insert(
ConversationsListing::DESCRIPTION.to_string(),
config_map
.into_iter()
.map(|(k, v)| (k, v.clone()))
.collect(),
);
map.insert(ConversationsListing::DESCRIPTION, config_map);
map
}

View File

@ -894,7 +894,7 @@ impl Component for PlainListing {
let shortcuts = &self.get_shortcuts(context)[PlainListing::DESCRIPTION];
if self.length > 0 {
match *event {
UIEvent::Input(ref k) if !self.unfocused && *k == shortcuts["open_thread"] => {
UIEvent::Input(ref k) if !self.unfocused && k == shortcuts["open_thread"] => {
let env_hash = self.get_env_under_cursor(self.cursor_pos.2, context);
let temp = (self.cursor_pos.0, self.cursor_pos.1, env_hash);
self.view = MailView::new(temp, None, None);
@ -902,7 +902,7 @@ impl Component for PlainListing {
self.dirty = true;
return true;
}
UIEvent::Input(ref k) if self.unfocused && *k == shortcuts["exit_thread"] => {
UIEvent::Input(ref k) if self.unfocused && k == shortcuts["exit_thread"] => {
self.unfocused = false;
self.dirty = true;
/* If self.row_updates is not empty and we exit a thread, the row_update events
@ -911,7 +911,7 @@ impl Component for PlainListing {
self.force_draw = true;
return true;
}
UIEvent::Input(ref key) if !self.unfocused && *key == shortcuts["select_entry"] => {
UIEvent::Input(ref key) if !self.unfocused && key == shortcuts["select_entry"] => {
let env_hash = self.get_env_under_cursor(self.cursor_pos.2, context);
self.selection.entry(env_hash).and_modify(|e| *e = !*e);
}
@ -1074,13 +1074,7 @@ impl Component for PlainListing {
};
let config_map = context.settings.shortcuts.compact_listing.key_values();
map.insert(
PlainListing::DESCRIPTION.to_string(),
config_map
.into_iter()
.map(|(k, v)| (k, v.clone()))
.collect(),
);
map.insert(PlainListing::DESCRIPTION, config_map);
map
}

View File

@ -693,7 +693,7 @@ impl Component for MailView {
let shortcuts = &self.get_shortcuts(context)[MailView::DESCRIPTION];
match *event {
UIEvent::Input(ref k) if *k == shortcuts["reply"] => {
UIEvent::Input(ref k) if k == shortcuts["reply"] => {
let account = &context.accounts[self.coordinates.0];
let folder_hash = account[self.coordinates.1].unwrap().folder.hash();
let envelope: EnvelopeRef = account.collection.get_env(self.coordinates.2);
@ -710,7 +710,7 @@ impl Component for MailView {
))));
return true;
}
UIEvent::Input(ref k) if *k == shortcuts["edit"] => {
UIEvent::Input(ref k) if k == shortcuts["edit"] => {
context.replies.push_back(UIEvent::Action(Tab(Edit(
self.coordinates.0,
self.coordinates.2,
@ -719,7 +719,7 @@ impl Component for MailView {
}
UIEvent::Input(ref key)
if !self.mode.is_contact_selector()
&& *key == shortcuts["add_addresses_to_contacts"] =>
&& key == shortcuts["add_addresses_to_contacts"] =>
{
let account = &context.accounts[self.coordinates.0];
let envelope: EnvelopeRef = account.collection.get_env(self.coordinates.2);
@ -766,7 +766,7 @@ impl Component for MailView {
}
UIEvent::Input(ref key)
if (self.mode == ViewMode::Normal || self.mode == ViewMode::Subview)
&& *key == shortcuts["view_raw_source"] =>
&& key == shortcuts["view_raw_source"] =>
{
self.mode = ViewMode::Raw;
self.set_dirty();
@ -777,7 +777,7 @@ impl Component for MailView {
|| self.mode == ViewMode::Subview
|| self.mode == ViewMode::Url
|| self.mode == ViewMode::Raw)
&& *key == shortcuts["return_to_normal_view"] =>
&& key == shortcuts["return_to_normal_view"] =>
{
self.mode = ViewMode::Normal;
self.set_dirty();
@ -786,7 +786,7 @@ impl Component for MailView {
UIEvent::Input(ref key)
if (self.mode == ViewMode::Normal || self.mode == ViewMode::Subview)
&& !self.cmd_buf.is_empty()
&& *key == shortcuts["open_mailcap"] =>
&& key == shortcuts["open_mailcap"] =>
{
let lidx = self.cmd_buf.parse::<usize>().unwrap();
self.cmd_buf.clear();
@ -843,7 +843,7 @@ impl Component for MailView {
}
}
UIEvent::Input(ref key)
if *key == shortcuts["open_attachment"]
if key == shortcuts["open_attachment"]
&& !self.cmd_buf.is_empty()
&& (self.mode == ViewMode::Normal || self.mode == ViewMode::Subview) =>
{
@ -975,7 +975,7 @@ impl Component for MailView {
}
};
}
UIEvent::Input(ref key) if *key == shortcuts["toggle_expand_headers"] => {
UIEvent::Input(ref key) if key == shortcuts["toggle_expand_headers"] => {
self.expand_headers = !self.expand_headers;
self.dirty = true;
return true;
@ -983,7 +983,7 @@ impl Component for MailView {
UIEvent::Input(ref key)
if !self.cmd_buf.is_empty()
&& self.mode == ViewMode::Url
&& *key == shortcuts["go_to_url"] =>
&& key == shortcuts["go_to_url"] =>
{
let lidx = self.cmd_buf.parse::<usize>().unwrap();
self.cmd_buf.clear();
@ -1041,7 +1041,7 @@ impl Component for MailView {
}
UIEvent::Input(ref key)
if (self.mode == ViewMode::Normal || self.mode == ViewMode::Url)
&& *key == shortcuts["toggle_url_mode"] =>
&& key == shortcuts["toggle_url_mode"] =>
{
match self.mode {
ViewMode::Normal => self.mode = ViewMode::Url,
@ -1338,7 +1338,7 @@ impl Component for MailView {
our_map.insert("toggle_url_mode", Key::Char('u'));
}
our_map.insert("toggle_expand_headers", Key::Char('h'));
map.insert(MailView::DESCRIPTION.to_string(), our_map);
map.insert(MailView::DESCRIPTION, our_map);
map
}

View File

@ -1074,7 +1074,7 @@ impl Component for ThreadView {
let config_map = context.settings.shortcuts.compact_listing.key_values();
map.insert(
ThreadView::DESCRIPTION.to_string(),
ThreadView::DESCRIPTION,
[
("reverse thread order", Key::Ctrl('r')),
("toggle_mailview", Key::Char('p')),

View File

@ -311,7 +311,6 @@ impl Pager {
pub fn update_from_str(&mut self, text: &str, width: Option<usize>) {
let lines: Vec<String> = text.split_lines_reflow(self.reflow, width);
debug!(&lines);
let height = lines.len() + 2;
let width = width.unwrap_or_else(|| lines.iter().map(|l| l.len()).max().unwrap_or(0));
let ascii_drawing = self.content.ascii_drawing;
@ -616,23 +615,11 @@ impl Component for Pager {
self.dirty = true;
}
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
let config_map: FnvHashMap<&'static str, &Key> =
let config_map: FnvHashMap<&'static str, Key> =
context.settings.shortcuts.pager.key_values();
[(
Pager::DESCRIPTION.to_string(),
[
("scroll_up", (*config_map["scroll_up"]).clone()),
("scroll_down", (*config_map["scroll_down"]).clone()),
("page_up", (*config_map["page_up"]).clone()),
("page_down", (*config_map["page_down"]).clone()),
]
.iter()
.cloned()
.collect::<ShortcutMap>(),
)]
.iter()
.cloned()
.collect()
let mut ret: ShortcutMaps = Default::default();
ret.insert(Pager::DESCRIPTION, config_map);
ret
}
fn id(&self) -> ComponentId {
@ -1382,7 +1369,9 @@ impl Component for Tabbed {
get_x(bottom_right!(area)).saturating_sub(3),
),
);
let children_maps = self.children[self.cursor_pos].get_shortcuts(context);
let mut children_maps = self.children[self.cursor_pos].get_shortcuts(context);
let our_map = self.get_shortcuts(context);
children_maps.extend(our_map.into_iter());
if children_maps.is_empty() {
return;
}
@ -1508,6 +1497,8 @@ impl Component for Tabbed {
self.dirty = false;
}
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
let our_shortcuts = self.get_shortcuts(context);
let shortcuts: &ShortcutMap = &our_shortcuts["general"];
match *event {
UIEvent::Input(Key::Alt(no)) if no >= '1' && no <= '9' => {
let no = no as usize - '1' as usize;
@ -1524,7 +1515,7 @@ impl Component for Tabbed {
}
return true;
}
UIEvent::Input(Key::Char('T')) => {
UIEvent::Input(ref key) if *key == shortcuts["next_tab"] => {
self.cursor_pos = (self.cursor_pos + 1) % self.children.len();
context
.replies
@ -1664,6 +1655,12 @@ impl Component for Tabbed {
self.id = id;
}
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
let mut map = ShortcutMaps::default();
map.insert("general", context.settings.shortcuts.general.key_values());
map
}
fn can_quit_cleanly(&mut self, context: &Context) -> bool {
for (i, c) in self.children.iter_mut().enumerate() {
if !c.can_quit_cleanly(context) {

View File

@ -4,9 +4,13 @@ use fnv::FnvHashMap;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Shortcuts {
#[serde(flatten)]
pub general: GeneralShortcuts,
#[serde(flatten)]
pub listing: ListingShortcuts,
#[serde(flatten)]
pub composing: ComposingShortcuts,
#[serde(flatten)]
pub compact_listing: CompactListingShortcuts,
#[serde(flatten)]
pub contact_list: ContactListShortcuts,
@ -38,9 +42,9 @@ macro_rules! shortcut_key_values {
}
}
/// Returns a hashmap of all shortcuts and their values
pub fn key_values(&self) -> FnvHashMap<&'static str, &Key> {
pub fn key_values(&self) -> FnvHashMap<&'static str, Key> {
[
$((stringify!($fname),&(self.$fname)),)*
$((stringify!($fname),(self.$fname).clone()),)*
].iter().cloned().collect()
}
}
@ -100,3 +104,17 @@ shortcut_key_values! { "pager",
page_down: Key |> "Go to next pager page" |> Key::PageDown
}
}
shortcut_key_values! { "general",
pub struct GeneralShortcuts {
next_tab: Key |> "Next tab." |> Key::Char('T'),
go_to_tab: Key |> "Go to the nth tab" |> Key::Alt('n')
}
}
shortcut_key_values! { "composing",
pub struct ComposingShortcuts {
send_mail: Key |> "Deliver draft to mailer" |> Key::Char('s'),
edit_mail: Key |> "Edit mail." |> Key::Char('e')
}
}