Skip to content

Commit 43a7739

Browse files
committed
feat(multiverse): Add a /invite command
1 parent bf134f0 commit 43a7739

File tree

2 files changed

+87
-14
lines changed

2 files changed

+87
-14
lines changed

labs/multiverse/src/widgets/room_view/input.rs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,28 @@
1+
use clap::{Parser, Subcommand};
12
use crossterm::event::KeyEvent;
3+
use matrix_sdk::ruma::OwnedUserId;
24
use matrix_sdk_ui::room_list_service::Room;
35
use ratatui::{prelude::*, widgets::*};
46
use style::palette::tailwind;
57
use tui_textarea::TextArea;
68

9+
#[derive(Debug, Parser)]
10+
#[command(name = "multiverse", disable_help_flag = true, disable_help_subcommand = true)]
11+
struct Cli {
12+
#[command(subcommand)]
13+
command: Command,
14+
}
15+
16+
#[derive(Debug, Subcommand)]
17+
pub enum Command {
18+
Invite { user_id: OwnedUserId },
19+
}
20+
21+
pub enum MessageOrCommand {
22+
Message(String),
23+
Command(Command),
24+
}
25+
726
/// A widget representing a text input to send messages to a room.
827
#[derive(Default)]
928
pub struct Input {
@@ -25,10 +44,20 @@ impl Input {
2544
}
2645

2746
/// Get the currently input text.
28-
pub fn get_text(&self) -> String {
29-
// TODO: Parse some commands using clap here and return an enum that might be a
30-
// string or a parsed command.
31-
self.textarea.lines().join("\n")
47+
pub fn get_input(&self) -> Result<MessageOrCommand, clap::Error> {
48+
let input = self.textarea.lines().join("\n");
49+
50+
if let Some(input) = input.strip_prefix("/") {
51+
let arguments = input.split_whitespace();
52+
53+
// Clap expects the first argument to be the binary name, like when a command is invoked
54+
// on the command line. Since we aren't a command line, but still find clap a neat
55+
// command parser, let's give it what it expects so we can parse our commands.
56+
Cli::try_parse_from(std::iter::once("multiverse").chain(arguments))
57+
.map(|cli| MessageOrCommand::Command(cli.command))
58+
} else {
59+
Ok(MessageOrCommand::Message(input))
60+
}
3261
}
3362

3463
/// Is the input area empty, returns false if the user hasn't input anything

labs/multiverse/src/widgets/room_view/mod.rs

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ use std::{ops::Deref, sync::Arc};
22

33
use color_eyre::Result;
44
use crossterm::event::{Event, KeyCode, KeyModifiers};
5+
use input::MessageOrCommand;
56
use invited_room::InvitedRoomView;
67
use matrix_sdk::{
78
locks::Mutex,
89
ruma::{
910
api::client::receipt::create_receipt::v3::ReceiptType,
10-
events::room::message::RoomMessageEventContent, OwnedRoomId,
11+
events::room::message::RoomMessageEventContent, OwnedRoomId, OwnedUserId,
1112
},
1213
RoomState,
1314
};
@@ -74,16 +75,18 @@ impl RoomView {
7475
match (key.modifiers, key.code) {
7576
(KeyModifiers::NONE, Enter) => {
7677
if !self.input.is_empty() {
77-
let message = self.input.get_text();
78+
let message_or_command = self.input.get_input();
7879

79-
match self.send_message(message).await {
80-
Ok(_) => {
81-
self.input.clear();
80+
match message_or_command {
81+
Ok(MessageOrCommand::Message(message)) => {
82+
self.send_message(message).await
83+
}
84+
Ok(MessageOrCommand::Command(command)) => {
85+
self.handle_command(command).await
8286
}
83-
Err(err) => {
84-
self.status_handle.set_message(format!(
85-
"error when sending event: {err}"
86-
));
87+
Err(e) => {
88+
self.status_handle.set_message(e.render().to_string());
89+
self.input.clear();
8790
}
8891
}
8992
}
@@ -261,7 +264,48 @@ impl RoomView {
261264
};
262265
}
263266

264-
pub async fn send_message(&self, message: String) -> Result<()> {
267+
async fn invite_member(&mut self, user_id: OwnedUserId) {
268+
let Some(room) = self
269+
.selected_room
270+
.as_deref()
271+
.and_then(|room_id| self.ui_rooms.lock().get(room_id).cloned())
272+
else {
273+
self.status_handle
274+
.set_message(format!("Coulnd't find the room object to invite {user_id}"));
275+
return;
276+
};
277+
278+
match room.invite_user_by_id(&user_id).await {
279+
Ok(_) => {
280+
self.status_handle
281+
.set_message(format!("Successfully invited {user_id} to the room"));
282+
self.input.clear();
283+
}
284+
Err(e) => {
285+
self.status_handle
286+
.set_message(format!("Failed to invite {user_id} to the room: {e:?}"));
287+
}
288+
}
289+
}
290+
291+
async fn handle_command(&mut self, command: input::Command) {
292+
match command {
293+
input::Command::Invite { user_id } => self.invite_member(user_id).await,
294+
}
295+
}
296+
297+
async fn send_message(&mut self, message: String) {
298+
match self.send_message_impl(message).await {
299+
Ok(_) => {
300+
self.input.clear();
301+
}
302+
Err(err) => {
303+
self.status_handle.set_message(format!("error when sending event: {err}"));
304+
}
305+
}
306+
}
307+
308+
async fn send_message_impl(&self, message: String) -> Result<()> {
265309
if let Some(sdk_timeline) = self.selected_room.as_deref().and_then(|room_id| {
266310
self.timelines.lock().get(room_id).map(|timeline| timeline.timeline.clone())
267311
}) {

0 commit comments

Comments
 (0)