mirror of
https://github.com/youwen5/iamb.git
synced 2025-06-19 21:29:52 -07:00
Support leaving rooms (#45)
This commit is contained in:
parent
50023bad40
commit
a5c25f2487
9 changed files with 177 additions and 37 deletions
79
Cargo.lock
generated
79
Cargo.lock
generated
|
@ -625,6 +625,22 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossterm"
|
||||||
|
version = "0.26.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"crossterm_winapi",
|
||||||
|
"libc",
|
||||||
|
"mio",
|
||||||
|
"parking_lot 0.12.1",
|
||||||
|
"signal-hook",
|
||||||
|
"signal-hook-mio",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossterm_winapi"
|
name = "crossterm_winapi"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
@ -2006,24 +2022,26 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "modalkit"
|
name = "modalkit"
|
||||||
version = "0.0.14"
|
version = "0.0.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c48c7d7e6d764a09435b43a7e4d342ba2d2e026626ca773b16a5ba34b90b933"
|
checksum = "b44af1b5a7737da948719b907c870b4c852f1d98300d873bd12568f4028d908a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anymap2",
|
"anymap2",
|
||||||
"arboard",
|
"arboard",
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"crossterm",
|
"crossterm 0.25.0",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"intervaltree",
|
"intervaltree",
|
||||||
"libc",
|
"libc",
|
||||||
"nom",
|
"nom",
|
||||||
"radix_trie",
|
"radix_trie",
|
||||||
|
"ratatui",
|
||||||
"regex",
|
"regex",
|
||||||
"ropey",
|
"ropey",
|
||||||
|
"textwrap",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tui",
|
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2699,6 +2717,19 @@ dependencies = [
|
||||||
"rand_core 0.3.1",
|
"rand_core 0.3.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ratatui"
|
||||||
|
version = "0.20.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcc0d032bccba900ee32151ec0265667535c230169f5a011154cdcd984e16829"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"cassowary",
|
||||||
|
"crossterm 0.26.1",
|
||||||
|
"unicode-segmentation",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rdrand"
|
name = "rdrand"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
@ -3209,6 +3240,12 @@ version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smawk"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
|
@ -3383,6 +3420,17 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textwrap"
|
||||||
|
version = "0.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
|
||||||
|
dependencies = [
|
||||||
|
"smawk",
|
||||||
|
"unicode-linebreak",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.40"
|
version = "1.0.40"
|
||||||
|
@ -3638,19 +3686,6 @@ version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tui"
|
|
||||||
version = "0.19.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"cassowary",
|
|
||||||
"crossterm",
|
|
||||||
"unicode-segmentation",
|
|
||||||
"unicode-width",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typed-arena"
|
name = "typed-arena"
|
||||||
version = "2.0.2"
|
version = "2.0.2"
|
||||||
|
@ -3684,6 +3719,16 @@ version = "1.0.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-linebreak"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c5faade31a542b8b35855fff6e8def199853b2da8da256da52f52f1316ee3137"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-normalization"
|
name = "unicode-normalization"
|
||||||
version = "0.1.22"
|
version = "0.1.22"
|
||||||
|
|
|
@ -40,7 +40,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.14"
|
version = "0.0.15"
|
||||||
|
|
||||||
[dependencies.matrix-sdk]
|
[dependencies.matrix-sdk]
|
||||||
version = "0.6"
|
version = "0.6"
|
||||||
|
|
|
@ -118,7 +118,9 @@ pub enum MessageAction {
|
||||||
React(String),
|
React(String),
|
||||||
|
|
||||||
/// Redact a message, with an optional reason.
|
/// Redact a message, with an optional reason.
|
||||||
Redact(Option<String>),
|
///
|
||||||
|
/// The [bool] argument indicates whether to skip confirmation.
|
||||||
|
Redact(Option<String>, bool),
|
||||||
|
|
||||||
/// Reply to a message.
|
/// Reply to a message.
|
||||||
Reply,
|
Reply,
|
||||||
|
@ -178,6 +180,7 @@ pub enum RoomAction {
|
||||||
InviteAccept,
|
InviteAccept,
|
||||||
InviteReject,
|
InviteReject,
|
||||||
InviteSend(OwnedUserId),
|
InviteSend(OwnedUserId),
|
||||||
|
Leave(bool),
|
||||||
Members(Box<CommandContext<ProgramContext>>),
|
Members(Box<CommandContext<ProgramContext>>),
|
||||||
Set(RoomField, String),
|
Set(RoomField, String),
|
||||||
Unset(RoomField),
|
Unset(RoomField),
|
||||||
|
|
|
@ -161,6 +161,17 @@ fn iamb_members(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
||||||
return Ok(step);
|
return Ok(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn iamb_leave(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
||||||
|
if !desc.arg.text.is_empty() {
|
||||||
|
return Result::Err(CommandError::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
let leave = IambAction::Room(RoomAction::Leave(desc.bang));
|
||||||
|
let step = CommandStep::Continue(leave.into(), ctx.context.take());
|
||||||
|
|
||||||
|
return Ok(step);
|
||||||
|
}
|
||||||
|
|
||||||
fn iamb_cancel(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
fn iamb_cancel(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
||||||
if !desc.arg.text.is_empty() {
|
if !desc.arg.text.is_empty() {
|
||||||
return Result::Err(CommandError::InvalidArgument);
|
return Result::Err(CommandError::InvalidArgument);
|
||||||
|
@ -237,7 +248,8 @@ fn iamb_redact(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
||||||
return Result::Err(CommandError::InvalidArgument);
|
return Result::Err(CommandError::InvalidArgument);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ract = IambAction::from(MessageAction::Redact(args.into_iter().next()));
|
let reason = args.into_iter().next();
|
||||||
|
let ract = IambAction::from(MessageAction::Redact(reason, desc.bang));
|
||||||
let step = CommandStep::Continue(ract.into(), ctx.context.take());
|
let step = CommandStep::Continue(ract.into(), ctx.context.take());
|
||||||
|
|
||||||
return Ok(step);
|
return Ok(step);
|
||||||
|
@ -469,6 +481,11 @@ fn add_iamb_commands(cmds: &mut ProgramCommands) {
|
||||||
f: iamb_invite,
|
f: iamb_invite,
|
||||||
});
|
});
|
||||||
cmds.add_command(ProgramCommand { name: "join".into(), aliases: vec![], f: iamb_join });
|
cmds.add_command(ProgramCommand { name: "join".into(), aliases: vec![], f: iamb_join });
|
||||||
|
cmds.add_command(ProgramCommand {
|
||||||
|
name: "leave".into(),
|
||||||
|
aliases: vec![],
|
||||||
|
f: iamb_leave,
|
||||||
|
});
|
||||||
cmds.add_command(ProgramCommand {
|
cmds.add_command(ProgramCommand {
|
||||||
name: "members".into(),
|
name: "members".into(),
|
||||||
aliases: vec![],
|
aliases: vec![],
|
||||||
|
@ -870,15 +887,19 @@ mod tests {
|
||||||
let ctx = ProgramContext::default();
|
let ctx = ProgramContext::default();
|
||||||
|
|
||||||
let res = cmds.input_cmd("redact", ctx.clone()).unwrap();
|
let res = cmds.input_cmd("redact", ctx.clone()).unwrap();
|
||||||
let act = IambAction::Message(MessageAction::Redact(None));
|
let act = IambAction::Message(MessageAction::Redact(None, false));
|
||||||
|
assert_eq!(res, vec![(act.into(), ctx.clone())]);
|
||||||
|
|
||||||
|
let res = cmds.input_cmd("redact!", ctx.clone()).unwrap();
|
||||||
|
let act = IambAction::Message(MessageAction::Redact(None, true));
|
||||||
assert_eq!(res, vec![(act.into(), ctx.clone())]);
|
assert_eq!(res, vec![(act.into(), ctx.clone())]);
|
||||||
|
|
||||||
let res = cmds.input_cmd("redact Removed", ctx.clone()).unwrap();
|
let res = cmds.input_cmd("redact Removed", ctx.clone()).unwrap();
|
||||||
let act = IambAction::Message(MessageAction::Redact(Some("Removed".into())));
|
let act = IambAction::Message(MessageAction::Redact(Some("Removed".into()), false));
|
||||||
assert_eq!(res, vec![(act.into(), ctx.clone())]);
|
assert_eq!(res, vec![(act.into(), ctx.clone())]);
|
||||||
|
|
||||||
let res = cmds.input_cmd("redact \"Removed\"", ctx.clone()).unwrap();
|
let res = cmds.input_cmd("redact \"Removed\"", ctx.clone()).unwrap();
|
||||||
let act = IambAction::Message(MessageAction::Redact(Some("Removed".into())));
|
let act = IambAction::Message(MessageAction::Redact(Some("Removed".into()), false));
|
||||||
assert_eq!(res, vec![(act.into(), ctx.clone())]);
|
assert_eq!(res, vec![(act.into(), ctx.clone())]);
|
||||||
|
|
||||||
let res = cmds.input_cmd("redact Removed Removed", ctx.clone());
|
let res = cmds.input_cmd("redact Removed Removed", ctx.clone());
|
||||||
|
|
51
src/main.rs
51
src/main.rs
|
@ -76,12 +76,14 @@ use modalkit::{
|
||||||
EditInfo,
|
EditInfo,
|
||||||
Editable,
|
Editable,
|
||||||
EditorAction,
|
EditorAction,
|
||||||
|
InfoMessage,
|
||||||
InsertTextAction,
|
InsertTextAction,
|
||||||
Jumpable,
|
Jumpable,
|
||||||
Promptable,
|
Promptable,
|
||||||
Scrollable,
|
Scrollable,
|
||||||
TabContainer,
|
TabContainer,
|
||||||
TabCount,
|
TabCount,
|
||||||
|
UIError,
|
||||||
WindowAction,
|
WindowAction,
|
||||||
WindowContainer,
|
WindowContainer,
|
||||||
},
|
},
|
||||||
|
@ -90,7 +92,7 @@ use modalkit::{
|
||||||
key::KeyManager,
|
key::KeyManager,
|
||||||
store::Store,
|
store::Store,
|
||||||
},
|
},
|
||||||
input::{bindings::BindingMachine, key::TerminalKey},
|
input::{bindings::BindingMachine, dialog::Pager, key::TerminalKey},
|
||||||
widgets::{
|
widgets::{
|
||||||
cmdbar::CommandBarState,
|
cmdbar::CommandBarState,
|
||||||
screen::{Screen, ScreenState},
|
screen::{Screen, ScreenState},
|
||||||
|
@ -156,8 +158,7 @@ impl Application {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn redraw(&mut self, full: bool, store: &mut ProgramStore) -> Result<(), std::io::Error> {
|
fn redraw(&mut self, full: bool, store: &mut ProgramStore) -> Result<(), std::io::Error> {
|
||||||
let modestr = self.bindings.showmode();
|
let bindings = &mut self.bindings;
|
||||||
let cursor = self.bindings.get_cursor_indicator();
|
|
||||||
let sstate = &mut self.screen;
|
let sstate = &mut self.screen;
|
||||||
let term = &mut self.terminal;
|
let term = &mut self.terminal;
|
||||||
|
|
||||||
|
@ -168,9 +169,20 @@ impl Application {
|
||||||
term.draw(|f| {
|
term.draw(|f| {
|
||||||
let area = f.size();
|
let area = f.size();
|
||||||
|
|
||||||
let screen = Screen::new(store).showmode(modestr).borders(true);
|
let modestr = bindings.show_mode();
|
||||||
|
let cursor = bindings.get_cursor_indicator();
|
||||||
|
let dialogstr = bindings.show_dialog(area.height as usize, area.width as usize);
|
||||||
|
|
||||||
|
// Don't show terminal cursor when we show a dialog.
|
||||||
|
let hide_cursor = !dialogstr.is_empty();
|
||||||
|
|
||||||
|
let screen = Screen::new(store).show_dialog(dialogstr).show_mode(modestr).borders(true);
|
||||||
f.render_stateful_widget(screen, area, sstate);
|
f.render_stateful_widget(screen, area, sstate);
|
||||||
|
|
||||||
|
if hide_cursor {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some((cx, cy)) = sstate.get_term_cursor() {
|
if let Some((cx, cy)) = sstate.get_term_cursor() {
|
||||||
if let Some(c) = cursor {
|
if let Some(c) = cursor {
|
||||||
let style = Style::default().fg(Color::Green);
|
let style = Style::default().fg(Color::Green);
|
||||||
|
@ -215,7 +227,8 @@ impl Application {
|
||||||
match self.screen.editor_command(&act, &ctx, store.deref_mut()) {
|
match self.screen.editor_command(&act, &ctx, store.deref_mut()) {
|
||||||
Ok(None) => {},
|
Ok(None) => {},
|
||||||
Ok(Some(info)) => {
|
Ok(Some(info)) => {
|
||||||
self.screen.push_info(info);
|
drop(store);
|
||||||
|
self.handle_info(info);
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.screen.push_error(e);
|
self.screen.push_error(e);
|
||||||
|
@ -279,7 +292,7 @@ impl Application {
|
||||||
Action::CommandBar(act) => self.screen.command_bar(&act, &ctx)?,
|
Action::CommandBar(act) => self.screen.command_bar(&act, &ctx)?,
|
||||||
Action::Macro(act) => self.bindings.macro_command(&act, &ctx, store)?,
|
Action::Macro(act) => self.bindings.macro_command(&act, &ctx, store)?,
|
||||||
Action::Scroll(style) => self.screen.scroll(&style, &ctx, store)?,
|
Action::Scroll(style) => self.screen.scroll(&style, &ctx, store)?,
|
||||||
Action::Suspend => self.terminal.program_suspend()?,
|
Action::ShowInfoMessage(info) => Some(info),
|
||||||
Action::Tab(cmd) => self.screen.tab_command(&cmd, &ctx, store)?,
|
Action::Tab(cmd) => self.screen.tab_command(&cmd, &ctx, store)?,
|
||||||
Action::Window(cmd) => self.screen.window_command(&cmd, &ctx, store)?,
|
Action::Window(cmd) => self.screen.window_command(&cmd, &ctx, store)?,
|
||||||
|
|
||||||
|
@ -289,6 +302,11 @@ impl Application {
|
||||||
|
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
Action::Suspend => {
|
||||||
|
self.terminal.program_suspend()?;
|
||||||
|
|
||||||
|
None
|
||||||
|
},
|
||||||
|
|
||||||
// UI actions.
|
// UI actions.
|
||||||
Action::RedrawScreen => {
|
Action::RedrawScreen => {
|
||||||
|
@ -402,6 +420,18 @@ impl Application {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_info(&mut self, info: InfoMessage) {
|
||||||
|
match info {
|
||||||
|
InfoMessage::Message(info) => {
|
||||||
|
self.screen.push_info(info);
|
||||||
|
},
|
||||||
|
InfoMessage::Pager(text) => {
|
||||||
|
let pager = Box::new(Pager::new(text, vec![]));
|
||||||
|
self.bindings.run_dialog(pager);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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()?;
|
||||||
|
|
||||||
|
@ -422,11 +452,18 @@ impl Application {
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
Ok(Some(info)) => {
|
Ok(Some(info)) => {
|
||||||
self.screen.push_info(info);
|
self.handle_info(info);
|
||||||
|
|
||||||
// Continue processing; we'll redraw later.
|
// Continue processing; we'll redraw later.
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
|
Err(
|
||||||
|
UIError::NeedConfirm(dialog) |
|
||||||
|
UIError::EditingFailure(EditError::NeedConfirm(dialog)),
|
||||||
|
) => {
|
||||||
|
self.bindings.run_dialog(dialog);
|
||||||
|
continue;
|
||||||
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.screen.push_error(e);
|
self.screen.push_error(e);
|
||||||
|
|
||||||
|
|
|
@ -199,7 +199,7 @@ fn room_prompt(
|
||||||
|
|
||||||
Err(err)
|
Err(err)
|
||||||
},
|
},
|
||||||
PromptAction::Recall(_, _) => {
|
PromptAction::Recall(..) => {
|
||||||
let msg = "Cannot recall history inside a list";
|
let msg = "Cannot recall history inside a list";
|
||||||
let err = EditError::Failure(msg.into());
|
let err = EditError::Failure(msg.into());
|
||||||
|
|
||||||
|
@ -1043,7 +1043,7 @@ impl Promptable<ProgramContext, ProgramStore, IambInfo> for VerifyItem {
|
||||||
|
|
||||||
Err(err)
|
Err(err)
|
||||||
},
|
},
|
||||||
PromptAction::Recall(_, _) => {
|
PromptAction::Recall(..) => {
|
||||||
let msg = "Cannot recall history inside a list";
|
let msg = "Cannot recall history inside a list";
|
||||||
let err = EditError::Failure(msg.into());
|
let err = EditError::Failure(msg.into());
|
||||||
|
|
||||||
|
@ -1120,7 +1120,7 @@ impl Promptable<ProgramContext, ProgramStore, IambInfo> for MemberItem {
|
||||||
|
|
||||||
Err(err)
|
Err(err)
|
||||||
},
|
},
|
||||||
PromptAction::Recall(_, _) => {
|
PromptAction::Recall(..) => {
|
||||||
let msg = "Cannot recall history inside a list";
|
let msg = "Cannot recall history inside a list";
|
||||||
let err = EditError::Failure(msg.into());
|
let err = EditError::Failure(msg.into());
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ use matrix_sdk::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use modalkit::{
|
use modalkit::{
|
||||||
|
input::dialog::PromptYesNo,
|
||||||
tui::{
|
tui::{
|
||||||
buffer::Buffer,
|
buffer::Buffer,
|
||||||
layout::Rect,
|
layout::Rect,
|
||||||
|
@ -40,6 +41,7 @@ use modalkit::{
|
||||||
|
|
||||||
use modalkit::editing::{
|
use modalkit::editing::{
|
||||||
action::{
|
action::{
|
||||||
|
Action,
|
||||||
EditError,
|
EditError,
|
||||||
EditInfo,
|
EditInfo,
|
||||||
EditResult,
|
EditResult,
|
||||||
|
@ -310,7 +312,16 @@ impl ChatState {
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
},
|
},
|
||||||
MessageAction::Redact(reason) => {
|
MessageAction::Redact(reason, skip_confirm) => {
|
||||||
|
if !skip_confirm {
|
||||||
|
let msg = "Are you sure you want to redact this message?";
|
||||||
|
let act = IambAction::Message(MessageAction::Redact(reason, true));
|
||||||
|
let prompt = PromptYesNo::new(msg, vec![Action::from(act)]);
|
||||||
|
let prompt = Box::new(prompt);
|
||||||
|
|
||||||
|
return Err(UIError::NeedConfirm(prompt));
|
||||||
|
}
|
||||||
|
|
||||||
let room = self.get_joined(&store.application.worker)?;
|
let room = self.get_joined(&store.application.worker)?;
|
||||||
let event_id = match &msg.event {
|
let event_id = match &msg.event {
|
||||||
MessageEvent::EncryptedOriginal(ev) => ev.event_id.clone(),
|
MessageEvent::EncryptedOriginal(ev) => ev.event_id.clone(),
|
||||||
|
@ -672,13 +683,14 @@ impl PromptActions<ProgramContext, ProgramStore, IambInfo> for ChatState {
|
||||||
&mut self,
|
&mut self,
|
||||||
dir: &MoveDir1D,
|
dir: &MoveDir1D,
|
||||||
count: &Count,
|
count: &Count,
|
||||||
|
prefixed: bool,
|
||||||
ctx: &ProgramContext,
|
ctx: &ProgramContext,
|
||||||
_: &mut ProgramStore,
|
_: &mut ProgramStore,
|
||||||
) -> EditResult<Vec<(ProgramAction, ProgramContext)>, IambInfo> {
|
) -> EditResult<Vec<(ProgramAction, ProgramContext)>, IambInfo> {
|
||||||
let count = ctx.resolve(count);
|
let count = ctx.resolve(count);
|
||||||
let rope = self.tbox.get();
|
let rope = self.tbox.get();
|
||||||
|
|
||||||
let text = self.sent.recall(&rope, &mut self.sent_scrollback, *dir, count);
|
let text = self.sent.recall(&rope, &mut self.sent_scrollback, *dir, prefixed, count);
|
||||||
|
|
||||||
if let Some(text) = text {
|
if let Some(text) = text {
|
||||||
self.tbox.set_text(text);
|
self.tbox.set_text(text);
|
||||||
|
@ -702,7 +714,9 @@ impl Promptable<ProgramContext, ProgramStore, IambInfo> for ChatState {
|
||||||
match act {
|
match act {
|
||||||
PromptAction::Submit => self.submit(ctx, store),
|
PromptAction::Submit => self.submit(ctx, store),
|
||||||
PromptAction::Abort(empty) => self.abort(*empty, ctx, store),
|
PromptAction::Abort(empty) => self.abort(*empty, ctx, store),
|
||||||
PromptAction::Recall(dir, count) => self.recall(dir, count, ctx, store),
|
PromptAction::Recall(dir, count, prefixed) => {
|
||||||
|
self.recall(dir, count, *prefixed, ctx, store)
|
||||||
|
},
|
||||||
_ => Err(EditError::Unimplemented("unknown prompt action".to_string())),
|
_ => Err(EditError::Unimplemented("unknown prompt action".to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,11 +43,13 @@ use modalkit::{
|
||||||
WriteFlags,
|
WriteFlags,
|
||||||
},
|
},
|
||||||
editing::completion::CompletionList,
|
editing::completion::CompletionList,
|
||||||
|
input::dialog::PromptYesNo,
|
||||||
input::InputContext,
|
input::InputContext,
|
||||||
widgets::{TermOffset, TerminalCursor, WindowOps},
|
widgets::{TermOffset, TerminalCursor, WindowOps},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::base::{
|
use crate::base::{
|
||||||
|
IambAction,
|
||||||
IambError,
|
IambError,
|
||||||
IambId,
|
IambId,
|
||||||
IambInfo,
|
IambInfo,
|
||||||
|
@ -218,6 +220,24 @@ impl RoomState {
|
||||||
Err(IambError::NotJoined.into())
|
Err(IambError::NotJoined.into())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
RoomAction::Leave(skip_confirm) => {
|
||||||
|
if let Some(room) = store.application.worker.client.get_joined_room(self.id()) {
|
||||||
|
if skip_confirm {
|
||||||
|
room.leave().await.map_err(IambError::from)?;
|
||||||
|
|
||||||
|
Ok(vec![])
|
||||||
|
} else {
|
||||||
|
let msg = "Do you really want to leave this room?";
|
||||||
|
let leave = IambAction::Room(RoomAction::Leave(true));
|
||||||
|
let prompt = PromptYesNo::new(msg, vec![Action::from(leave)]);
|
||||||
|
let prompt = Box::new(prompt);
|
||||||
|
|
||||||
|
Err(UIError::NeedConfirm(prompt))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(IambError::NotJoined.into())
|
||||||
|
}
|
||||||
|
},
|
||||||
RoomAction::Members(mut cmd) => {
|
RoomAction::Members(mut cmd) => {
|
||||||
let width = Count::Exact(30);
|
let width = Count::Exact(30);
|
||||||
let act =
|
let act =
|
||||||
|
|
|
@ -1215,7 +1215,7 @@ impl ClientWorker {
|
||||||
let _req = request.await.map_err(IambError::from)?;
|
let _req = request.await.map_err(IambError::from)?;
|
||||||
let info = format!("Sent verification request to {user_id}");
|
let info = format!("Sent verification request to {user_id}");
|
||||||
|
|
||||||
Ok(InfoMessage::from(info).into())
|
Ok(Some(InfoMessage::from(info)))
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let msg = format!("Could not find identity information for {user_id}");
|
let msg = format!("Could not find identity information for {user_id}");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue