use loc::Loc;
use focus_char::FocusChar;
use optimizer::Optimizer;
use svg_element::SvgElement;
use svg::node::element::SVG;
use svg::Node;
use svg::node::element::{
Circle as SvgCircle,
Definitions,
Line as SvgLine,
Marker,
Path as SvgPath,
Rectangle as SvgRect,
Style,
Text as SvgText,
};
use element::Element;
use pom::TextInput;
use pom::parser::{sym,none_of};
use settings::Settings;
use unicode_width::UnicodeWidthChar;
#[derive(Debug)]
pub struct Grid {
pub settings: Settings,
index: Vec<Vec<String>>,
text_elm: Vec<(usize, usize, String)>,
}
impl Grid {
/// instantiate a grid from input ascii text
/// Issues:
/// 1. 2-width, 5 bytes, single character i.e. 统
/// 2. 1-width, 2 bytes, single character i.e. ö
/// 3. 1-width, 3 bytes, single character i.e. o͡͡͡
pub fn from_str(s: &str, settings: &Settings) -> Grid {
let lines: Vec<&str> = s.lines().collect();
let mut rows: Vec<Vec<String>> = Vec::with_capacity(lines.len());
let mut text_elm: Vec<(usize, usize, String)> = vec![];
for (y, line) in lines.iter().enumerate() {
let (line, escaped_texts): (String, Vec<(usize, String)>) = exclude_escaped_text(line);
let mut row: Vec<String> = Vec::with_capacity(line.chars().count());
for (x, escaped) in escaped_texts {
text_elm.push((x, y, svg_escape(&escaped)));
}
for ch in line.chars() {
if let Some(1) = ch.width() {
row.push(format!("{}", ch));
} else if let Some(2) = ch.width() {
row.push(format!("{}", ch));
// HACK: push a blank to the next cell,
//in order to make this character twice as
// big and aligns the next succeeding characters on
// this row
row.push(format!("\0"));
}
// if zero width char, append it to the previous string
else if let Some(0) = ch.width() {
let prev: Option<String> = row.pop();
match prev {
Some(mut prev) => {
prev.push(ch);
row.push(prev);
}
None => (),
}
}
}
rows.push(row);
}
Grid {
settings: settings.clone(),
index: rows,
text_elm: text_elm,
}
}
/// reassemble the Grid content into a string
/// trimming unneeded whitespace to the right for every line
pub fn to_string(&self) -> String {
let mut buff = String::new();
let mut do_ln = false;
for row in self.index.iter() {
let mut line = String::new();
if do_ln {
//first line don't do \n
buff.push('\n');
} else {
do_ln = true;
}
for cell in row {
if cell == "\0" {
; //easy make over the full-width hack of the string
} else {
line.push_str(cell);
}
}
buff.push_str(&line);
}
buff
}
pub fn rows(&self) -> usize {
self.index.len()
}
/// get the maximum row len
pub fn columns(&self) -> usize {
self.index.iter().map(|r| r.len()).max().unwrap_or(0)
}
/// get a character at this location
/// widths are computed since there are
/// characters that spans 2 columns
/// and characters that has 0 width
///
pub fn get(&self, loc: &Loc) -> Option<&String> {
match self.index.get(loc.y as usize) {
Some(row) => row.get(loc.x as usize),
None => None,
}
}
/// put a text into this location
/// prepare the grid for this location first
pub fn put(&mut self, loc: &Loc, s: &str) {
let new_loc = self.accomodate(loc);
if let Some(row) = self.index.get_mut(new_loc.y as usize) {
if let Some(cell) = row.get_mut(new_loc.x as usize) {
*cell = s.to_owned();
} else {
panic!("no cell on this {}", new_loc.x);
}
} else {
panic!("no row on this {}", new_loc.y);
}
}
/// insert a new line to at this point
pub fn insert_line(&mut self, line: usize) {
self.accomodate(&Loc::new(0,