Support composing messages in an external editor (#155)

This commit is contained in:
Leonid Dyachkov 2023-09-10 16:45:27 +03:00 committed by Ulyssa
parent 47e650c2be
commit 0565b6eb05
No known key found for this signature in database
GPG key ID: F2873CA2997B83C5
6 changed files with 141 additions and 19 deletions

105
Cargo.lock generated
View file

@ -253,9 +253,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.0.2" version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "487f1e0fcbe47deb8b0574e646def1c903389d95241dd1bbcc6ce4a715dfc0c1" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]] [[package]]
name = "blake3" name = "blake3"
@ -420,7 +420,7 @@ version = "4.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76e21918af71fb4bcd813230cf549e33d14f73d0326b932b630ce2930332b131" checksum = "76e21918af71fb4bcd813230cf549e33d14f73d0326b932b630ce2930332b131"
dependencies = [ dependencies = [
"bitflags 2.0.2", "bitflags 2.4.0",
"clap_derive", "clap_derive",
"clap_lex", "clap_lex",
"is-terminal", "is-terminal",
@ -961,6 +961,16 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "edit"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c562aa71f7bc691fde4c6bf5f93ae5a5298b617c2eb44c76c87832299a17fbb4"
dependencies = [
"tempfile",
"which",
]
[[package]] [[package]]
name = "either" name = "either"
version = "1.8.1" version = "1.8.1"
@ -1010,13 +1020,13 @@ dependencies = [
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.0" version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
dependencies = [ dependencies = [
"errno-dragonfly", "errno-dragonfly",
"libc", "libc",
"windows-sys 0.45.0", "windows-sys 0.48.0",
] ]
[[package]] [[package]]
@ -1071,6 +1081,12 @@ dependencies = [
"regex", "regex",
] ]
[[package]]
name = "fastrand"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.25" version = "1.0.25"
@ -1431,6 +1447,15 @@ dependencies = [
"digest 0.10.6", "digest 0.10.6",
] ]
[[package]]
name = "home"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
dependencies = [
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "html5ever" name = "html5ever"
version = "0.26.0" version = "0.26.0"
@ -1518,7 +1543,7 @@ dependencies = [
[[package]] [[package]]
name = "iamb" name = "iamb"
version = "0.0.8" version = "0.0.9-alpha.1"
dependencies = [ dependencies = [
"arboard", "arboard",
"bitflags 1.3.2", "bitflags 1.3.2",
@ -1527,6 +1552,7 @@ dependencies = [
"comrak", "comrak",
"css-color-parser", "css-color-parser",
"dirs", "dirs",
"edit",
"emojis", "emojis",
"futures", "futures",
"gethostname 0.4.1", "gethostname 0.4.1",
@ -1772,9 +1798,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.140" version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]] [[package]]
name = "line-wrap" name = "line-wrap"
@ -1812,6 +1838,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
[[package]]
name = "linux-raw-sys"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.9" version = "0.4.9"
@ -2379,7 +2411,7 @@ dependencies = [
"cfg-if", "cfg-if",
"instant", "instant",
"libc", "libc",
"redox_syscall", "redox_syscall 0.2.16",
"smallvec", "smallvec",
"winapi", "winapi",
] ]
@ -2392,7 +2424,7 @@ checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"redox_syscall", "redox_syscall 0.2.16",
"smallvec", "smallvec",
"windows-sys 0.45.0", "windows-sys 0.45.0",
] ]
@ -2925,6 +2957,15 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
] ]
[[package]]
name = "redox_syscall"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags 1.3.2",
]
[[package]] [[package]]
name = "redox_users" name = "redox_users"
version = "0.4.3" version = "0.4.3"
@ -2932,7 +2973,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
dependencies = [ dependencies = [
"getrandom 0.2.8", "getrandom 0.2.8",
"redox_syscall", "redox_syscall 0.2.16",
"thiserror", "thiserror",
] ]
@ -3167,13 +3208,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"errno 0.3.0", "errno 0.3.3",
"io-lifetimes", "io-lifetimes",
"libc", "libc",
"linux-raw-sys 0.3.1", "linux-raw-sys 0.3.1",
"windows-sys 0.45.0", "windows-sys 0.45.0",
] ]
[[package]]
name = "rustix"
version = "0.38.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdf14a7a466ce88b5eac3da815b53aefc208ce7e74d1c263aabb04d88c4abeb1"
dependencies = [
"bitflags 2.4.0",
"errno 0.3.3",
"libc",
"linux-raw-sys 0.4.7",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.20.8" version = "0.20.8"
@ -3594,6 +3648,19 @@ dependencies = [
"yaml-rust", "yaml-rust",
] ]
[[package]]
name = "tempfile"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
dependencies = [
"cfg-if",
"fastrand",
"redox_syscall 0.3.5",
"rustix 0.38.12",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "tendril" name = "tendril"
version = "0.4.3" version = "0.4.3"
@ -4238,6 +4305,18 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb"
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix 0.38.12",
]
[[package]] [[package]]
name = "wildmatch" name = "wildmatch"
version = "2.1.1" version = "2.1.1"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "iamb" name = "iamb"
version = "0.0.8" version = "0.0.9-alpha.1"
edition = "2018" edition = "2018"
authors = ["Ulyssa <git@ulyssa.dev>"] authors = ["Ulyssa <git@ulyssa.dev>"]
repository = "https://github.com/ulyssa/iamb" repository = "https://github.com/ulyssa/iamb"
@ -51,6 +51,7 @@ tracing-subscriber = "0.3.16"
unicode-segmentation = "^1.7" unicode-segmentation = "^1.7"
unicode-width = "0.1.10" unicode-width = "0.1.10"
url = {version = "^2.2.2", features = ["serde"]} url = {version = "^2.2.2", features = ["serde"]}
edit = "0.1.4"
[dependencies.modalkit] [dependencies.modalkit]
version = "0.0.16" version = "0.0.16"

