]> git.proxmox.com Git - rustc.git/blame - src/vendor/pulldown-cmark-0.0.14/src/main.rs
New upstream version 1.22.1+dfsg1
[rustc.git] / src / vendor / pulldown-cmark-0.0.14 / src / main.rs
CommitLineData
ea8adc8c
XL
1// Copyright 2015 Google Inc. All rights reserved.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19// THE SOFTWARE.
20
21//! Command line tool to exercise pulldown-cmark.
22
23extern crate getopts;
24
25extern crate pulldown_cmark;
26
27use pulldown_cmark::Parser;
28use pulldown_cmark::{Options, OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};
29use pulldown_cmark::html;
30
31use std::env;
32use std::io;
33use std::io::{Read, Write};
34use std::path::Path;
35use std::fs::File;
36
37fn render_html(text: &str, opts: Options) -> String {
38 let mut s = String::with_capacity(text.len() * 3 / 2);
39 let p = Parser::new_ext(text, opts);
40 html::push_html(&mut s, p);
41 s
42}
43
44fn dry_run(text:&str, opts: Options) {
45 let p = Parser::new_ext(text, opts);
46 /*
47 let events = p.collect::<Vec<_>>();
48 let count = events.len();
49 */
50 let count = p.count();
51 println!("{} events", count);
52}
53
54fn print_events(text: &str, opts: Options) {
55 let mut p = Parser::new_ext(text, opts);
56 loop {
57 print!("{}: ", p.get_offset());
58 if let Some(event) = p.next() {
59 println!("{:?}", event);
60 } else {
61 break;
62 }
63 }
64 println!("EOF");
65}
66
67fn read_file(filename: &str) -> String {
68 let path = Path::new(filename);
69 let mut file = match File::open(&path) {
70 Err(why) => panic!("couldn't open {}: {}", path.display(), why),
71 Ok(file) => file
72 };
73 let mut s = String::new();
74 match file.read_to_string(&mut s) {
75 Err(why) => panic!("couldn't open {}: {}", path.display(), why),
76 Ok(_) => s
77 }
78}
79
80// Tests in the spec (v0.26) are of the form:
81//
82// ```````````````````````````````` example
83// <markdown input>
84// .
85// <expected output>
86// ````````````````````````````````
87struct Spec<'a> {
88 spec: &'a str,
89 test_n: usize,
90}
91
92impl<'a> Spec<'a> {
93 pub fn new(spec: &'a str) -> Self {
94 Spec{ spec: spec, test_n: 0 }
95 }
96}
97
98struct TestCase<'a> {
99 n: usize,
100 input: &'a str,
101 expected: &'a str,
102}
103
104impl<'a> TestCase<'a> {
105 pub fn new(n: usize, input: &'a str, expected: &'a str) -> Self {
106 TestCase { n: n, input: input, expected: expected }
107 }
108}
109
110impl<'a> Iterator for Spec<'a> {
111 type Item = TestCase<'a>;
112
113 fn next(&mut self) -> Option<TestCase<'a>> {
114 let spec = self.spec;
115
116 let i_start = match self.spec.find("```````````````````````````````` example\n").map(|pos| pos + 41) {
117 Some(pos) => pos,
118 None => return None,
119 };
120
121 let i_end = match self.spec[i_start..].find("\n.\n").map(|pos| pos + i_start){
122 Some(pos) => pos,
123 None => return None,
124 };
125
126 let e_end = match self.spec[i_end + 3..].find("````````````````````````````````\n").map(|pos| pos + i_end + 3){
127 Some(pos) => pos,
128 None => return None,
129 };
130
131 self.test_n += 1;
132 self.spec = &self.spec[e_end + 33 ..];
133
134 Some(TestCase::new(self.test_n, &spec[i_start .. i_end], &spec[i_end + 3 .. e_end]))
135 }
136}
137
138
139fn run_spec(spec_text: &str, args: &[String], opts: Options) {
140 //println!("spec length={}, args={:?}", spec_text.len(), args);
141 let (first, last) = if args.is_empty() {
142 (None, None)
143 } else {
144 let mut iter = args[0].split("..");
145 let first = iter.next().and_then(|s| s.parse().ok());
146 let last = match iter.next() {
147 Some(s) => s.parse().ok(),
148 None => first
149 };
150 (first, last)
151 };
152
153 let spec = Spec::new(spec_text);
154 let mut tests_failed = 0;
155 let mut tests_run = 0;
156 let mut line_count = 0;
157
158 for test in spec {
159 if first.map(|fst| test.n < fst).unwrap_or(false) { continue }
160 if last.map(|lst| test.n > lst).unwrap_or(false) { break }
161
162 if tests_run == 0 || line_count == 0 || (test.n % 10 == 0) {
163 if line_count > 30 {
164 println!("");
165 line_count = 0;
166 } else if line_count > 0 {
167 print!(" ");
168 }
169 print!("[{:3}]", test.n);
170 } else if line_count > 0 && (test.n % 10) == 5 {
171 print!(" ");
172 }
173
174 let our_html = render_html(&test.input.replace("→", "\t").replace("\n", "\r\n"), opts);
175
176 if our_html == test.expected.replace("→", "\t") {
177 print!(".");
178 } else {
179 if tests_failed == 0 {
180 print!("FAIL {}:\n\n---input---\n{}\n\n---wanted---\n{}\n\n---got---\n{}\n",
181 test.n, test.input, test.expected, our_html);
182 } else {
183 print!("X");
184 }
185 tests_failed += 1;
186 }
187
188 let _ = io::stdout().flush();
189 tests_run += 1;
190 line_count += 1;
191 }
192
193 println!("\n{}/{} tests passed", tests_run - tests_failed, tests_run)
194}
195
196fn brief<ProgramName>(program: ProgramName) -> String
197 where ProgramName: std::fmt::Display {
198 return format!("Usage: {} FILE [options]", program);
199}
200
201pub fn main() {
202 let args: Vec<_> = env::args().collect();
203 let mut opts = getopts::Options::new();
204 opts.optflag("h", "help", "this help message");
205 opts.optflag("d", "dry-run", "dry run, produce no output");
206 opts.optflag("e", "events", "print event sequence instead of rendering");
207 opts.optflag("T", "enable-tables", "enable GitHub-style tables");
208 opts.optflag("F", "enable-footnotes", "enable Hoedown-style footnotes");
209 opts.optopt("s", "spec", "run tests from spec file", "FILE");
210 opts.optopt("b", "bench", "run benchmark", "FILE");
211 let matches = match opts.parse(&args[1..]) {
212 Ok(m) => m,
213 Err(f) => {
214 let message = format!("{}\n{}\n",
215 f.to_string(),
216 opts.usage(&brief(&args[0])));
217 if let Err(err) = write!(std::io::stderr(), "{}", message) {
218 panic!("Failed to write to standard error: {}\n\
219 Error encountered while trying to log the \
220 following message: \"{}\"",
221 err,
222 message);
223 }
224 std::process::exit(1);
225 }
226 };
227 if matches.opt_present("help") {
228 println!("{}", opts.usage(&brief(&args[0])));
229 return;
230 }
231 let mut opts = Options::empty();
232 if matches.opt_present("enable-tables") {
233 opts.insert(OPTION_ENABLE_TABLES);
234 }
235 if matches.opt_present("enable-footnotes") {
236 opts.insert(OPTION_ENABLE_FOOTNOTES);
237 }
238 if let Some(filename) = matches.opt_str("spec") {
239 run_spec(&read_file(&filename), &matches.free, opts);
240 } else if let Some(filename) = matches.opt_str("bench") {
241 let inp = read_file(&filename);
242 for _ in 0..1000 {
243 let _ = render_html(&inp, opts);
244 }
245 } else {
246 let mut input = String::new();
247 if let Err(why) = io::stdin().read_to_string(&mut input) {
248 panic!("couldn't read from stdin: {}", why)
249 }
250 if matches.opt_present("events") {
251 print_events(&input, opts);
252 } else if matches.opt_present("dry-run") {
253 dry_run(&input, opts);
254 } else {
255 print!("{}", render_html(&input, opts));
256 }
257 }
258}