diff --git a/Cargo.lock b/Cargo.lock index 1b08ce2..f60d11b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1882,9 +1882,9 @@ dependencies = [ [[package]] name = "modalkit" -version = "0.0.12" +version = "0.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a4e5226a5d33a7bdf5b4fc067baa211c94f21aa6667af5eec8b357a8af5e4ba" +checksum = "038bb42efcd659fb123708bf8e4ea12ca9023f07d44514f9358b9334ea7ba80f" dependencies = [ "anymap2", "arboard", diff --git a/Cargo.toml b/Cargo.toml index 567f9e7..e3521cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ unicode-width = "0.1.10" url = {version = "^2.2.2", features = ["serde"]} [dependencies.modalkit] -version = "0.0.12" +version = "0.0.13" [dependencies.matrix-sdk] version = "0.6" diff --git a/src/base.rs b/src/base.rs index 6cc4283..bdf11ca 100644 --- a/src/base.rs +++ b/src/base.rs @@ -135,6 +135,12 @@ pub enum MessageAction { pub enum CreateRoomType { /// A direct message room. Direct(OwnedUserId), + + /// A standard chat room. + Room, + + /// A Matrix space. + Space, } bitflags::bitflags! { @@ -184,8 +190,14 @@ pub enum SendAction { Upload(String), } +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum HomeserverAction { + CreateRoom(Option, CreateRoomType, CreateRoomFlags), +} + #[derive(Clone, Debug, Eq, PartialEq)] pub enum IambAction { + Homeserver(HomeserverAction), Message(MessageAction), Room(RoomAction), Send(SendAction), @@ -194,6 +206,12 @@ pub enum IambAction { ToggleScrollbackFocus, } +impl From for IambAction { + fn from(act: HomeserverAction) -> Self { + IambAction::Homeserver(act) + } +} + impl From for IambAction { fn from(act: MessageAction) -> Self { IambAction::Message(act) @@ -215,6 +233,7 @@ impl From for IambAction { impl ApplicationAction for IambAction { fn is_edit_sequence(&self, _: &C) -> SequenceStatus { match self { + IambAction::Homeserver(..) => SequenceStatus::Break, IambAction::Message(..) => SequenceStatus::Break, IambAction::Room(..) => SequenceStatus::Break, IambAction::Send(..) => SequenceStatus::Break, @@ -226,6 +245,7 @@ impl ApplicationAction for IambAction { fn is_last_action(&self, _: &C) -> SequenceStatus { match self { + IambAction::Homeserver(..) => SequenceStatus::Atom, IambAction::Message(..) => SequenceStatus::Atom, IambAction::Room(..) => SequenceStatus::Atom, IambAction::Send(..) => SequenceStatus::Atom, @@ -237,6 +257,7 @@ impl ApplicationAction for IambAction { fn is_last_selection(&self, _: &C) -> SequenceStatus { match self { + IambAction::Homeserver(..) => SequenceStatus::Ignore, IambAction::Message(..) => SequenceStatus::Ignore, IambAction::Room(..) => SequenceStatus::Ignore, IambAction::Send(..) => SequenceStatus::Ignore, @@ -248,6 +269,7 @@ impl ApplicationAction for IambAction { fn is_switchable(&self, _: &C) -> bool { match self { + IambAction::Homeserver(..) => false, IambAction::Message(..) => false, IambAction::Room(..) => false, IambAction::Send(..) => false, diff --git a/src/commands.rs b/src/commands.rs index 8f6dfa8..ce06e5a 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -4,13 +4,16 @@ use matrix_sdk::ruma::{events::tag::TagName, OwnedUserId}; use modalkit::{ editing::base::OpenTarget, - env::vim::command::{CommandContext, CommandDescription}, + env::vim::command::{CommandContext, CommandDescription, OptionType}, input::commands::{CommandError, CommandResult, CommandStep}, input::InputContext, }; use crate::base::{ + CreateRoomFlags, + CreateRoomType, DownloadFlags, + HomeserverAction, IambAction, IambId, MessageAction, @@ -297,6 +300,53 @@ fn iamb_join(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult { return Ok(step); } +fn iamb_create(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult { + let args = desc.arg.options()?; + let mut flags = CreateRoomFlags::NONE; + let mut alias = None; + let mut ct = CreateRoomType::Room; + + for arg in args { + match arg { + OptionType::Flag(name, Some(arg)) => { + match name.as_str() { + "alias" => { + if alias.is_some() { + let msg = "Multiple ++alias arguments are not allowed"; + let err = CommandError::Error(msg.into()); + + return Err(err); + } else { + alias = Some(arg); + } + }, + _ => return Err(CommandError::InvalidArgument), + } + }, + OptionType::Flag(name, None) => { + match name.as_str() { + "public" => flags |= CreateRoomFlags::PUBLIC, + "space" => ct = CreateRoomType::Space, + "enc" | "encrypted" => flags |= CreateRoomFlags::ENCRYPTED, + _ => return Err(CommandError::InvalidArgument), + } + }, + OptionType::Positional(_) => { + let msg = ":create doesn't take any positional arguments"; + let err = CommandError::Error(msg.into()); + + return Err(err); + }, + } + } + + let hact = HomeserverAction::CreateRoom(alias, ct, flags); + let iact = IambAction::from(hact); + let step = CommandStep::Continue(iact.into(), ctx.context.take()); + + return Ok(step); +} + fn iamb_room(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult { let mut args = desc.arg.strings()?; @@ -400,6 +450,11 @@ fn add_iamb_commands(cmds: &mut ProgramCommands) { aliases: vec![], f: iamb_cancel, }); + cmds.add_command(ProgramCommand { + name: "create".into(), + aliases: vec![], + f: iamb_create, + }); cmds.add_command(ProgramCommand { name: "dms".into(), aliases: vec![], f: iamb_dms }); cmds.add_command(ProgramCommand { name: "download".into(), diff --git a/src/main.rs b/src/main.rs index 68626f2..3137ce1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,6 +53,7 @@ use crate::{ base::{ AsyncProgramStore, ChatStore, + HomeserverAction, IambAction, IambError, IambId, @@ -64,7 +65,7 @@ use crate::{ }, config::{ApplicationSettings, Iamb}, windows::IambWindow, - worker::{ClientWorker, LoginStyle, Requester}, + worker::{create_room, ClientWorker, LoginStyle, Requester}, }; use modalkit::{ @@ -355,6 +356,12 @@ impl Application { None }, + IambAction::Homeserver(act) => { + let acts = self.homeserver_command(act, ctx, store).await?; + self.action_prepend(acts); + + None + }, IambAction::Message(act) => { self.screen.current_window_mut()?.message_command(act, ctx, store).await? }, @@ -387,6 +394,25 @@ impl Application { Ok(info) } + async fn homeserver_command( + &mut self, + action: HomeserverAction, + ctx: ProgramContext, + store: &mut ProgramStore, + ) -> IambResult, ProgramContext)>> { + match action { + HomeserverAction::CreateRoom(alias, vis, flags) => { + let client = &store.application.worker.client; + let room_id = create_room(client, alias.as_deref(), vis, flags).await?; + let room = IambId::Room(room_id); + let target = OpenTarget::Application(room); + let action = WindowAction::Switch(target); + + Ok(vec![(action.into(), ctx)]) + }, + } + } + pub async fn run(&mut self) -> Result<(), std::io::Error> { self.terminal.clear()?; @@ -518,7 +544,7 @@ fn main() -> IambResult<()> { let subscriber = FmtSubscriber::builder() .with_writer(appender) - .with_max_level(Level::TRACE) + .with_max_level(Level::INFO) .finish(); tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed"); diff --git a/src/worker.rs b/src/worker.rs index 5707df8..21667f5 100644 --- a/src/worker.rs +++ b/src/worker.rs @@ -20,7 +20,7 @@ use matrix_sdk::{ room::{Invited, Messages, MessagesOptions, Room as MatrixRoom, RoomMember}, ruma::{ api::client::{ - room::create_room::v3::{Request as CreateRoomRequest, RoomPreset}, + room::create_room::v3::{CreationContent, Request as CreateRoomRequest, RoomPreset}, room::Visibility, space::get_hierarchy::v1::Request as SpaceHierarchyRequest, }, @@ -50,6 +50,7 @@ use matrix_sdk::{ SyncMessageLikeEvent, SyncStateEvent, }, + room::RoomType, serde::Raw, EventEncryptionAlgorithm, OwnedRoomId, @@ -93,10 +94,10 @@ pub async fn create_room( rt: CreateRoomType, flags: CreateRoomFlags, ) -> IambResult { - let creation_content = None; + let mut creation_content = None; let mut initial_state = vec![]; - let is_direct; - let preset; + let mut is_direct = false; + let mut preset = None; let mut invite = vec![]; let visibility = if flags.contains(CreateRoomFlags::PUBLIC) { @@ -111,6 +112,14 @@ pub async fn create_room( is_direct = true; preset = Some(RoomPreset::TrustedPrivateChat); }, + CreateRoomType::Space => { + let mut cc = CreationContent::new(); + cc.room_type = Some(RoomType::Space); + + let raw_cc = Raw::new(&cc).map_err(IambError::from)?; + creation_content = Some(raw_cc); + }, + CreateRoomType::Room => {}, } // Set up encryption.