View file

@ -202,6 +202,7 @@ pub enum RoomAction {
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum SendAction { pub enum SendAction {
Submit, Submit,
SubmitFromEditor,
Upload(String), Upload(String),
UploadImage(usize, usize, Cow<'static, [u8]>), UploadImage(usize, usize, Cow<'static, [u8]>),
} }
@ -222,6 +223,16 @@ pub enum IambAction {
ToggleScrollbackFocus, ToggleScrollbackFocus,
} }
impl IambAction {
/// Indicates whether this action will draw over the screen.
pub fn scribbles(&self) -> bool {
match self {
IambAction::Send(SendAction::SubmitFromEditor) => true,
_ => false,
}
}
}
impl From<HomeserverAction> for IambAction { impl From<HomeserverAction> for IambAction {
fn from(act: HomeserverAction) -> Self { fn from(act: HomeserverAction) -> Self {
IambAction::Homeserver(act) IambAction::Homeserver(act)

View file

@ -266,6 +266,18 @@ fn iamb_reply(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
return Ok(step); return Ok(step);
} }
fn iamb_editor(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
if !desc.arg.text.is_empty() {
return Result::Err(CommandError::InvalidArgument);
}
let sact = IambAction::from(SendAction::SubmitFromEditor);
let step = CommandStep::Continue(sact.into(), ctx.context.take());
return Ok(step);
}
fn iamb_rooms(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult { fn iamb_rooms(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);
@ -537,6 +549,11 @@ fn add_iamb_commands(cmds: &mut ProgramCommands) {
aliases: vec![], aliases: vec![],
f: iamb_welcome, f: iamb_welcome,
}); });
cmds.add_command(ProgramCommand {
name: "editor".into(),
aliases: vec![],
f: iamb_editor,
});
} }
pub fn setup_commands() -> ProgramCommands { pub fn setup_commands() -> ProgramCommands {

View file

@ -224,6 +224,9 @@ struct Application {
/// The tab layout before the last executed [TabAction]. /// The tab layout before the last executed [TabAction].
last_layout: Option<TabLayoutDescription<IambInfo>>, last_layout: Option<TabLayoutDescription<IambInfo>>,
/// Whether we need to do a full redraw (e.g., after running a subprocess).
dirty: bool,
} }
impl Application { impl Application {
@ -263,6 +266,7 @@ impl Application {
screen, screen,
focused: true, focused: true,
last_layout: None, last_layout: None,
dirty: true,
}) })
} }
@ -314,7 +318,8 @@ impl Application {
async fn step(&mut self) -> Result<TerminalKey, std::io::Error> { async fn step(&mut self) -> Result<TerminalKey, std::io::Error> {
loop { loop {
self.redraw(false, self.store.clone().lock().await.deref_mut())?; self.redraw(self.dirty, self.store.clone().lock().await.deref_mut())?;
self.dirty = false;
if !poll(Duration::from_secs(1))? { if !poll(Duration::from_secs(1))? {
// Redraw in case there's new messages to show. // Redraw in case there's new messages to show.
@ -479,6 +484,10 @@ impl Application {
ctx: ProgramContext, ctx: ProgramContext,
store: &mut ProgramStore, store: &mut ProgramStore,
) -> IambResult<EditInfo> { ) -> IambResult<EditInfo> {
if action.scribbles() {
self.dirty = true;
}
let info = match action { let info = match action {
IambAction::ToggleScrollbackFocus => { IambAction::ToggleScrollbackFocus => {
self.screen.current_window_mut()?.focus_toggle(); self.screen.current_window_mut()?.focus_toggle();

View file

@ -7,6 +7,7 @@ use std::path::{Path, PathBuf};
use modalkit::editing::store::RegisterError; use modalkit::editing::store::RegisterError;
use std::process::Command; use std::process::Command;
use tokio; use tokio;
use edit::edit as external_edit;
use matrix_sdk::{ use matrix_sdk::{
attachment::AttachmentConfig, attachment::AttachmentConfig,
@ -429,14 +430,18 @@ impl ChatState {
let mut show_echo = true; let mut show_echo = true;
let (event_id, msg) = match act { let (event_id, msg) = match act {
SendAction::Submit => { SendAction::Submit | SendAction::SubmitFromEditor => {
let msg = self.tbox.get(); let msg = self.tbox.get();
if msg.is_blank() { let msg = if let SendAction::SubmitFromEditor = act {
external_edit(msg.trim_end().to_string())?
} else if msg.is_blank() {
return Ok(None); return Ok(None);
} } else {
msg.trim_end().to_string()
};
let mut msg = text_to_message(msg.trim_end().to_string()); let mut msg = text_to_message(msg);
if let Some((_, event_id)) = &self.editing { if let Some((_, event_id)) = &self.editing {
msg.relates_to = Some(Relation::Replacement(Replacement::new( msg.relates_to = Some(Relation::Replacement(Replacement::new(