diff --git a/src/windows/room/chat.rs b/src/windows/room/chat.rs index cb584f46..aadb0227 100644 --- a/src/windows/room/chat.rs +++ b/src/windows/room/chat.rs @@ -653,8 +653,17 @@ impl ChatState { &mut self, act: &EditorAction, ctx: &ProgramContext, + info: &RoomInfo, ) -> Option { - auto_toggle_focus(&mut self.focus, act, ctx, &self.scrollback, &mut self.tbox) + auto_toggle_focus( + &mut self.focus, + act, + ctx, + &self.scrollback, + &mut self.tbox, + &mut self.reply_to, + info, + ) } pub fn typing_notice( @@ -761,7 +770,8 @@ impl Editable for ChatState { ) -> EditResult { // Check whether we should automatically switch between the message bar // or message scrollback, and use an adjusted action if we do so. - let adjusted = self.auto_toggle_focus(act, ctx); + let info = store.application.rooms.get_or_default(self.room_id.clone()); + let adjusted = self.auto_toggle_focus(act, ctx, info); let act = adjusted.as_ref().unwrap_or(act); // Send typing notice if needed. @@ -1012,17 +1022,25 @@ pub fn auto_toggle_focus( ctx: &ProgramContext, scrollback: &ScrollbackState, tbox: &mut TextBoxState, + reply_to: &mut Option, + info: &RoomInfo, ) -> Option { let is_insert = ctx.get_insert_style().is_some(); match (focus, act) { (f @ RoomFocus::Scrollback, _) if is_insert => { // Insert mode commands should switch focus. + if reply_to.is_none() && !tbox.get_text().is_empty() { + *reply_to = scrollback.get_key(info); + } f.toggle(); None }, (f @ RoomFocus::Scrollback, EditorAction::InsertText(_)) => { // Pasting or otherwise inserting text should switch. + if reply_to.is_none() && !tbox.get_text().is_empty() { + *reply_to = scrollback.get_key(info); + } f.toggle(); None }, @@ -1050,6 +1068,30 @@ pub fn auto_toggle_focus( None } }, + ( + f @ RoomFocus::MessageBar, + EditorAction::Edit( + op, + EditTarget::Motion(mov @ MoveType::Line(MoveDir1D::Next), count), + ), + ) if !is_insert && ctx.resolve(op).is_motion() => { + let count = ctx.resolve(count); + + if count > 0 && tbox.get_cursor().y == tbox.get_lines() - 1 && !scrollback.is_latest() { + // Trying to move down a line in msgbar when scrollback is not at the bottom should + // switch as long as we're not in Insert mode. + f.toggle(); + + // And decrement the count for the action. + let count = count.saturating_sub(1).into(); + let target = EditTarget::Motion(mov.clone(), count); + let dec = EditorAction::Edit(op.clone(), target); + + Some(dec) + } else { + None + } + }, ( f @ RoomFocus::MessageBar, EditorAction::Edit( @@ -1109,6 +1151,8 @@ mod tests { let id = IambBufferId::Room(room_id, None, RoomFocus::MessageBar); let ebuf = store.load_buffer(id); let mut tbox = TextBoxState::new(ebuf); + let mut reply_to = None; + let info = RoomInfo::default(); // Start out focused on the scrollback. let mut focused = RoomFocus::Scrollback; @@ -1119,43 +1163,99 @@ mod tests { MoveDir1D::Next, 1.into(), )); - let res = auto_toggle_focus(&mut focused, &act, &ctx, &scrollback, &mut tbox); + let res = auto_toggle_focus( + &mut focused, + &act, + &ctx, + &scrollback, + &mut tbox, + &mut reply_to, + &info, + ); assert_eq!(focused, RoomFocus::MessageBar); assert!(res.is_none()); // Going down in message bar doesn't toggle: let act = move_line!(MoveDir1D::Next, 1); - let res = auto_toggle_focus(&mut focused, &act, &ctx, &scrollback, &mut tbox); + let res = auto_toggle_focus( + &mut focused, + &act, + &ctx, + &scrollback, + &mut tbox, + &mut reply_to, + &info, + ); assert_eq!(focused, RoomFocus::MessageBar); assert!(res.is_none()); // But going up will: let act = move_line!(MoveDir1D::Previous, 1); - let res = auto_toggle_focus(&mut focused, &act, &ctx, &scrollback, &mut tbox); + let res = auto_toggle_focus( + &mut focused, + &act, + &ctx, + &scrollback, + &mut tbox, + &mut reply_to, + &info, + ); assert_eq!(focused, RoomFocus::Scrollback); assert_eq!(res, Some(move_line!(MoveDir1D::Previous, 0))); // Going up in scrollback doesn't toggle: let act = move_line!(MoveDir1D::Previous, 1); - let res = auto_toggle_focus(&mut focused, &act, &ctx, &scrollback, &mut tbox); + let res = auto_toggle_focus( + &mut focused, + &act, + &ctx, + &scrollback, + &mut tbox, + &mut reply_to, + &info, + ); assert_eq!(focused, RoomFocus::Scrollback); assert_eq!(res, None); // And then go back down: let act = move_line!(MoveDir1D::Next, 1); - let res = auto_toggle_focus(&mut focused, &act, &ctx, &scrollback, &mut tbox); + let res = auto_toggle_focus( + &mut focused, + &act, + &ctx, + &scrollback, + &mut tbox, + &mut reply_to, + &info, + ); assert_eq!(focused, RoomFocus::MessageBar); assert_eq!(res, Some(move_line!(MoveDir1D::Next, 0))); // Go up 2 will go up 1 in scrollback: let act = move_line!(MoveDir1D::Previous, 2); - let res = auto_toggle_focus(&mut focused, &act, &ctx, &scrollback, &mut tbox); + let res = auto_toggle_focus( + &mut focused, + &act, + &ctx, + &scrollback, + &mut tbox, + &mut reply_to, + &info, + ); assert_eq!(focused, RoomFocus::Scrollback); assert_eq!(res, Some(move_line!(MoveDir1D::Previous, 1))); // Go down 3 will go down 2 in messagebar: let act = move_line!(MoveDir1D::Next, 3); - let res = auto_toggle_focus(&mut focused, &act, &ctx, &scrollback, &mut tbox); + let res = auto_toggle_focus( + &mut focused, + &act, + &ctx, + &scrollback, + &mut tbox, + &mut reply_to, + &info, + ); assert_eq!(focused, RoomFocus::MessageBar); assert_eq!(res, Some(move_line!(MoveDir1D::Next, 2))); } diff --git a/src/windows/room/scrollback.rs b/src/windows/room/scrollback.rs index 1566931e..d2b263dc 100644 --- a/src/windows/room/scrollback.rs +++ b/src/windows/room/scrollback.rs @@ -170,7 +170,7 @@ impl ScrollbackState { self.viewctx.dimensions = (area.width as usize, area.height as usize); } - pub fn get_key(&self, info: &mut RoomInfo) -> Option { + pub fn get_key(&self, info: &RoomInfo) -> Option { self.cursor .timestamp .clone()