]>
git.proxmox.com Git - rustc.git/blob - src/doc/book/2018-edition/tools/src/bin/link2print.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 // FIXME: We have some long lines that could be refactored, but it's not a big deal.
13 // ignore-tidy-linelength
17 use std
:: collections
:: HashMap
;
19 use std
:: io
:: {Read, Write}
;
20 use regex
:: {Regex, Captures}
;
24 write_md ( parse_links ( parse_references ( read_md ())));
27 fn read_md () -> String
{
28 let mut buffer
= String
:: new ();
29 match io
:: stdin (). read_to_string (& mut buffer
) {
31 Err ( error
) => panic
!( error
),
35 fn write_md ( output
: String
) {
36 write
!( io
:: stdout (), " {} " , output
). unwrap ();
39 fn parse_references ( buffer
: String
) -> ( String
, HashMap
< String
, String
>) {
40 let mut ref_map
= HashMap
:: new ();
41 // FIXME: Currently doesn't handle "title" in following line
42 let re
= Regex
:: new ( r
### "(?m) \n ?^ {0,3} \ [([^]]+) \ ]:[[:blank:]]*(.*)$" ###).unwrap();
43 let output
= re
. replace_all (& buffer
, | caps
: & Captures
| {
44 let key
= caps
. at ( 1 ). unwrap (). to_owned (). to_uppercase ();
45 let val
= caps
. at ( 2 ). unwrap (). to_owned ();
46 if ref_map
. insert ( key
, val
). is_some () {
47 panic
!( "Did not expect markdown page to have duplicate reference" );
54 fn parse_links (( buffer
, ref_map
): ( String
, HashMap
< String
, String
>)) -> String
{
55 // FIXME: check which punctuation is allowed by spec
56 let re
= Regex
:: new ( r
### "(?:(?P<pre>(?:```(?:[^`]|`[^`])*`? \n ``` \n )|(?:[^[]`[^` \n ]+[ \n ]?[^` \n ]*`))|(?: \ [(?P<name>[^]]+) \ ](?:(?: \ ([[:blank:]]*(?P<val>[^" )]*[^ ])(?:[[:blank:]]* "[^" ]* ")? \ ))|(?: \ [(?P<key>[^]]*) \ ]))?))" ###).expect( "could not create regex" );
57 let error_code
= Regex
:: new ( r
### "^E \ d {4} $" ###).expect( "could not create regex" );
58 let output
= re
. replace_all (& buffer
, | caps
: & Captures
| {
59 match caps
. name ( "pre" ) {
60 Some ( pre_section
) => format
!( " {} " , pre_section
. to_owned ()),
62 let name
= caps
. name ( "name" ). expect ( "could not get name" ). to_owned ();
63 // Really we should ignore text inside code blocks,
64 // this is a hack to not try to treat `#[derive()]`,
65 // `[profile]`, `[test]`, or `[E\d\d\d\d]` like a link
66 if name
. starts_with ( "derive(" ) ||
67 name
. starts_with ( "profile" ) ||
68 name
. starts_with ( "test" ) ||
69 error_code
. is_match (& name
) {
73 let val
= match caps
. name ( "val" ) {
75 Some ( value
) => value
. to_owned (),
77 match caps
. name ( "key" ) {
81 "" => format
!( " {} " , ref_map
. get (& name
. to_uppercase ()). expect (& format
!( "could not find url for the link text ` {} `" , name
))),
83 _
=> format
!( " {} " , ref_map
. get (& key
. to_uppercase ()). expect (& format
!( "could not find url for the link text ` {} `" , key
))),
86 // [name] as reference
87 None
=> format
!( " {} " , ref_map
. get (& name
. to_uppercase ()). expect (& format
!( "could not find url for the link text ` {} `" , name
))),
91 format
!( " {} at * {} *" , name
, val
)
100 fn parse ( source
: String
) -> String
{
101 super :: parse_links ( super :: parse_references ( source
))
105 fn parses_inline_link () {
106 let source
= r
"This is a [link](http://google.com) that should be expanded" . to_string ();
107 let target
= r
"This is a link at *http://google.com* that should be expanded" . to_string ();
108 assert_eq
!( parse ( source
), target
);
112 fn parses_multiline_links () {
113 let source
= r
"This is a [link](http://google.com) that
114 should appear expanded. Another [location](/here/) and [another](http://gogogo)"
116 let target
= r
"This is a link at *http://google.com* that
117 should appear expanded. Another location at */here/* and another at *http://gogogo*"
119 assert_eq
!( parse ( source
), target
);
123 fn parses_reference () {
124 let source
= r
"This is a [link][theref].
125 [theref]: http://example.com/foo
128 let target
= r
"This is a link at *http://example.com/foo*.
131 assert_eq
!( parse ( source
), target
);
135 fn parses_implicit_link () {
136 let source
= r
"This is an [implicit][] link.
137 [implicit]: /The Link/"
139 let target
= r
"This is an implicit at */The Link/* link." . to_string ();
140 assert_eq
!( parse ( source
), target
);
143 fn parses_refs_with_one_space_indentation () {
144 let source
= r
"This is a [link][ref]
147 let target
= r
"This is a link at *The link*" . to_string ();
148 assert_eq
!( parse ( source
), target
);
152 fn parses_refs_with_two_space_indentation () {
153 let source
= r
"This is a [link][ref]
156 let target
= r
"This is a link at *The link*" . to_string ();
157 assert_eq
!( parse ( source
), target
);
161 fn parses_refs_with_three_space_indentation () {
162 let source
= r
"This is a [link][ref]
165 let target
= r
"This is a link at *The link*" . to_string ();
166 assert_eq
!( parse ( source
), target
);
171 fn rejects_refs_with_four_space_indentation () {
172 let source
= r
"This is a [link][ref]
175 let target
= r
"This is a link at *The link*" . to_string ();
176 assert_eq
!( parse ( source
), target
);
180 fn ignores_optional_inline_title () {
181 let source
= r
### "This is a titled [link](http://example.com " My title ")." ###.to_string();
182 let target
= r
"This is a titled link at *http://example.com*." . to_string ();
183 assert_eq
!( parse ( source
), target
);
187 fn parses_title_with_puctuation () {
188 let source
= r
### "[link](http://example.com " It's Title ")" ###.to_string();
189 let target
= r
"link at *http://example.com*" . to_string ();
190 assert_eq
!( parse ( source
), target
);
194 fn parses_name_with_punctuation () {
195 let source
= r
### "[I'm here](there)" ###.to_string();
196 let target
= r
### "I'm here at *there*" ###.to_string();
197 assert_eq
!( parse ( source
), target
);
200 fn parses_name_with_utf8 () {
201 let source
= r
### "[user’s forum](the user’s forum)" ###.to_string();
202 let target
= r
### "user’s forum at *the user’s forum*" ###.to_string();
203 assert_eq
!( parse ( source
), target
);
208 fn parses_reference_with_punctuation () {
209 let source
= r
### "[link][the ref-ref]
210 [the ref-ref]:http://example.com/ref-ref" ###
212 let target
= r
### "link at *http://example.com/ref-ref*" ###.to_string();
213 assert_eq
!( parse ( source
), target
);
217 fn parses_reference_case_insensitively () {
218 let source
= r
"[link][Ref]
219 [ref]: The reference"
221 let target
= r
"link at *The reference*" . to_string ();
222 assert_eq
!( parse ( source
), target
);
225 fn parses_link_as_reference_when_reference_is_empty () {
226 let source
= r
"[link as reference][]
227 [link as reference]: the actual reference"
229 let target
= r
"link as reference at *the actual reference*" . to_string ();
230 assert_eq
!( parse ( source
), target
);
234 fn parses_link_without_reference_as_reference () {
235 let source
= r
"[link] is alone
236 [link]: The contents"
238 let target
= r
"link at *The contents* is alone" . to_string ();
239 assert_eq
!( parse ( source
), target
);
244 fn parses_link_without_reference_as_reference_with_asterisks () {
245 let source
= r
"*[link]* is alone
246 [link]: The contents"
248 let target
= r
"*link* at *The contents* is alone" . to_string ();
249 assert_eq
!( parse ( source
), target
);
252 fn ignores_links_in_pre_sections () {
253 let source
= r
### "```toml
257 authors = [" Your Name <you@example.com> "]
263 let target
= source
. clone ();
264 assert_eq
!( parse ( source
), target
);
268 fn ignores_links_in_quoted_sections () {
269 let source
= r
### "do not change `[package]`." ###.to_string();
270 let target
= source
. clone ();
271 assert_eq
!( parse ( source
), target
);
274 fn ignores_links_in_quoted_sections_containing_newlines () {
275 let source
= r
"do not change `this [package]
276 is still here` [link](ref)"
278 let target
= r
"do not change `this [package]
279 is still here` link at *ref*"
281 assert_eq
!( parse ( source
), target
);
285 fn ignores_links_in_pre_sections_while_still_handling_links () {
286 let source
= r
### "```toml
290 authors = [" Your Name <you@example.com> "]
296 [link]: http://gohere
299 let target
= r
### "```toml
303 authors = [" Your Name <you@example.com> "]
307 Another link at *http://gohere*
311 assert_eq
!( parse ( source
), target
);
314 fn ignores_quotes_in_pre_sections () {
315 let source
= r
### "```bash
317 Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
318 src/main.rs:23:21: 23:35 error: mismatched types [E0308]
319 src/main.rs:23 match guess.cmp(&secret_number) {
321 src/main.rs:23:21: 23:35 help: run `rustc --explain E0308` to see a detailed explanation
322 src/main.rs:23:21: 23:35 note: expected type `&std::string::String`
323 src/main.rs:23:21: 23:35 note: found type `&_`
324 error: aborting due to previous error
325 Could not compile `guessing_game`.
329 let target
= source
. clone ();
330 assert_eq
!( parse ( source
), target
);
333 fn ignores_short_quotes () {
334 let source
= r
"to `1` at index `[0]` i" . to_string ();
335 let target
= source
. clone ();
336 assert_eq
!( parse ( source
), target
);
339 fn ignores_pre_sections_with_final_quote () {
340 let source
= r
### "```bash
342 Compiling points v0.1.0 (file:///projects/points)
343 error: the trait bound `Point: std::fmt::Display` is not satisfied [--explain E0277]
345 8 |> println!(" Point 1: {} ", p1);
347 <std macros>:2:27: 2:58: note: in this expansion of format_args!
348 <std macros>:3:1: 3:54: note: in this expansion of print! (defined in <std macros>)
349 src/main.rs:8:5: 8:33: note: in this expansion of println! (defined in <std macros>)
350 note: `Point` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
351 note: required by `std::fmt::Display::fmt`
353 `here` is another [link](the ref)
355 let target
= r
### "```bash
357 Compiling points v0.1.0 (file:///projects/points)
358 error: the trait bound `Point: std::fmt::Display` is not satisfied [--explain E0277]
360 8 |> println!(" Point 1: {} ", p1);
362 <std macros>:2:27: 2:58: note: in this expansion of format_args!
363 <std macros>:3:1: 3:54: note: in this expansion of print! (defined in <std macros>)
364 src/main.rs:8:5: 8:33: note: in this expansion of println! (defined in <std macros>)
365 note: `Point` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
366 note: required by `std::fmt::Display::fmt`
368 `here` is another link at *the ref*
370 assert_eq
!( parse ( source
), target
);
373 fn parses_adam_p_cheatsheet () {
374 let source
= r
### "[I'm an inline-style link](https://www.google.com)
376 [I'm an inline-style link with title](https://www.google.com " Google's Homepage ")
378 [I'm a reference-style link][Arbitrary case-insensitive reference text]
380 [I'm a relative reference to a repository file](../blob/master/LICENSE)
382 [You can use numbers for reference-style link definitions][1]
384 Or leave it empty and use the [link text itself][].
386 URLs and URLs in angle brackets will automatically get turned into links.
387 http://www.example.com or <http://www.example.com> and sometimes
388 example.com (but not on Github, for example).
390 Some text to show that the reference links can follow later.
392 [arbitrary case-insensitive reference text]: https://www.mozilla.org
393 [1]: http://slashdot.org
394 [link text itself]: http://www.reddit.com" ###
397 let target
= r
### "I'm an inline-style link at *https://www.google.com*
399 I'm an inline-style link with title at *https://www.google.com*
401 I'm a reference-style link at *https://www.mozilla.org*
403 I'm a relative reference to a repository file at *../blob/master/LICENSE*
405 You can use numbers for reference-style link definitions at *http://slashdot.org*
407 Or leave it empty and use the link text itself at *http://www.reddit.com*.
409 URLs and URLs in angle brackets will automatically get turned into links.
410 http://www.example.com or <http://www.example.com> and sometimes
411 example.com (but not on Github, for example).
413 Some text to show that the reference links can follow later.
416 assert_eq
!( parse ( source
), target
);