message.rs: Use itertools to group quotes lines

I've tried to simplify the code that group lines by quote/no-quote, it's
a lot simpler using the itertools crate.

This patch also adds a new enum for the message part, instead of use a
simple bool, so we can manage other kind of rendering in a message. I
was thinking about the Markdown code block for example.
This commit is contained in:
Daniel García Moreno 2018-07-29 19:57:40 +02:00
parent d4598b9e73
commit d093f03bfc
4 changed files with 57 additions and 49 deletions

16
Cargo.lock generated
View file

@ -289,6 +289,11 @@ name = "dtoa"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "either"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "encoding_rs"
version = "0.7.2"
@ -373,6 +378,7 @@ dependencies = [
"gstreamer-player 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"gtk 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"html2pango 0.1.0 (git+https://gitlab.gnome.org/World/html2pango)",
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"letter-avatar 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"notify-rust 3.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -897,6 +903,14 @@ dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itertools"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.2"
@ -2301,6 +2315,7 @@ dependencies = [
"checksum dbus 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4a0c10ea61042b7555729ab0608727bbbb06ce709c11e6047cfa4e10f6d052d"
"checksum dbus 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58ec7b4cac6f79f36af1cd9cfdb9b935fc5a4e899f494ee03a3a6165f7d10b4b"
"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
"checksum encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98fd0f24d1fb71a4a6b9330c8ca04cbd4e7cc5d846b54ca74ff376bc7c9f798d"
"checksum entities 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca"
"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
@ -2348,6 +2363,7 @@ dependencies = [
"checksum hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a5aa51f6ae9842239b0fac14af5f22123b8432b4cc774a44ff059fcba0f675ca"
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450"
"checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"

View file

@ -33,6 +33,7 @@ log = "0.4.3"
fragile = "0.2.1"
letter-avatar = "0.1.1"
sourceview = "0.4.0"
itertools = "0.7.8"
[dependencies.cairo-rs]
features = ["png"]

View file

@ -5,6 +5,7 @@ extern crate gtk;
extern crate gdk;
extern crate rand;
extern crate itertools;
extern crate gstreamer as gst;
extern crate gstreamer_player as gst_player;

View file

@ -3,6 +3,7 @@ extern crate chrono;
extern crate pango;
extern crate glib;
use itertools::Itertools;
use app::App;
use i18n::i18n;
@ -285,61 +286,17 @@ impl<'a> MessageBox<'a> {
fn calculate_msg_parts(&self, body: &str) -> Vec<gtk::Label> {
let mut parts_labels: Vec<gtk::Label> = vec![];
let lines: Vec<&str> = body.lines().map(|l| l.trim()).collect();
let mut lines_read: usize = 0;
let mut parts_lines: Vec<(Vec<&str>, bool)> = vec![];
while lines_read < lines.len() {
if let Some(line) = lines.get(lines_read) {
let is_quote = line.starts_with(">");
let part_lines: Vec<&str> = if is_quote {
lines.iter().skip(lines_read).take_while(|line| {
if line.starts_with(">") {
lines_read += 1;
true
} else {
false
}
}).map(|line| *line).collect()
} else {
lines.iter().skip(lines_read).take_while(|line| {
if !line.starts_with(">") {
lines_read += 1;
true
} else {
false
}
}).map(|line| *line).collect()
};
parts_lines.push((part_lines, is_quote));
}
}
for (lines, is_quote) in parts_lines.iter_mut() {
for line in lines {
if *is_quote {
*line = line.trim_left_matches(">").trim_left();
}
}
}
let parts: Vec<(String, bool)> = parts_lines.iter()
.map(|(part_lines, is_quote)|
(part_lines.join("\n").trim().to_string(), *is_quote)
).collect();
for (part, is_quote) in parts {
for (part, kind) in split_msg(body) {
let msg_part = gtk::Label::new("");
self.connect_right_click_menu(msg_part.clone().upcast::<gtk::Widget>());
msg_part.set_markup(&markup_text(&part));
self.set_label_styles(&msg_part);
if is_quote {
if let Some(style) = msg_part.get_style_context() {
style.add_class("quote");
match kind {
MsgPartType::Quote => {
msg_part.get_style_context().map(|s| s.add_class("quote"));
}
_ => {}
}
parts_labels.push(msg_part);
@ -691,3 +648,36 @@ fn set_username_async(backend: Sender<BKCommand>,
}
});
}
#[derive(PartialEq)]
enum MsgPartType {
Normal,
Quote,
}
fn kind_of_line(line: &&str) -> MsgPartType {
match line {
l if l.starts_with(">") => MsgPartType::Quote,
_ => MsgPartType::Normal,
}
}
/// Split a message into parts depending on the kind
/// Currently supported types:
/// * Normal
/// * Quote
fn split_msg(body: &str) -> Vec<(String, MsgPartType)> {
let mut parts: Vec<(String, MsgPartType)> = vec![];
for (k, group) in body.lines()
.map(|l| l.trim())
.group_by(kind_of_line).into_iter() {
let v: Vec<&str> = group
.map(|l| l.trim_left_matches(">").trim_left())
.collect();
let s = v.join("\n").to_string();
parts.push((s, k));
}
parts
}