diff --git a/src/doc/style/errors/ergonomics.md b/src/doc/style/errors/ergonomics.md index 0985475f56a9a..a404d25bf3703 100644 --- a/src/doc/style/errors/ergonomics.md +++ b/src/doc/style/errors/ergonomics.md @@ -57,7 +57,7 @@ fn write_info(info: &Info) -> Result<(), IoError> { ``` See -[the `result` module documentation](https://doc.rust-lang.org/stable/std/result/index.html#the-try!-macro) +[the `result` module documentation](https://doc.rust-lang.org/stable/std/result/index.html#the-try-macro) for more details. ### The `Result`-`impl` pattern [FIXME] diff --git a/src/doc/style/features/traits/generics.md b/src/doc/style/features/traits/generics.md index 2d9356fc42d1d..26ffda50ac53d 100644 --- a/src/doc/style/features/traits/generics.md +++ b/src/doc/style/features/traits/generics.md @@ -27,7 +27,7 @@ explicitly implement to be used by this generic function. * _Inference_. Since the type parameters to generic functions can usually be inferred, generic functions can help cut down on verbosity in code where explicit conversions or other method calls would usually be necessary. See the - [overloading/implicits use case](#use-case:-limited-overloading-and/or-implicit-conversions) + [overloading/implicits use case](#use-case-limited-overloading-andor-implicit-conversions) below. * _Precise types_. Because generics give a _name_ to the specific type implementing a trait, it is possible to be precise about places where that @@ -51,7 +51,7 @@ explicitly implement to be used by this generic function. a `Vec` contains elements of a single concrete type (and, indeed, the vector representation is specialized to lay these out in line). Sometimes heterogeneous collections are useful; see - [trait objects](#use-case:-trait-objects) below. + [trait objects](#use-case-trait-objects) below. * _Signature verbosity_. Heavy use of generics can bloat function signatures. **[Ed. note]** This problem may be mitigated by some language improvements; stay tuned. diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index 18ce93ea06a64..47d41a155e4ca 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -24,28 +24,28 @@ systems may want to jump around. * [The Basics](#the-basics) * [Unwrapping explained](#unwrapping-explained) * [The `Option` type](#the-option-type) - * [Composing `Option` values](#composing-option-values) + * [Composing `Option` values](#composing-optiont-values) * [The `Result` type](#the-result-type) * [Parsing integers](#parsing-integers) * [The `Result` type alias idiom](#the-result-type-alias-idiom) - * [A brief interlude: unwrapping isn't evil](#a-brief-interlude:-unwrapping-isn't-evil) + * [A brief interlude: unwrapping isn't evil](#a-brief-interlude-unwrapping-isn't-evil) * [Working with multiple error types](#working-with-multiple-error-types) * [Composing `Option` and `Result`](#composing-option-and-result) * [The limits of combinators](#the-limits-of-combinators) * [Early returns](#early-returns) - * [The `try!` macro](#the-try!-macro) + * [The `try!` macro](#the-try-macro) * [Defining your own error type](#defining-your-own-error-type) * [Standard library traits used for error handling](#standard-library-traits-used-for-error-handling) * [The `Error` trait](#the-error-trait) * [The `From` trait](#the-from-trait) - * [The real `try!` macro](#the-real-try!-macro) + * [The real `try!` macro](#the-real-try-macro) * [Composing custom error types](#composing-custom-error-types) * [Advice for library writers](#advice-for-library-writers) -* [Case study: A program to read population data](#case-study:-a-program-to-read-population-data) +* [Case study: A program to read population data](#case-study-a-program-to-read-population-data) * [Initial setup](#initial-setup) * [Argument parsing](#argument-parsing) * [Writing the logic](#writing-the-logic) - * [Error handling with `Box`](#error-handling-with-box%3Cerror%3E) + * [Error handling with `Box`](#error-handling-with-boxerror) * [Reading from stdin](#reading-from-stdin) * [Error handling with a custom type](#error-handling-with-a-custom-type) * [Adding functionality](#adding-functionality) @@ -87,7 +87,7 @@ thread '
' panicked at 'Invalid number: 11', src/bin/panic-simple.rs:5 Here's another example that is slightly less contrived. A program that accepts an integer as an argument, doubles it and prints it. - + ```rust,should_panic use std::env; @@ -139,7 +139,7 @@ system is an important concept because it will cause the compiler to force the programmer to handle that absence. Let's take a look at an example that tries to find a character in a string: - + ```rust // Searches `haystack` for the Unicode character `needle`. If one is found, the @@ -186,7 +186,7 @@ But wait, what about `unwrap` used in [`unwrap-double`](#code-unwrap-double)? There was no case analysis there! Instead, the case analysis was put inside the `unwrap` method for you. You could define it yourself if you want: - + ```rust enum Option { @@ -253,7 +253,7 @@ option is `None`, in which case, just return `None`. Rust has parametric polymorphism, so it is very easy to define a combinator that abstracts this pattern: - + ```rust fn map(option: Option, f: F) -> Option where F: FnOnce(T) -> A { @@ -394,7 +394,7 @@ remove choices because they will panic if `Option` is `None`. The `Result` type is also [defined in the standard library][6]: - + ```rust enum Result { @@ -562,7 +562,7 @@ combinators that affect only the error type, such as ### The `Result` type alias idiom In the standard library, you may frequently see types like -`Result`. But wait, [we defined `Result`](#code-result-def-1) to +`Result`. But wait, [we defined `Result`](#code-result-def) to have two type parameters. How can we get away with only specifying one? The key is to define a `Result` type alias that *fixes* one of the type parameters to a particular type. Usually the fixed type is @@ -672,7 +672,7 @@ with both an `Option` and a `Result`, the solution is *usually* to convert the (from `env::args()`) means the user didn't invoke the program correctly. We could just use a `String` to describe the error. Let's try: - + ```rust use std::env; @@ -906,7 +906,7 @@ seen above. Here is a simplified definition of a `try!` macro: - + ```rust macro_rules! try { @@ -1168,7 +1168,7 @@ The `std::convert::From` trait is [defined in the standard library](../std/convert/trait.From.html): - + ```rust trait From { @@ -1250,7 +1250,7 @@ macro_rules! try { This is not its real definition. Its real definition is [in the standard library](../std/macro.try!.html): - + ```rust macro_rules! try { @@ -1515,7 +1515,7 @@ and [`rustc-serialize`](https://crates.io/crates/rustc-serialize) crates. We're not going to spend a lot of time on setting up a project with Cargo because it is already covered well in [the Cargo -chapter](../book/hello-cargo) and [Cargo's documentation][14]. +chapter](../book/hello-cargo.html) and [Cargo's documentation][14]. To get started from scratch, run `cargo new --bin city-pop` and make sure your `Cargo.toml` looks something like this: @@ -1573,7 +1573,7 @@ fn main() { let mut opts = Options::new(); opts.optflag("h", "help", "Show this usage message."); - + let matches = match opts.parse(&args[1..]) { Ok(m) => { m } Err(e) => { panic!(e.to_string()) } @@ -1584,7 +1584,7 @@ fn main() { } let data_path = args[1].clone(); let city = args[2].clone(); - + // Do stuff with information } ``` @@ -1647,27 +1647,27 @@ fn main() { let mut opts = Options::new(); opts.optflag("h", "help", "Show this usage message."); - + let matches = match opts.parse(&args[1..]) { Ok(m) => { m } Err(e) => { panic!(e.to_string()) } }; - + if matches.opt_present("h") { print_usage(&program, opts); return; } - + let data_file = args[1].clone(); let data_path = Path::new(&data_file); let city = args[2].clone(); - + let file = fs::File::open(data_path).unwrap(); let mut rdr = csv::Reader::from_reader(file); - + for row in rdr.decode::() { let row = row.unwrap(); - + if row.city == city { println!("{}, {}: {:?}", row.city, row.country, @@ -1773,7 +1773,7 @@ fn main() { print_usage(&program, opts); return; } - + let data_file = args[1].clone(); let data_path = Path::new(&data_file); let city = args[2].clone(); @@ -1882,7 +1882,7 @@ opts.optflag("h", "help", "Show this usage message."); ... let file = matches.opt_str("f"); let data_file = file.as_ref().map(Path::new); - + let city = if !matches.free.is_empty() { matches.free[0].clone() } else { diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index c98a54e451475..f68e82501e91e 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -207,9 +207,7 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> { /// /// Any leading or trailing whitespace will be trimmed. fn collapse_whitespace(s: &str) -> String { - s.split(|c: char| c.is_whitespace()).filter(|s| { - !s.is_empty() - }).collect::>().join(" ") + s.split_whitespace().collect::>().join(" ") } thread_local!(static USED_HEADER_MAP: RefCell> = { @@ -277,25 +275,44 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { // Extract the text provided let s = if text.is_null() { - "".to_string() + "".to_owned() } else { let s = unsafe { (*text).as_bytes() }; - str::from_utf8(s).unwrap().to_string() + str::from_utf8(&s).unwrap().to_owned() }; - // Transform the contents of the header into a hyphenated string - let id = s.split_whitespace().map(|s| s.to_ascii_lowercase()) - .collect::>().join("-"); - + // Discard '', '' tags and some escaped characters, + // transform the contents of the header into a hyphenated string + // without non-alphanumeric characters other than '-' and '_'. + // // This is a terrible hack working around how hoedown gives us rendered // html for text rather than the raw text. + let mut id = s.clone(); + let repl_sub = vec!["", "", "", "", + "", "", + "<", ">", "&", "'", """]; + for sub in repl_sub { + id = id.replace(sub, ""); + } + let id = id.chars().filter_map(|c| { + if c.is_alphanumeric() || c == '-' || c == '_' { + if c.is_ascii() { + Some(c.to_ascii_lowercase()) + } else { + Some(c) + } + } else if c.is_whitespace() && c.is_ascii() { + Some('-') + } else { + None + } + }).collect::(); let opaque = unsafe { (*data).opaque as *mut hoedown_html_renderer_state }; let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) }; // Make sure our hyphenated ID is unique for this page let id = USED_HEADER_MAP.with(|map| { - let id = id.replace("", "").replace("", "").to_string(); let id = match map.borrow_mut().get_mut(&id) { None => id, Some(a) => { *a += 1; format!("{}-{}", id, *a - 1) } @@ -304,22 +321,15 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { id }); - let sec = match opaque.toc_builder { - Some(ref mut builder) => { - builder.push(level as u32, s.clone(), id.clone()) - } - None => {""} - }; + + let sec = opaque.toc_builder.as_mut().map_or("".to_owned(), |builder| { + format!("{} ", builder.push(level as u32, s.clone(), id.clone())) + }); // Render the HTML - let text = format!(r##"{sec}{}"##, - s, lvl = level, id = id, - sec = if sec.is_empty() { - sec.to_string() - } else { - format!("{} ", sec) - }); + let text = format!("\ + {sec}{}", + s, lvl = level, id = id, sec = sec); let text = CString::new(text).unwrap(); unsafe { hoedown_buffer_puts(ob, text.as_ptr()) } @@ -333,7 +343,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { _: *const hoedown_renderer_data, ) -> libc::c_int { let content = if text.is_null() { - "".to_string() + "".to_owned() } else { let bytes = unsafe { (*text).as_bytes() }; let s = str::from_utf8(bytes).unwrap(); @@ -367,10 +377,9 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { hoedown_html_renderer_free(renderer); - let mut ret = match opaque.toc_builder { - Some(b) => write!(w, "", b.into_toc()), - None => Ok(()) - }; + let mut ret = opaque.toc_builder.map_or(Ok(()), |builder| { + write!(w, "", builder.into_toc()) + }); if ret.is_ok() { let buf = (*ob).as_bytes(); @@ -404,7 +413,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { stripped_filtered_line(l).unwrap_or(l) }); let text = lines.collect::>().join("\n"); - tests.add_test(text.to_string(), + tests.add_test(text.to_owned(), block_info.should_panic, block_info.no_run, block_info.ignore, block_info.test_harness); } @@ -560,10 +569,7 @@ pub fn plain_summary_line(md: &str) -> String { md.len() as libc::size_t); hoedown_document_free(document); let plain_slice = (*ob).as_bytes(); - let plain = match str::from_utf8(plain_slice) { - Ok(s) => s.to_string(), - Err(_) => "".to_string(), - }; + let plain = str::from_utf8(plain_slice).unwrap_or("").to_owned(); hoedown_buffer_free(ob); plain } @@ -572,7 +578,7 @@ pub fn plain_summary_line(md: &str) -> String { #[cfg(test)] mod tests { use super::{LangString, Markdown}; - use super::{collapse_whitespace, plain_summary_line}; + use super::plain_summary_line; #[test] fn test_lang_string_parse() { @@ -607,6 +613,27 @@ mod tests { format!("{}", Markdown(markdown)); } + #[test] + fn test_header() { + fn t(input: &str, expect: &str) { + let output = format!("{}", Markdown(input)); + assert_eq!(output, expect); + } + + t("# Foo bar", "\n

\ + Foo bar

"); + t("## Foo-bar_baz qux", "\n

Foo-bar_baz qux

"); + t("### **Foo** *bar* baz!?!& -_qux_-%", + "\n

\ + Foo \ + bar baz!?!& -_qux_-%

"); + t("####**Foo?** & \\*bar?!* _`baz`_ ❤ #qux", + "\n

\ + Foo? & *bar?!* \ + baz ❤ #qux

"); + } + #[test] fn test_plain_summary_line() { fn t(input: &str, expect: &str) { @@ -620,18 +647,4 @@ mod tests { t("# top header", "top header"); t("## header", "header"); } - - #[test] - fn test_collapse_whitespace() { - fn t(input: &str, expected: &str) { - let actual = collapse_whitespace(input); - assert_eq!(actual, expected); - } - - t("foo", "foo"); - t("foo bar baz", "foo bar baz"); - t(" foo bar", "foo bar"); - t("\tfoo bar\nbaz", "foo bar baz"); - t("foo bar \n baz\t\tqux\n", "foo bar baz qux"); - } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 774d13966bd6b..c67a4182f54cb 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -18,7 +18,7 @@ //! language primitives](#primitives), [standard macros](#macros), //! [I/O](io/index.html) and [multithreading](thread/index.html), among //! [many other -//! things](#what-is-in-the-standard-library-documentation?). +//! things](#what-is-in-the-standard-library-documentation). //! //! `std` is available to all Rust crates by default, just as if each //! one contained an `extern crate std` import at the [crate