From 46af7774a5b4410181a105a05cba78577cf49845 Mon Sep 17 00:00:00 2001 From: spiders Date: Tue, 3 May 2022 15:02:07 -0700 Subject: [PATCH] introduced BubbleConfig & config_from_string; refactored accordingly this is in preparation for - introducing configuring the bubble - fixing right bubble alignment --- src/bubbles.rs | 242 +++++++++++++++++++++++++++++++++++++------------ src/main.rs | 34 +++---- 2 files changed, 199 insertions(+), 77 deletions(-) diff --git a/src/bubbles.rs b/src/bubbles.rs index 5e8fa06..4ba8aa5 100644 --- a/src/bubbles.rs +++ b/src/bubbles.rs @@ -1,70 +1,192 @@ use voca_rs::*; -pub fn bubble_from_text(text: &str, bubble_anchor: usize, max_length: usize) -> String { - bubble_from_lines(wrap_block(text, max_length), bubble_anchor) +// carry's information about the anchor point for a bubble, what column to wrap words at, and what the bubbles border looks like +pub struct BubbleConfig { + anchor: usize, + wrap: usize, + + top: String, + left: String, + right: String, + bottom: String, + top_left: String, + top_right: String, + bottom_left: String, + bottom_right: String, + middle_left: String, + middle_right: String, } -fn bubble_from_lines(lines: Vec, min_length: usize) -> String { - let longest_length: usize; - let lengths: Vec<(&String, usize)> = lines - .iter() - .zip(lines.iter().map(|s| count::count_graphemes(s))) - .collect(); - match lines.iter().map(|s| count::count_graphemes(s)).max() { - None => return "".to_string(), - Some(l) => longest_length = l, - }; +impl BubbleConfig { + // assembles a config from critical information, attempting to use sensible defaults where possible + pub fn config_from_string(anchor: usize, wrap: usize, border: Option) -> BubbleConfig { + if let Some(border) = border { + let chars = split::graphemes(&border); + let top = if let Some(item) = chars.get(0) { + item.to_string() + } else { + // Some("") results in the default like None + return BubbleConfig { + anchor, + wrap, - // let line_length = cmp::max(longest_length, min_length); - let line_length = longest_length; - let left_pad_length = if longest_length < min_length { - min_length + (longest_length / 2) + 2 - } else { - 0 - }; + top: "_".to_string(), + left: "<".to_string(), + right: ">".to_string(), + bottom: "-".to_string(), + top_left: "/".to_string(), + top_right: "\\".to_string(), + bottom_left: "\\".to_string(), + bottom_right: "/".to_string(), + middle_left: "|".to_string(), + middle_right: "|".to_string(), + }; + }; + let left = if let Some(item) = chars.get(1) { + item.to_string() + } else { + top.clone() + }; + let right = if let Some(item) = chars.get(2) { + item.to_string() + } else { + left.clone() + }; + let bottom = if let Some(item) = chars.get(3) { + item.to_string() + } else { + top.clone() + }; + let top_left = if let Some(item) = chars.get(4) { + item.to_string() + } else { + left.clone() + }; + let top_right = if let Some(item) = chars.get(5) { + item.to_string() + } else { + right.clone() + }; + let bottom_left = if let Some(item) = chars.get(6) { + item.to_string() + } else { + left.clone() + }; + let bottom_right = if let Some(item) = chars.get(7) { + item.to_string() + } else { + right.clone() + }; + let middle_left = if let Some(item) = chars.get(8) { + item.to_string() + } else { + left.clone() + }; + let middle_right = if let Some(item) = chars.get(9) { + item.to_string() + } else { + right.clone() + }; + BubbleConfig { + anchor, + wrap, - let bubble_top = manipulate::pad_left( - &format!(" _{}_ \n", "_".repeat(line_length)), - left_pad_length, - " ", - ); - let bubble_bottom = manipulate::pad_left( - &format!(" -{}- ", "-".repeat(line_length)), - left_pad_length, - " ", - ); - let mut bubble_body = String::new(); - - match lines.len() { - 1 => { - return format!( - "{}{}{}", - bubble_top, - manipulate::pad_left(&format!("< {} >\n", lines[0]), left_pad_length, " "), - bubble_bottom - ) - } - n => { - bubble_body.push_str(&manipulate::pad_left( - &format!("/ {} \\\n", lines[0]), - left_pad_length, - " ", - )); - if n > 2 { - for i in 1..n - 1 { - bubble_body.push_str(&manipulate::pad_left( - &format!("| {} |\n", lines[i]), - left_pad_length, - " ", - )); - } + top, + left, + right, + bottom, + top_left, + top_right, + bottom_left, + bottom_right, + middle_left, + middle_right, + } + } else { + BubbleConfig { + anchor, + wrap, + + top: "_".to_string(), + left: "<".to_string(), + right: ">".to_string(), + bottom: "-".to_string(), + top_left: "/".to_string(), + top_right: "\\".to_string(), + bottom_left: "\\".to_string(), + bottom_right: "/".to_string(), + middle_left: "|".to_string(), + middle_right: "|".to_string(), + } + } + } + + pub fn text(&self, text: &str) -> String { + self.bubble_from_lines(wrap_block(text, self.wrap)) + } + + fn bubble_from_lines(&self, lines: Vec) -> String { + let longest_length: usize; + let lengths: Vec<(&String, usize)> = lines + .iter() + .zip(lines.iter().map(|s| count::count_graphemes(s))) + .collect(); + match lines.iter().map(|s| count::count_graphemes(s)).max() { + None => return "".to_string(), + Some(l) => longest_length = l, + }; + + // let line_length = cmp::max(longest_length, min_length); + let line_length = longest_length; + let left_pad_length = if longest_length < self.anchor { + self.anchor + (longest_length / 2) + 2 + } else { + 0 + }; + + let bubble_top = manipulate::pad_left( + &format!(" _{}_ \n", "_".repeat(line_length)), + left_pad_length, + " ", + ); + let bubble_bottom = manipulate::pad_left( + &format!(" -{}- ", "-".repeat(line_length)), + left_pad_length, + " ", + ); + let mut bubble_body = String::new(); + + match lines.len() { + 1 => { + return format!( + "{}{}{}", + bubble_top, + manipulate::pad_left(&format!("< {} >\n", lines[0]), left_pad_length, " "), + bubble_bottom + ) + } + n => { + bubble_body.push_str(&manipulate::pad_left( + &format!("/ {} \\\n", lines[0]), + left_pad_length, + " ", + )); + if n > 2 { + for i in 1..n - 1 { + bubble_body.push_str(&manipulate::pad_left( + &format!("| {} |\n", lines[i]), + left_pad_length, + " ", + )); + } + } + bubble_body.push_str(&manipulate::pad_left( + &format!("\\ {} /\n", lines[n - 1]), + left_pad_length, + " ", + )); + return format!("{}{}{}", bubble_top, bubble_body, bubble_bottom); } - bubble_body.push_str(&manipulate::pad_left( - &format!("\\ {} /\n", lines[n - 1]), - left_pad_length, - " ", - )); - return format!("{}{}{}", bubble_top, bubble_body, bubble_bottom); } } } diff --git a/src/main.rs b/src/main.rs index 82cdeea..985179d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,9 @@ mod bubbles; mod critters; mod kule; +use bubbles::*; use clap::Parser; +use critters::*; use kule::Formats; use kule::FourBit; use std::io; @@ -19,7 +21,7 @@ use voca_rs::*; fn main() { let cli = Args::parse(); let mut text = String::new(); - let config = cli.config_from_arguments(); + let (critter_config, bubble_config) = cli.configs_from_arguments(); if !cli.text.is_empty() { text = cli.text.join(" ") @@ -28,7 +30,7 @@ fn main() { .read_to_string(&mut text) .expect("failed to read input"); } - output(&text, config); + output(&text, critter_config, bubble_config); } #[derive(Parser, Debug)] @@ -88,7 +90,7 @@ struct Args { } impl Args { - fn config_from_arguments(&self) -> critters::CritterConfig { + fn configs_from_arguments(&self) -> (CritterConfig, BubbleConfig) { let mut eyes = self.lukin.clone(); let mut tongue = self.uta.clone(); let mut line = self.palisa.clone(); @@ -182,23 +184,21 @@ impl Args { _ => String::new(), }) } - critters::CritterConfig::config_from_string( - &eyes, - &tongue, - &line, - &object, - &Some(format), - &name, - ) + let critter_config = + CritterConfig::config_from_string(&eyes, &tongue, &line, &object, &Some(format), &name); + let bubble_config = BubbleConfig::config_from_string( + critter_config.template.anchor, + DEFAULT_MAXIMUM_LINE_LENGTH, + None, + ); + + (critter_config, bubble_config) } } -fn output(text: &str, config: critters::CritterConfig) -> () { - print!( - "{}", - bubbles::bubble_from_text(text, config.template.anchor, DEFAULT_MAXIMUM_LINE_LENGTH) - ); - println!("{}", config.format_critter()) +fn output(text: &str, critter_config: CritterConfig, bubble_config: BubbleConfig) -> () { + print!("{}", bubble_config.text(text)); + println!("{}", critter_config.format_critter()) } const DEFAULT_MAXIMUM_LINE_LENGTH: usize = 40;