diff --git a/src/comments.rs b/src/comments.rs index e64c607..1ef4397 100644 --- a/src/comments.rs +++ b/src/comments.rs @@ -1,9 +1,7 @@ #[derive(Debug)] pub struct Comment { // index where the comment starts - idx: usize, - // does the comment have a leading space - space: bool, + pub idx: usize, } pub fn find_comment(line: &str) -> Option { @@ -24,7 +22,6 @@ pub fn find_comment(line: &str) -> Option { if prev_c == '%' { return Some(Comment { idx: 0, - space: false, }); } @@ -40,12 +37,10 @@ pub fn find_comment(line: &str) -> Option { if prev_c == ' ' { return Some(Comment { idx: i, - space: true, }); } else if prev_c != '\\' { return Some(Comment { idx: i, - space: false, }); } } diff --git a/src/format.rs b/src/format.rs index cdff0d2..fc3f199 100644 --- a/src/format.rs +++ b/src/format.rs @@ -2,15 +2,21 @@ use crate::indent::*; use crate::subs::*; use crate::wrap::*; +const MAX_WRAP_TRY: u8 = 3; + pub fn format_file(file: &str, debug: bool) -> String { let mut new_file = remove_extra_newlines(file); new_file = begin_end_environments_new_line(&new_file); new_file = remove_tabs(&new_file); new_file = remove_trailing_spaces(&new_file); new_file = apply_indent(&new_file, debug); - //if needs_wrap(&file){ - //new_file = wrap(&new_file); - //new_file = apply_indent(&new_file, debug); - //}; + + let mut wrap_tries = 0; + while needs_wrap(&file) && wrap_tries < MAX_WRAP_TRY { + wrap_tries += 1; + new_file = wrap(&new_file); + new_file = apply_indent(&new_file, debug); + }; + new_file } diff --git a/src/tests.rs b/src/tests.rs index 5a9fcf0..9c0aad4 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -51,6 +51,8 @@ mod tests { #[test] fn test_files() { + test_file("wrap", "tex"); + /* let filenames: Vec = fs::read_dir("tests/") .unwrap() .map(|f| f.unwrap().file_name().into_string().unwrap()) @@ -69,5 +71,6 @@ mod tests { let extension = &extensions[i]; test_file(&filename, &extension); } + */ } } diff --git a/src/wrap.rs b/src/wrap.rs index 74d28cb..bc44028 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -1,30 +1,96 @@ -// wrapping +use crate::comments::*; const WRAP: usize = 80; -// any line under WRAP chars must be unchanged - -// while line is long -// find the first break space (should be after non-space character) -// if break is after WRAP, throw warning -// if no comment, replace space with newline -// if comment and break before comment, replace space with newline -// if comment and break after comment -// if spaced comment -// replace space before comment with newline -// if non-spaced comment -// replace comment % with %\n% - pub fn needs_wrap(file: &str) -> bool { file.lines().any(|l| l.len() > WRAP) } +pub fn line_needs_wrap(line: &str) -> bool { + line.len() > WRAP +} + +pub fn find_wrap_point(line: &str) -> Option { + let mut wrap_point: Option = None; + for i in 0..WRAP { + if line.chars().nth(i) == Some(' ') { + wrap_point = Some(i); + } + } + wrap_point +} + +pub fn wrap_line(line: &str) -> String { + let mut remaining_line = line.to_string(); + let mut new_line = "".to_string(); + let mut can_wrap = true; + while line_needs_wrap(&remaining_line) && can_wrap { + let wrap_point = find_wrap_point(&remaining_line); + let comm = find_comment(&remaining_line); + match wrap_point { + Some(p) => { + let line_start = match comm { + Some(ref c) => { + if p > c.idx { + "%" + } + else { + "" + } + } + None => "" + }; + new_line.push_str(&remaining_line[0..p]); + new_line.push('\n'); + remaining_line = remaining_line[p..remaining_line.len()].to_string(); + remaining_line.insert_str(0, line_start); + }, + None => { + can_wrap = false; + println!("long line cannot be wrapped!"); + println!("{}", line); + } + } + } + new_line.push_str(&remaining_line); + new_line +} + pub fn wrap(file: &str) -> String { let mut new_file = "".to_string(); let lines: Vec<&str> = file.lines().collect(); - for line in lines.iter() { + for line in lines { + if line_needs_wrap(line) { + let new_line = wrap_line(line); + new_file.push_str(&new_line); + } else { + new_file.push_str(line); + } + new_file.push('\n'); } + new_file +} + +#[cfg(test)] - //dbg!(&file); - file.to_string() +#[test] +fn test_wrap_line() { + // no comment + let s_in = "This line is too long because it has more than eighty characters inside it. \ + Therefore it should be split."; + let s_out = "This line is too long because it has more than eighty characters inside it.\n \ + Therefore it should be split."; + assert_eq!(wrap_line(s_in), s_out); + // break before comment + let s_in = "This line is too long because it has more than eighty characters inside it. \ + Therefore it % should be split."; + let s_out = "This line is too long because it has more than eighty characters inside it.\n \ + Therefore it % should be split."; + assert_eq!(wrap_line(s_in), s_out); + // break after comment + let s_in = "This line is too long because % it has more than eighty characters inside it. \ + Therefore it should be split."; + let s_out = "This line is too long because % it has more than eighty characters inside it.\n\ + % Therefore it should be split."; + assert_eq!(wrap_line(s_in), s_out); } diff --git a/tests/wrap_in.tex b/tests/wrap_in.tex index ad01e9e..dcb1a4c 100644 --- a/tests/wrap_in.tex +++ b/tests/wrap_in.tex @@ -11,7 +11,7 @@ This line is too long because it has more than% eighty characters inside it. Therefore it should be split. % unbreakable line -Thislineistoolongbecauseithasmorethan%eightycharactersinsideit.Thereforeitshouldbesplit. +Thislineistoolongbecauseithasmorethan%eightycharactersinsideit.Buttherearenospacessoitcannotbesplit. % long line only after indenting ( diff --git a/tests/wrap_out.tex b/tests/wrap_out.tex index d19f0a0..e4a49db 100644 --- a/tests/wrap_out.tex +++ b/tests/wrap_out.tex @@ -7,15 +7,15 @@ Therefore it % should be split. % break after spaced comment -This line is too long because it has more than -% eighty characters inside it. Therefore it should be split. +This line is too long because it has more than % eighty characters inside it. +% Therefore it should be split. % break after non-spaced comment -This line is too long because it has more than% -% eighty characters inside it. Therefore it should be split. +This line is too long because it has more than% eighty characters inside it. +% Therefore it should be split. % unbreakable line -Thislineistoolongbecauseithasmorethan%eightycharactersinsideitThereforeitcannotbesplit. +Thislineistoolongbecauseithasmorethan%eightycharactersinsideit.Buttherearenospacessoitcannotbesplit. % long line only after indenting ( @@ -24,9 +24,9 @@ ) % double break after comment -This line has a long comment. -% This comment is very long so needs to be split over three lines which is -% another edge case which should be checked here with all these extra words +This line has a long comment. % This comment is very long so needs to be split +% over three lines which is another edge case which should be checked here with +% all these extra words % double break after only comment % This line is all a long comment. This comment is very long so needs to be