diff --git a/README.md b/README.md index b14ac67..fef2726 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,8 @@ ctrl-p = "select_channel_modal previous" [keybindings.message_selected] alt-y = "" alt-w = "copy_message selected" +ctrl-t = "react :thumbsup:" +ctrl-h = "react ❤️" ``` ## License diff --git a/src/app.rs b/src/app.rs index 2ca93b3..f613c24 100644 --- a/src/app.rs +++ b/src/app.rs @@ -318,9 +318,9 @@ impl App { Command::ToggleMultiline => { self.is_multiline_input = !self.is_multiline_input; } - Command::React => { + Command::React(reaction) => { if let Some(idx) = self.channels.state.selected() { - self.add_reaction(idx).await; + self.add_reaction(idx, reaction).await; } } Command::OpenUrl => { @@ -441,8 +441,12 @@ impl App { } } - pub async fn add_reaction(&mut self, channel_idx: usize) -> Option<()> { - let reaction = self.take_reaction()?; + pub async fn add_reaction( + &mut self, + channel_idx: usize, + reaction: Option, + ) -> Option<()> { + let reaction = reaction.or_else(|| self.take_reaction()?); let channel = self.storage.channel(self.channels.items[channel_idx])?; let message = self.selected_message()?; let remove = reaction.is_none(); @@ -1653,7 +1657,7 @@ impl HandleReactionOptions { } /// Returns an emoji string if `s` is an emoji or if `s` is a GitHub emoji shortcode. -fn to_emoji(s: &str) -> Option<&str> { +pub fn to_emoji(s: &str) -> Option<&str> { let s = s.trim(); if emojis::get(s).is_some() { Some(s) @@ -1839,7 +1843,7 @@ pub(crate) mod tests { .select(Some(0)); app.get_input().put_char('👍'); - app.add_reaction(0).await; + app.add_reaction(0, None).await; let arrived_at = app.messages[&channel_id].items[0]; let reactions = &app @@ -1865,7 +1869,7 @@ pub(crate) mod tests { for c in ":thumbsup:".chars() { app.get_input().put_char(c); } - app.add_reaction(0).await; + app.add_reaction(0, None).await; let arrived_at = app.messages[&channel_id].items[0]; let reactions = &app @@ -1896,7 +1900,7 @@ pub(crate) mod tests { .into_owned(); message.reactions.push((app.user_id, "👍".to_string())); app.storage.store_message(channel_id, message); - app.add_reaction(0).await; + app.add_reaction(0, None).await; let reactions = &app .storage @@ -1919,7 +1923,7 @@ pub(crate) mod tests { for c in ":thumbsup".chars() { app.get_input().put_char(c); } - app.add_reaction(0).await; + app.add_reaction(0, None).await; assert_eq!(app.get_input().data, ":thumbsup"); let arrived_at = app.messages[&channel_id].items[0]; diff --git a/src/command.rs b/src/command.rs index 5ddec99..256356f 100644 --- a/src/command.rs +++ b/src/command.rs @@ -5,6 +5,8 @@ use crokey::KeyCombination; use serde::{Deserialize, Serialize}; use strum::{EnumIter, EnumProperty, EnumString, VariantNames}; +use crate::app::to_emoji; + pub type KeybindingConfig = HashMap; pub type ModeKeybindingConfig = HashMap; pub type Keybinding = HashMap; @@ -161,7 +163,7 @@ pub enum Command { #[strum(props(desc = "Switch between single-line and multi-line modes."))] ToggleMultiline, #[strum(props(desc = "Sends emoji from input line as reaction on selected message."))] - React, + React(Option), #[strum(props(desc = "Scroll a widget", usage = "scroll help up|down entry"))] #[strum(serialize = "scroll", to_string = "scroll {0} {1} {2}")] Scroll(Widget, DirectionVertical, MoveAmountVisual), @@ -376,6 +378,19 @@ fn parse(input: &str) -> Result { Ok(Command::CopyMessage(selector)) // Ok(Command::CopyMessage(MessageSelector::from_str(args.first().unwrap_or(&""))?)) } + Command::React(_) => { + let usage = E::InsufficientArgs { + cmd: cmd_str.to_string(), + hint: Some("Optional emoji or :emoji code:".into()), + }; + match args.first() { + None => Ok(Command::React(None)), + Some(&s) => match to_emoji(s) { + Some(em) => Ok(Command::React(Some(em.into()))), + None => Err(usage), + }, + } + } _ => Ok(cmd), } }