Support creating new rooms and spaces (#40)

This commit is contained in:
Ulyssa 2023-03-04 12:23:17 -08:00
parent 11625262f1
commit 93eff79f79
No known key found for this signature in database
GPG key ID: 1B3965A3D18B9B64
6 changed files with 122 additions and 10 deletions

4
Cargo.lock generated
View file

@ -1882,9 +1882,9 @@ dependencies = [
[[package]] [[package]]
name = "modalkit" name = "modalkit"
version = "0.0.12" version = "0.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a4e5226a5d33a7bdf5b4fc067baa211c94f21aa6667af5eec8b357a8af5e4ba" checksum = "038bb42efcd659fb123708bf8e4ea12ca9023f07d44514f9358b9334ea7ba80f"
dependencies = [ dependencies = [
"anymap2", "anymap2",
"arboard", "arboard",

View file

@ -39,7 +39,7 @@ unicode-width = "0.1.10"
url = {version = "^2.2.2", features = ["serde"]} url = {version = "^2.2.2", features = ["serde"]}
[dependencies.modalkit] [dependencies.modalkit]
version = "0.0.12" version = "0.0.13"
[dependencies.matrix-sdk] [dependencies.matrix-sdk]
version = "0.6" version = "0.6"

View file

@ -135,6 +135,12 @@ pub enum MessageAction {
pub enum CreateRoomType { pub enum CreateRoomType {
/// A direct message room. /// A direct message room.
Direct(OwnedUserId), Direct(OwnedUserId),
/// A standard chat room.
Room,
/// A Matrix space.
Space,
} }
bitflags::bitflags! { bitflags::bitflags! {
@ -184,8 +190,14 @@ pub enum SendAction {
Upload(String), Upload(String),
} }
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum HomeserverAction {
CreateRoom(Option<String>, CreateRoomType, CreateRoomFlags),
}
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum IambAction { pub enum IambAction {
Homeserver(HomeserverAction),
Message(MessageAction), Message(MessageAction),
Room(RoomAction), Room(RoomAction),
Send(SendAction), Send(SendAction),
@ -194,6 +206,12 @@ pub enum IambAction {
ToggleScrollbackFocus, ToggleScrollbackFocus,
} }
impl From<HomeserverAction> for IambAction {
fn from(act: HomeserverAction) -> Self {
IambAction::Homeserver(act)
}
}
impl From<MessageAction> for IambAction { impl From<MessageAction> for IambAction {
fn from(act: MessageAction) -> Self { fn from(act: MessageAction) -> Self {
IambAction::Message(act) IambAction::Message(act)
@ -215,6 +233,7 @@ impl From<SendAction> for IambAction {
impl ApplicationAction for IambAction { impl ApplicationAction for IambAction {
fn is_edit_sequence<C: EditContext>(&self, _: &C) -> SequenceStatus { fn is_edit_sequence<C: EditContext>(&self, _: &C) -> SequenceStatus {
match self { match self {
IambAction::Homeserver(..) => SequenceStatus::Break,
IambAction::Message(..) => SequenceStatus::Break, IambAction::Message(..) => SequenceStatus::Break,
IambAction::Room(..) => SequenceStatus::Break, IambAction::Room(..) => SequenceStatus::Break,
IambAction::Send(..) => SequenceStatus::Break, IambAction::Send(..) => SequenceStatus::Break,
@ -226,6 +245,7 @@ impl ApplicationAction for IambAction {
fn is_last_action<C: EditContext>(&self, _: &C) -> SequenceStatus { fn is_last_action<C: EditContext>(&self, _: &C) -> SequenceStatus {
match self { match self {
IambAction::Homeserver(..) => SequenceStatus::Atom,
IambAction::Message(..) => SequenceStatus::Atom, IambAction::Message(..) => SequenceStatus::Atom,
IambAction::Room(..) => SequenceStatus::Atom, IambAction::Room(..) => SequenceStatus::Atom,
IambAction::Send(..) => SequenceStatus::Atom, IambAction::Send(..) => SequenceStatus::Atom,
@ -237,6 +257,7 @@ impl ApplicationAction for IambAction {
fn is_last_selection<C: EditContext>(&self, _: &C) -> SequenceStatus { fn is_last_selection<C: EditContext>(&self, _: &C) -> SequenceStatus {
match self { match self {
IambAction::Homeserver(..) => SequenceStatus::Ignore,
IambAction::Message(..) => SequenceStatus::Ignore, IambAction::Message(..) => SequenceStatus::Ignore,
IambAction::Room(..) => SequenceStatus::Ignore, IambAction::Room(..) => SequenceStatus::Ignore,
IambAction::Send(..) => SequenceStatus::Ignore, IambAction::Send(..) => SequenceStatus::Ignore,
@ -248,6 +269,7 @@ impl ApplicationAction for IambAction {
fn is_switchable<C: EditContext>(&self, _: &C) -> bool { fn is_switchable<C: EditContext>(&self, _: &C) -> bool {
match self { match self {
IambAction::Homeserver(..) => false,
IambAction::Message(..) => false, IambAction::Message(..) => false,
IambAction::Room(..) => false, IambAction::Room(..) => false,
IambAction::Send(..) => false, IambAction::Send(..) => false,

View file

@ -4,13 +4,16 @@ use matrix_sdk::ruma::{events::tag::TagName, OwnedUserId};
use modalkit::{ use modalkit::{
editing::base::OpenTarget, editing::base::OpenTarget,
env::vim::command::{CommandContext, CommandDescription}, env::vim::command::{CommandContext, CommandDescription, OptionType},
input::commands::{CommandError, CommandResult, CommandStep}, input::commands::{CommandError, CommandResult, CommandStep},
input::InputContext, input::InputContext,
}; };
use crate::base::{ use crate::base::{
CreateRoomFlags,
CreateRoomType,
DownloadFlags, DownloadFlags,
HomeserverAction,
IambAction, IambAction,
IambId, IambId,
MessageAction, MessageAction,
@ -297,6 +300,53 @@ fn iamb_join(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
return Ok(step); 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 { fn iamb_room(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
let mut args = desc.arg.strings()?; let mut args = desc.arg.strings()?;
@ -400,6 +450,11 @@ fn add_iamb_commands(cmds: &mut ProgramCommands) {
aliases: vec![], aliases: vec![],
f: iamb_cancel, 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: "dms".into(), aliases: vec![], f: iamb_dms });
cmds.add_command(ProgramCommand { cmds.add_command(ProgramCommand {
name: "download".into(), name: "download".into(),

View file

@ -53,6 +53,7 @@ use crate::{
base::{ base::{
AsyncProgramStore, AsyncProgramStore,
ChatStore, ChatStore,
HomeserverAction,
IambAction, IambAction,
IambError, IambError,
IambId, IambId,
@ -64,7 +65,7 @@ use crate::{
}, },
config::{ApplicationSettings, Iamb}, config::{ApplicationSettings, Iamb},
windows::IambWindow, windows::IambWindow,
worker::{ClientWorker, LoginStyle, Requester}, worker::{create_room, ClientWorker, LoginStyle, Requester},
}; };
use modalkit::{ use modalkit::{
@ -355,6 +356,12 @@ impl Application {
None None
}, },
IambAction::Homeserver(act) => {
let acts = self.homeserver_command(act, ctx, store).await?;
self.action_prepend(acts);
None
},
IambAction::Message(act) => { IambAction::Message(act) => {
self.screen.current_window_mut()?.message_command(act, ctx, store).await? self.screen.current_window_mut()?.message_command(act, ctx, store).await?
}, },
@ -387,6 +394,25 @@ impl Application {
Ok(info) Ok(info)
} }
async fn homeserver_command(
&mut self,
action: HomeserverAction,
ctx: ProgramContext,
store: &mut ProgramStore,
) -> IambResult<Vec<(Action<IambInfo>, 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> { pub async fn run(&mut self) -> Result<(), std::io::Error> {
self.terminal.clear()?; self.terminal.clear()?;
@ -518,7 +544,7 @@ fn main() -> IambResult<()> {
let subscriber = FmtSubscriber::builder() let subscriber = FmtSubscriber::builder()
.with_writer(appender) .with_writer(appender)
.with_max_level(Level::TRACE) .with_max_level(Level::INFO)
.finish(); .finish();
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed"); tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");

View file

@ -20,7 +20,7 @@ use matrix_sdk::{
room::{Invited, Messages, MessagesOptions, Room as MatrixRoom, RoomMember}, room::{Invited, Messages, MessagesOptions, Room as MatrixRoom, RoomMember},
ruma::{ ruma::{
api::client::{ api::client::{
room::create_room::v3::{Request as CreateRoomRequest, RoomPreset}, room::create_room::v3::{CreationContent, Request as CreateRoomRequest, RoomPreset},
room::Visibility, room::Visibility,
space::get_hierarchy::v1::Request as SpaceHierarchyRequest, space::get_hierarchy::v1::Request as SpaceHierarchyRequest,
}, },
@ -50,6 +50,7 @@ use matrix_sdk::{
SyncMessageLikeEvent, SyncMessageLikeEvent,
SyncStateEvent, SyncStateEvent,
}, },
room::RoomType,
serde::Raw, serde::Raw,
EventEncryptionAlgorithm, EventEncryptionAlgorithm,
OwnedRoomId, OwnedRoomId,
@ -93,10 +94,10 @@ pub async fn create_room(
rt: CreateRoomType, rt: CreateRoomType,
flags: CreateRoomFlags, flags: CreateRoomFlags,
) -> IambResult<OwnedRoomId> { ) -> IambResult<OwnedRoomId> {
let creation_content = None; let mut creation_content = None;
let mut initial_state = vec![]; let mut initial_state = vec![];
let is_direct; let mut is_direct = false;
let preset; let mut preset = None;
let mut invite = vec![]; let mut invite = vec![];
let visibility = if flags.contains(CreateRoomFlags::PUBLIC) { let visibility = if flags.contains(CreateRoomFlags::PUBLIC) {
@ -111,6 +112,14 @@ pub async fn create_room(
is_direct = true; is_direct = true;
preset = Some(RoomPreset::TrustedPrivateChat); 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. // Set up encryption.