From 48ea6ca81cc300478b12baa606e7c111be328a64 Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Fri, 31 Jul 2026 09:53:42 +0700 Subject: [PATCH] send custom emoji --- Cargo.lock | 1 + crates/chat_ui/Cargo.toml | 1 + crates/chat_ui/src/lib.rs | 19 ++++++++++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 994d91d..47a1743 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1087,6 +1087,7 @@ dependencies = [ "nostr-sdk", "person", "pulldown-cmark", + "regex", "serde", "settings", "smallvec", diff --git a/crates/chat_ui/Cargo.toml b/crates/chat_ui/Cargo.toml index fd2c1f1..23c2f28 100644 --- a/crates/chat_ui/Cargo.toml +++ b/crates/chat_ui/Cargo.toml @@ -25,4 +25,5 @@ serde.workspace = true linkify = "0.10.0" pulldown-cmark = "0.13.1" +regex = "1" diff --git a/crates/chat_ui/src/lib.rs b/crates/chat_ui/src/lib.rs index 2b14ab7..f4c885d 100644 --- a/crates/chat_ui/src/lib.rs +++ b/crates/chat_ui/src/lib.rs @@ -1,5 +1,5 @@ use std::collections::{BTreeMap, HashMap, HashSet}; -use std::sync::{Arc, RwLock}; +use std::sync::{Arc, LazyLock, RwLock}; pub use actions::*; use anyhow::{Context as AnyhowContext, Error}; @@ -17,6 +17,7 @@ use gpui::{ use itertools::Itertools; use nostr_sdk::prelude::*; use person::{Person, PersonRegistry}; +use regex::Regex; use settings::{AppSettings, SignerKind}; use smallvec::{SmallVec, smallvec}; use state::{NostrRegistry, upload}; @@ -38,6 +39,11 @@ use crate::text::RenderedText; const REACTION_EMOJIS: &[&str] = &["👍", "👎", "😄", "🎉", "😕", "❤️", "🚀", "👀"]; const COMPACT_REACTION_EMOJIS: &[&str] = &["👍", "❤️", "👀"]; +/// Regex matching strings that consist entirely of emoji characters, +/// zero-width joiners, variation selectors, and keycap combiners. +static EMOJI_RE: LazyLock = + LazyLock::new(|| Regex::new(r"^[\p{Emoji}\u{200D}\u{FE0F}\u{20E3}]+$").unwrap()); + mod actions; mod text; @@ -361,6 +367,17 @@ impl ChatPanel { return; } + // If replying to exactly one message with only a valid emoji, + // send as a reaction instead of a text message + if replies.len() == 1 && EMOJI_RE.is_match(&content) && self.attachments.read(cx).is_empty() + { + for reply in &replies { + self.send_reaction(&content, reply, window, cx); + } + self.clear(window, cx); + return; + } + self.send_message(&content, replies, false, window, cx); }