diff --git a/src/base.rs b/src/base.rs index b2299773..01731df6 100644 --- a/src/base.rs +++ b/src/base.rs @@ -194,8 +194,8 @@ pub enum MessageAction { pub enum SpaceAction { /// Add a room or update metadata. SetChild { - /// The room ID, alias, or a user whose DM room should be added to the space. - child: String, + /// The room that should be added to the space. + child: OwnedRoomOrAliasId, /// The order parameter to use when sorting children in the space. order: Option, /// Whether the room is suggested. diff --git a/src/commands.rs b/src/commands.rs index 0047c481..5c7bf381 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -930,10 +930,13 @@ fn iamb_space(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult { } } - let Some(child) = raw_child else { + let child = raw_child.ok_or_else(|| { let msg = "Must specify a room to add"; - return Err(CommandError::Error(msg.into())); - }; + CommandError::Error(msg.into()) + })?; + let child = OwnedRoomOrAliasId::from_str(&child).map_err(|e| { + CommandError::Error(format!("{child:?} is not a valid room identifier: {e}")) + })?; SpaceAction::SetChild { child, order, suggested }.into() }, @@ -1539,7 +1542,7 @@ mod tests { let cmd = "space child set !roomid:example.org"; let res = cmds.input_cmd(cmd, ctx.clone()).unwrap(); let act = SpaceAction::SetChild { - child: "!roomid:example.org".to_owned(), + child: owned_room_id!("!roomid:example.org").into(), order: None, suggested: false, }; @@ -1548,7 +1551,7 @@ mod tests { let cmd = "space child set ++order=abcd ++suggested !roomid:example.org"; let res = cmds.input_cmd(cmd, ctx.clone()).unwrap(); let act = SpaceAction::SetChild { - child: "!roomid:example.org".to_owned(), + child: owned_room_id!("!roomid:example.org").into(), order: Some("abcd".into()), suggested: true, }; diff --git a/src/completions.rs b/src/completions.rs index 3547c82d..2bd910e6 100644 --- a/src/completions.rs +++ b/src/completions.rs @@ -295,6 +295,16 @@ fn complete_matrix_names(input: &str, store: &ChatStore) -> Vec { store.rooms.complete(input).into_iter().map(|i| i.to_string()).collect() } +/// Tab completion for known room aliases and ids. +fn complete_room_alias_or_id(input: &str, store: &ChatStore) -> Vec { + let list = store.names.complete(input); + if !list.is_empty() { + return list; + } + + store.rooms.complete(input).into_iter().map(|i| i.to_string()).collect() +} + /// Tab completion for open verification requests fn complete_verification(input: &str, store: &ChatStore) -> Vec { store.verifications.complete(input) @@ -500,13 +510,13 @@ fn complete_iamb_space(args: Vec, store: &ChatStore) -> Vec { if arg.is_empty() { let mut opts = complete_options(args.as_slice(), &options); if !has_room { - opts.extend(complete_matrix_names(arg, store)); + opts.extend(complete_room_alias_or_id(arg, store)); } opts } else if arg.starts_with('+') { complete_options(args.as_slice(), &options) } else if !has_room { - complete_matrix_names(arg, store) + complete_room_alias_or_id(arg, store) } else { vec![] } diff --git a/src/windows/room/space.rs b/src/windows/room/space.rs index 6a652fc8..e3d8476d 100644 --- a/src/windows/room/space.rs +++ b/src/windows/room/space.rs @@ -105,9 +105,26 @@ impl SpaceState { return Err(IambError::InsufficientPermission.into()); } - let child_id = store.application.worker.join_room(child)?; + let (child_id, via) = match OwnedRoomId::try_from(child) { + Ok(room_id) => { + // assume the new child is reachable the same way as the parent + let via = self.room.route().await.map_err(IambError::from)?; + + (room_id, via) + }, + Err(alias) => { + let resp = store + .application + .worker + .client + .resolve_room_alias(&alias) + .await + .map_err(IambError::from)?; + + (resp.room_id, resp.servers) + }, + }; - let via = self.room.route().await.map_err(IambError::from)?; let mut ev = SpaceChildEventContent::new(via); ev.order = order .as_deref()