Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow # to appear in rustdoc code output. #41785

Merged
merged 1 commit into from
May 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 48 additions & 27 deletions src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,47 @@ pub struct MarkdownHtml<'a>(pub &'a str, pub RenderType);
/// A unit struct like `Markdown`, that renders only the first paragraph.
pub struct MarkdownSummaryLine<'a>(pub &'a str);

/// Returns Some(code) if `s` is a line that should be stripped from
/// documentation but used in example code. `code` is the portion of
/// `s` that should be used in tests. (None for lines that should be
/// left as-is.)
fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
/// Controls whether a line will be hidden or shown in HTML output.
///
/// All lines are used in documentation tests.
enum Line<'a> {
Hidden(&'a str),
Shown(&'a str),
}

impl<'a> Line<'a> {
fn for_html(self) -> Option<&'a str> {
match self {
Line::Shown(l) => Some(l),
Line::Hidden(_) => None,
}
}

fn for_code(self) -> &'a str {
match self {
Line::Shown(l) |
Line::Hidden(l) => l,
}
}
}

// FIXME: There is a minor inconsistency here. For lines that start with ##, we
// have no easy way of removing a potential single space after the hashes, which
// is done in the single # case. This inconsistency seems okay, if non-ideal. In
// order to fix it we'd have to iterate to find the first non-# character, and
// then reallocate to remove it; which would make us return a String.
fn map_line(s: &str) -> Line {
let trimmed = s.trim();
if trimmed == "#" {
Some("")
if trimmed.starts_with("##") {
Line::Shown(&trimmed[1..])
} else if trimmed.starts_with("# ") {
Some(&trimmed[2..])
// # text
Line::Hidden(&trimmed[2..])
} else if trimmed == "#" {
// We cannot handle '#text' because it could be #[attr].
Line::Hidden("")
} else {
None
Line::Shown(s)
}
}

Expand Down Expand Up @@ -148,9 +177,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
_ => {}
}
}
let lines = origtext.lines().filter(|l| {
stripped_filtered_line(*l).is_none()
});
let lines = origtext.lines().filter_map(|l| map_line(l).for_html());
let text = lines.collect::<Vec<&str>>().join("\n");
PLAYGROUND.with(|play| {
// insert newline to clearly separate it from the
Expand All @@ -160,9 +187,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
if url.is_empty() {
return None;
}
let test = origtext.lines().map(|l| {
stripped_filtered_line(l).unwrap_or(l)
}).collect::<Vec<&str>>().join("\n");
let test = origtext.lines()
.map(|l| map_line(l).for_code())
.collect::<Vec<&str>>().join("\n");
let krate = krate.as_ref().map(|s| &**s);
let test = test::maketest(&test, krate, false,
&Default::default());
Expand Down Expand Up @@ -543,9 +570,7 @@ pub fn render(w: &mut fmt::Formatter,
}
};

let lines = origtext.lines().filter(|l| {
stripped_filtered_line(*l).is_none()
});
let lines = origtext.lines().filter_map(|l| map_line(l).for_html());
let text = lines.collect::<Vec<&str>>().join("\n");
if rendered { return }
PLAYGROUND.with(|play| {
Expand All @@ -556,9 +581,9 @@ pub fn render(w: &mut fmt::Formatter,
if url.is_empty() {
return None;
}
let test = origtext.lines().map(|l| {
stripped_filtered_line(l).unwrap_or(l)
}).collect::<Vec<&str>>().join("\n");
let test = origtext.lines()
.map(|l| map_line(l).for_code())
.collect::<Vec<&str>>().join("\n");
let krate = krate.as_ref().map(|s| &**s);
let test = test::maketest(&test, krate, false,
&Default::default());
Expand Down Expand Up @@ -734,9 +759,7 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position
let opaque = (*data).opaque as *mut hoedown_html_renderer_state;
let tests = &mut *((*opaque).opaque as *mut ::test::Collector);
let text = str::from_utf8(text).unwrap();
let lines = text.lines().map(|l| {
stripped_filtered_line(l).unwrap_or(l)
});
let lines = text.lines().map(|l| map_line(l).for_code());
let text = lines.collect::<Vec<&str>>().join("\n");
let filename = tests.get_filename();

Expand Down Expand Up @@ -827,9 +850,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Sp
}
}
let offset = offset.unwrap_or(0);
let lines = test_s.lines().map(|l| {
stripped_filtered_line(l).unwrap_or(l)
});
let lines = test_s.lines().map(|l| map_line(l).for_code());
let text = lines.collect::<Vec<&str>>().join("\n");
nb_lines += doc[prev_offset..offset].lines().count();
let line = tests.get_line() + (nb_lines - 1);
Expand Down
25 changes: 25 additions & 0 deletions src/test/rustdoc/issue-41783.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// @has issue_41783/struct.Foo.html
// @!has - 'space'
// @!has - 'comment'
// @has - '# <span class="ident">single'
// @has - '#<span class="attribute"># <span class="ident">double</span>'
// @has - '#<span class="attribute">#<span class="attribute"># <span class="ident">triple</span>'

/// ```no_run
/// # # space
/// # comment
/// ## single
/// ### double
/// #### triple
/// ```
pub struct Foo;