/*! * Removes the common level of indention from description strings. For * instance, if an entire doc comment is indented 8 spaces we want to * remove those 8 spaces from every line. * * The first line of a string is allowed to be intend less than * subsequent lines in the same paragraph in order to account for * instances where the string containing the doc comment is opened in the * middle of a line, and each of the following lines is indented. */ export mk_pass; fn mk_pass() -> pass { text_pass::mk_pass(~"unindent", unindent) } fn unindent(s: ~str) -> ~str { let lines = str::lines_any(s); let mut saw_first_line = false; let mut saw_second_line = false; let min_indent = do vec::foldl(uint::max_value, lines) |min_indent, line| { // After we see the first non-whitespace line, look at // the line we have. If it is not whitespace, and therefore // part of the first paragraph, then ignore the indentation // level of the first line let ignore_previous_indents = saw_first_line && !saw_second_line && !str::is_whitespace(line); let min_indent = if ignore_previous_indents { uint::max_value } else { min_indent }; if saw_first_line { saw_second_line = true; } if str::is_whitespace(line) { min_indent } else { saw_first_line = true; let mut spaces = 0u; do str::all(line) |char| { // Only comparing against space because I wouldn't // know what to do with mixed whitespace chars if char == ' ' { spaces += 1u; true } else { false } }; uint::min(min_indent, spaces) } }; if vec::is_not_empty(lines) { let unindented = ~[str::trim(vec::head(lines))] + do par::anymap(vec::tail(lines)) |line| { if str::is_whitespace(line) { line } else { assert str::len(line) >= min_indent; str::slice(line, min_indent, str::len(line)) } }; str::connect(unindented, ~"\n") } else { s } } #[test] fn should_unindent() { let s = ~" line1\n line2"; let r = unindent(s); assert r == ~"line1\nline2"; } #[test] fn should_unindent_multiple_paragraphs() { let s = ~" line1\n\n line2"; let r = unindent(s); assert r == ~"line1\n\nline2"; } #[test] fn should_leave_multiple_indent_levels() { // Line 2 is indented another level beyond the // base indentation and should be preserved let s = ~" line1\n\n line2"; let r = unindent(s); assert r == ~"line1\n\n line2"; } #[test] fn should_ignore_first_line_indent() { // Thi first line of the first paragraph may not be indented as // far due to the way the doc string was written: // // #[doc = "Start way over here // and continue here"] let s = ~"line1\n line2"; let r = unindent(s); assert r == ~"line1\nline2"; } #[test] fn should_not_ignore_first_line_indent_in_a_single_line_para() { let s = ~"line1\n\n line2"; let r = unindent(s); assert r == ~"line1\n\n line2"; }