about summary refs log tree commit diff
path: root/src/rustdoc
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2012-01-24 22:02:36 -0800
committerBrian Anderson <banderson@mozilla.com>2012-01-24 23:24:54 -0800
commitb779277daecb81efc0d6b0d9920c35d283e10530 (patch)
treebcb07595afe2f097bba3b085f1dee1e4fb10c2ca /src/rustdoc
parente8694589143830f1eff367016a3bb72c124345a5 (diff)
rustdoc: Add a pass to normalize indentation levels in doc comments
Diffstat (limited to 'src/rustdoc')
-rw-r--r--src/rustdoc/rustdoc.rc1
-rwxr-xr-xsrc/rustdoc/rustdoc.rs1
-rw-r--r--src/rustdoc/unindent_pass.rs120
3 files changed, 122 insertions, 0 deletions
diff --git a/src/rustdoc/rustdoc.rc b/src/rustdoc/rustdoc.rc
index 15083e569b9..055ce07209f 100644
--- a/src/rustdoc/rustdoc.rc
+++ b/src/rustdoc/rustdoc.rc
@@ -25,6 +25,7 @@ mod prune_undoc_pass;
 mod prune_unexported_pass;
 mod desc_to_brief_pass;
 mod desc_pass;
+mod unindent_pass;
 mod trim_pass;
 mod astsrv;
 mod demo;
diff --git a/src/rustdoc/rustdoc.rs b/src/rustdoc/rustdoc.rs
index 4a0332eede6..45b20aefc6c 100755
--- a/src/rustdoc/rustdoc.rs
+++ b/src/rustdoc/rustdoc.rs
@@ -102,6 +102,7 @@ fn run(source_file: str) {
         prune_undoc_pass::mk_pass(),
         desc_to_brief_pass::mk_pass(),
         trim_pass::mk_pass(),
+        unindent_pass::mk_pass(),
         markdown_pass::mk_pass {|| std::io:: stdout()}
     ]);
 }
\ No newline at end of file
diff --git a/src/rustdoc/unindent_pass.rs b/src/rustdoc/unindent_pass.rs
new file mode 100644
index 00000000000..ea439fd94c4
--- /dev/null
+++ b/src/rustdoc/unindent_pass.rs
@@ -0,0 +1,120 @@
+#[doc = "
+
+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 {
+    desc_pass::mk_pass(unindent)
+}
+
+fn unindent(s: str) -> str {
+    let lines = str::lines_any(s);
+    let saw_first_line = false;
+    let saw_second_line = false;
+    let min_indent = 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 spaces = 0u;
+            str::loop_chars(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
+                }
+            };
+            math::min(min_indent, spaces)
+        }
+    };
+
+    if check vec::is_not_empty(lines) {
+        let unindented = [str::trim(vec::head(lines))]
+            + vec::map(vec::tail(lines)) {|line|
+            if str::is_whitespace(line) {
+                line
+            } else {
+                assert str::byte_len(line) >= min_indent;
+                str::char_slice(line, min_indent, str::char_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";
+}
\ No newline at end of file