Browse Source

ui: use any email as composing template with edit command

concerns #38
tags/pre-alpha-0.0
Manos Pitsidianakis 3 years ago
parent
commit
9b4b6051f1
Signed by untrusted user: epilys GPG Key ID: 73627C2F690DF710
  1. 7
      melib/src/error.rs
  2. 5
      melib/src/mailbox/email.rs
  3. 19
      melib/src/mailbox/email/compose.rs
  4. 17
      ui/src/components/mail/compose.rs
  5. 29
      ui/src/components/mail/view/thread.rs
  6. 6
      ui/src/components/utilities.rs
  7. 1
      ui/src/execute/actions.rs

7
melib/src/error.rs

@ -29,6 +29,7 @@ use std::fmt;
use std::io;
use std::result;
use std::string;
use std::str;
use nom;
@ -90,6 +91,12 @@ impl From<string::FromUtf8Error> for MeliError {
}
}
impl From<str::Utf8Error> for MeliError {
#[inline]
fn from(kind: str::Utf8Error) -> MeliError {
MeliError::new(format!("{:?}", kind))
}
}
//use std::option;
//impl From<option::NoneError> for MeliError {
// #[inline]

5
melib/src/mailbox/email.rs

@ -557,6 +557,11 @@ impl Envelope {
}
builder.build()
}
pub fn headers<'a>(&self, bytes: &'a [u8]) -> Result<Vec<(&'a str, &'a str)>> {
let ret = parser::headers(bytes).to_full_result()?;
let len = ret.len();
ret.into_iter().try_fold(Vec::with_capacity(len), |mut acc, (a, b)| Ok({acc.push((std::str::from_utf8(a)?, std::str::from_utf8(b)?)); acc }))
}
pub fn body(&self, mut operation: Box<BackendOp>) -> Attachment {
let file = operation.as_bytes();
self.body_bytes(file.unwrap())

19
melib/src/mailbox/email/compose.rs

@ -1,4 +1,5 @@
use super::*;
use mailbox::backends::BackendOp;
use chrono::{DateTime, Local};
use data_encoding::BASE64_MIME;
use std::str;
@ -93,6 +94,23 @@ impl str::FromStr for Draft {
}
impl Draft {
pub fn edit(envelope: &Envelope, mut op: Box<BackendOp>) -> Self {
let mut ret = Draft::default();
//TODO: Inform user if error
{
let bytes = op.as_bytes().unwrap_or(&[]);
for (h, v) in envelope.headers(bytes).unwrap_or_else(|_| Vec::new()) {
ret.header_order.push(h.into());
ret.headers_mut()
.insert(h.into(), v.into());
}
}
ret.body = envelope.body(op).text();
ret
}
pub fn new_reply(envelope: &Envelope, bytes: &[u8]) -> Self {
let mut ret = Draft::default();
ret.headers_mut().insert(
@ -128,6 +146,7 @@ impl Draft {
let mut ret = String::with_capacity(reply_body.len() + lines.len());
for l in lines {
ret.push('>');
ret.push(' ');
ret.push_str(l.trim());
ret.push('\n');
}

17
ui/src/components/mail/compose.rs

@ -117,6 +117,23 @@ impl Composer {
* msg: index of message we reply to in thread_nodes
* context: current context
*/
pub fn edit(coordinates: (usize, usize, usize), msg: usize, context: &Context) -> Self {
let mailbox = &context.accounts[coordinates.0][coordinates.1]
.as_ref()
.unwrap();
let threads = &mailbox.collection.threads;
let thread_nodes = &threads.thread_nodes();
let mut ret = Composer::default();
let message = &mailbox.collection[&thread_nodes[msg].message().unwrap()];
let op = context.accounts[coordinates.0]
.backend
.operation(message.hash(), mailbox.folder.hash());
ret.draft = Draft::edit(message, op);
ret.account_cursor = coordinates.0;
ret
}
pub fn with_context(coordinates: (usize, usize, usize), msg: usize, context: &Context) -> Self {
let mailbox = &context.accounts[coordinates.0][coordinates.1]
.as_ref()

29
ui/src/components/mail/view/thread.rs

@ -555,6 +555,35 @@ impl Component for ThreadView {
});
return true;
}
UIEventType::Input(Key::Char('e')) => {
{
let mailbox = &context.accounts[self.coordinates.0][self.coordinates.1]
.as_ref()
.unwrap();
let threads = &mailbox.collection.threads;
let thread_node = &threads.thread_nodes()[threads.root_set(self.coordinates.2)];
let i = if let Some(i) = thread_node.message() {
i
} else {
threads.thread_nodes()[thread_node.children()[0]]
.message()
.unwrap()
};
let envelope: &Envelope = &mailbox.collection[&i];
let op = context.accounts[self.coordinates.0]
.backend
.operation(envelope.hash(), mailbox.folder.hash());
eprintln!("sending action edit for {}, {}", envelope.message_id(), op.description());
}
context.replies.push_back(UIEvent {
id: 0,
event_type: UIEventType::Action(Tab(Edit(
self.coordinates,
self.entries[self.expanded_pos].index.1,
))),
});
return true;
}
UIEventType::Input(Key::Up) => {
if self.cursor_pos > 0 {
self.new_cursor_pos = self.new_cursor_pos.saturating_sub(1);

6
ui/src/components/utilities.rs

@ -980,6 +980,12 @@ impl Component for Tabbed {
self.children[self.cursor_pos].set_dirty();
return true;
}
UIEventType::Action(Tab(Edit(coordinates, msg))) => {
self.add_component(Box::new(Composer::edit(coordinates, msg, context)));
self.cursor_pos = self.children.len() - 1;
self.children[self.cursor_pos].set_dirty();
return true;
}
UIEventType::Action(Tab(TabOpen(ref mut e))) if e.is_some() => {
self.add_component(e.take().unwrap());
self.cursor_pos = self.children.len() - 1;

1
ui/src/execute/actions.rs

@ -42,6 +42,7 @@ pub enum TabAction {
NewDraft,
Reply((usize, usize, usize), usize), // thread coordinates (account, mailbox, root_set idx) and message idx
Close,
Edit((usize, usize, usize), usize), // thread coordinates (account, mailbox, root_set idx) and message idx
Kill(Uuid),
}

Loading…
Cancel
Save