Add :open attachments command (#31)

Fixes #27
This commit is contained in:
Benjamin Große 2023-01-28 12:29:06 +00:00 committed by Ulyssa
parent a1574c6b8d
commit 1d93461183
No known key found for this signature in database
GPG key ID: 1B3965A3D18B9B64
5 changed files with 96 additions and 24 deletions

View file

@ -81,9 +81,9 @@ pub enum MessageAction {
/// Download an attachment to the given path.
///
/// The [bool] argument controls whether to overwrite any already existing file at the
/// destination path.
Download(Option<String>, bool),
/// The second argument controls whether to overwrite any already existing file at the
/// destination path, or to open the attachment after downloading.
Download(Option<String>, DownloadFlags),
/// Edit a sent message.
Edit,
@ -95,6 +95,18 @@ pub enum MessageAction {
Reply,
}
bitflags::bitflags! {
pub struct DownloadFlags: u32 {
const NONE = 0b00000000;
/// Overwrite file if it already exists.
const FORCE = 0b00000001;
/// Open file after downloading.
const OPEN = 0b00000010;
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RoomField {
Name,

View file

@ -10,6 +10,7 @@ use modalkit::{
};
use crate::base::{
DownloadFlags,
IambAction,
IambId,
MessageAction,
@ -317,7 +318,29 @@ fn iamb_download(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult
return Result::Err(CommandError::InvalidArgument);
}
let mact = MessageAction::Download(args.pop(), desc.bang);
let mut flags = DownloadFlags::NONE;
if desc.bang {
flags |= DownloadFlags::FORCE;
};
let mact = MessageAction::Download(args.pop(), flags);
let iact = IambAction::from(mact);
let step = CommandStep::Continue(iact.into(), ctx.context.take());
return Ok(step);
}
fn iamb_open(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
let mut args = desc.arg.strings()?;
if args.len() > 1 {
return Result::Err(CommandError::InvalidArgument);
}
let mut flags = DownloadFlags::OPEN;
if desc.bang {
flags |= DownloadFlags::FORCE;
};
let mact = MessageAction::Download(args.pop(), flags);
let iact = IambAction::from(mact);
let step = CommandStep::Continue(iact.into(), ctx.context.take());
@ -328,6 +351,7 @@ fn add_iamb_commands(cmds: &mut ProgramCommands) {
cmds.add_command(ProgramCommand { names: vec!["cancel".into()], f: iamb_cancel });
cmds.add_command(ProgramCommand { names: vec!["dms".into()], f: iamb_dms });
cmds.add_command(ProgramCommand { names: vec!["download".into()], f: iamb_download });
cmds.add_command(ProgramCommand { names: vec!["open".into()], f: iamb_open });
cmds.add_command(ProgramCommand { names: vec!["edit".into()], f: iamb_edit });
cmds.add_command(ProgramCommand { names: vec!["invite".into()], f: iamb_invite });
cmds.add_command(ProgramCommand { names: vec!["join".into()], f: iamb_join });

View file

@ -4,6 +4,8 @@ use std::fs;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use tokio;
use matrix_sdk::{
attachment::AttachmentConfig,
media::{MediaFormat, MediaRequest},
@ -55,6 +57,7 @@ use modalkit::editing::{
};
use crate::base::{
DownloadFlags,
IambAction,
IambBufferId,
IambError,
@ -155,7 +158,7 @@ impl ChatState {
Ok(None)
},
MessageAction::Download(filename, force) => {
MessageAction::Download(filename, flags) => {
if let MessageEvent::Original(ev) = &msg.event {
let media = client.media();
@ -202,29 +205,42 @@ impl ChatState {
},
};
if !force && filename.exists() {
let msg = format!(
"The file {} already exists; use :download! to overwrite it.",
filename.display()
);
let err = UIError::Failure(msg);
if filename.exists() {
if !flags.contains(DownloadFlags::FORCE) {
let msg = format!(
"The file {} already exists; add ! to end of command to overwrite it.",
filename.display()
);
let err = UIError::Failure(msg);
return Err(err);
return Err(err);
}
let req = MediaRequest { source, format: MediaFormat::File };
let bytes =
media.get_media_content(&req, true).await.map_err(IambError::from)?;
fs::write(filename.as_path(), bytes.as_slice())?;
msg.downloaded = true;
}
let req = MediaRequest { source, format: MediaFormat::File };
let info = if flags.contains(DownloadFlags::OPEN) {
// open::that may not return until the spawned program closes.
let target = filename.clone().into_os_string();
tokio::task::spawn_blocking(move || open::that(target));
let bytes =
media.get_media_content(&req, true).await.map_err(IambError::from)?;
fs::write(filename.as_path(), bytes.as_slice())?;
msg.downloaded = true;
let info = InfoMessage::from(format!(
"Attachment downloaded to {}",
filename.display()
));
InfoMessage::from(format!(
"Attachment downloaded to {} and opened",
filename.display()
))
} else {
InfoMessage::from(format!(
"Attachment downloaded to {}",
filename.display()
))
};
return Ok(info.into());
}