Name |
Date |
Size |
#Lines |
LOC |
||
---|---|---|---|---|---|---|
.. | - | - | ||||
custom_files.rs | D | 23-Nov-2023 | 6 KiB | 198 | 150 | |
peg_calculator.rs | D | 23-Nov-2023 | 2.2 KiB | 69 | 52 | |
readme_preview.rs | D | 23-Nov-2023 | 10.6 KiB | 357 | 288 | |
reusable_diagnostic.rs | D | 23-Nov-2023 | 3.4 KiB | 106 | 93 | |
term.rs | D | 23-Nov-2023 | 5.8 KiB | 176 | 146 |
readme_preview.rs
1 //! Renders the preview SVG for the README. 2 //! 3 //! To update the preview, execute the following command from the top level of 4 //! the repository: 5 //! 6 //! ```sh 7 //! cargo run --example readme_preview svg > codespan-reporting/assets/readme_preview.svg 8 //! ``` 9 10 use codespan_reporting::diagnostic::{Diagnostic, Label}; 11 use codespan_reporting::files::SimpleFile; 12 use codespan_reporting::term::termcolor::{Color, ColorSpec, StandardStream, WriteColor}; 13 use codespan_reporting::term::{self, ColorArg}; 14 use std::io::{self, Write}; 15 use structopt::StructOpt; 16 17 #[derive(Debug, StructOpt)] 18 #[structopt(name = "emit")] 19 pub enum Opts { 20 /// Render SVG output 21 Svg, 22 /// Render Stderr output 23 Stderr { 24 /// Configure coloring of output 25 #[structopt( 26 long = "color", 27 parse(try_from_str), 28 default_value = "auto", 29 possible_values = ColorArg::VARIANTS, 30 case_insensitive = true 31 )] 32 color: ColorArg, 33 }, 34 } 35 main() -> anyhow::Result<()>36fn main() -> anyhow::Result<()> { 37 let file = SimpleFile::new( 38 "FizzBuzz.fun", 39 unindent::unindent( 40 r#" 41 module FizzBuzz where 42 43 fizz₁ : Nat → String 44 fizz₁ num = case (mod num 5) (mod num 3) of 45 0 0 => "FizzBuzz" 46 0 _ => "Fizz" 47 _ 0 => "Buzz" 48 _ _ => num 49 50 fizz₂ : Nat → String 51 fizz₂ num = 52 case (mod num 5) (mod num 3) of 53 0 0 => "FizzBuzz" 54 0 _ => "Fizz" 55 _ 0 => "Buzz" 56 _ _ => num 57 "#, 58 ), 59 ); 60 61 let diagnostics = [Diagnostic::error() 62 .with_message("`case` clauses have incompatible types") 63 .with_code("E0308") 64 .with_labels(vec![ 65 Label::primary((), 328..331).with_message("expected `String`, found `Nat`"), 66 Label::secondary((), 211..331).with_message("`case` clauses have incompatible types"), 67 Label::secondary((), 258..268).with_message("this is found to be of type `String`"), 68 Label::secondary((), 284..290).with_message("this is found to be of type `String`"), 69 Label::secondary((), 306..312).with_message("this is found to be of type `String`"), 70 Label::secondary((), 186..192).with_message("expected type `String` found here"), 71 ]) 72 .with_notes(vec![unindent::unindent( 73 " 74 expected type `String` 75 found type `Nat` 76 ", 77 )])]; 78 79 // let mut files = SimpleFiles::new(); 80 match Opts::from_args() { 81 Opts::Svg => { 82 let mut buffer = Vec::new(); 83 let mut writer = HtmlEscapeWriter::new(SvgWriter::new(&mut buffer)); 84 let config = codespan_reporting::term::Config { 85 styles: codespan_reporting::term::Styles::with_blue(Color::Blue), 86 ..codespan_reporting::term::Config::default() 87 }; 88 89 for diagnostic in &diagnostics { 90 term::emit(&mut writer, &config, &file, &diagnostic)?; 91 } 92 93 let num_lines = buffer.iter().filter(|byte| **byte == b'\n').count() + 1; 94 95 let padding = 10; 96 let font_size = 12; 97 let line_spacing = 3; 98 let width = 882; 99 let height = padding + num_lines * (font_size + line_spacing) + padding; 100 101 let stdout = std::io::stdout(); 102 let writer = &mut stdout.lock(); 103 104 write!( 105 writer, 106 r#"<svg viewBox="0 0 {width} {height}" xmlns="http://www.w3.org/2000/svg"> 107 <style> 108 /* https://github.com/aaron-williamson/base16-alacritty/blob/master/colors/base16-tomorrow-night-256.yml */ 109 pre {{ 110 background: #1d1f21; 111 margin: 0; 112 padding: {padding}px; 113 border-radius: 6px; 114 color: #ffffff; 115 font: {font_size}px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace; 116 }} 117 118 pre .bold {{ font-weight: bold; }} 119 120 pre .fg.black {{ color: #1d1f21; }} 121 pre .fg.red {{ color: #cc6666; }} 122 pre .fg.green {{ color: #b5bd68; }} 123 pre .fg.yellow {{ color: #f0c674; }} 124 pre .fg.blue {{ color: #81a2be; }} 125 pre .fg.magenta {{ color: #b294bb; }} 126 pre .fg.cyan {{ color: #8abeb7; }} 127 pre .fg.white {{ color: #c5c8c6; }} 128 129 pre .fg.black.bright {{ color: #969896; }} 130 pre .fg.red.bright {{ color: #cc6666; }} 131 pre .fg.green.bright {{ color: #b5bd68; }} 132 pre .fg.yellow.bright {{ color: #f0c674; }} 133 pre .fg.blue.bright {{ color: #81a2be; }} 134 pre .fg.magenta.bright {{ color: #b294bb; }} 135 pre .fg.cyan.bright {{ color: #8abeb7; }} 136 pre .fg.white.bright {{ color: #ffffff; }} 137 138 pre .bg.black {{ background-color: #1d1f21; }} 139 pre .bg.red {{ background-color: #cc6666; }} 140 pre .bg.green {{ background-color: #b5bd68; }} 141 pre .bg.yellow {{ background-color: #f0c674; }} 142 pre .bg.blue {{ background-color: #81a2be; }} 143 pre .bg.magenta {{ background-color: #b294bb; }} 144 pre .bg.cyan {{ background-color: #8abeb7; }} 145 pre .bg.white {{ background-color: #c5c8c6; }} 146 147 pre .bg.black.bright {{ background-color: #969896; }} 148 pre .bg.red.bright {{ background-color: #cc6666; }} 149 pre .bg.green.bright {{ background-color: #b5bd68; }} 150 pre .bg.yellow.bright {{ background-color: #f0c674; }} 151 pre .bg.blue.bright {{ background-color: #81a2be; }} 152 pre .bg.magenta.bright {{ background-color: #b294bb; }} 153 pre .bg.cyan.bright {{ background-color: #8abeb7; }} 154 pre .bg.white.bright {{ background-color: #ffffff; }} 155 </style> 156 157 <foreignObject x="0" y="0" width="{width}" height="{height}"> 158 <div xmlns="http://www.w3.org/1999/xhtml"> 159 <pre>"#, 160 padding = padding, 161 font_size = font_size, 162 width = width, 163 height = height, 164 )?; 165 166 writer.write_all(&buffer)?; 167 168 write!( 169 writer, 170 "</pre> 171 </div> 172 </foreignObject> 173 </svg> 174 " 175 )?; 176 } 177 Opts::Stderr { color } => { 178 let writer = StandardStream::stderr(color.into()); 179 let config = codespan_reporting::term::Config::default(); 180 for diagnostic in &diagnostics { 181 term::emit(&mut writer.lock(), &config, &file, &diagnostic)?; 182 } 183 } 184 } 185 186 Ok(()) 187 } 188 189 /// Rudimentary HTML escaper which performs the following conversions: 190 /// 191 /// - `<` ⇒ `<` 192 /// - `>` ⇒ `>` 193 /// - `&` ⇒ `&` 194 pub struct HtmlEscapeWriter<W> { 195 upstream: W, 196 } 197 198 impl<W> HtmlEscapeWriter<W> { new(upstream: W) -> HtmlEscapeWriter<W>199 pub fn new(upstream: W) -> HtmlEscapeWriter<W> { 200 HtmlEscapeWriter { upstream } 201 } 202 } 203 204 impl<W: Write> Write for HtmlEscapeWriter<W> { write(&mut self, buf: &[u8]) -> io::Result<usize>205 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 206 let mut last_term = 0usize; 207 for (i, byte) in buf.iter().enumerate() { 208 let escape = match byte { 209 b'<' => &b"<"[..], 210 b'>' => &b">"[..], 211 b'&' => &b"&"[..], 212 _ => continue, 213 }; 214 self.upstream.write_all(&buf[last_term..i])?; 215 last_term = i + 1; 216 self.upstream.write_all(escape)?; 217 } 218 self.upstream.write_all(&buf[last_term..])?; 219 Ok(buf.len()) 220 } 221 flush(&mut self) -> io::Result<()>222 fn flush(&mut self) -> io::Result<()> { 223 self.upstream.flush() 224 } 225 } 226 227 impl<W: WriteColor> WriteColor for HtmlEscapeWriter<W> { supports_color(&self) -> bool228 fn supports_color(&self) -> bool { 229 self.upstream.supports_color() 230 } 231 set_color(&mut self, spec: &ColorSpec) -> io::Result<()>232 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { 233 self.upstream.set_color(spec) 234 } 235 reset(&mut self) -> io::Result<()>236 fn reset(&mut self) -> io::Result<()> { 237 self.upstream.reset() 238 } 239 } 240 241 pub struct SvgWriter<W> { 242 upstream: W, 243 color: ColorSpec, 244 } 245 246 impl<W> SvgWriter<W> { new(upstream: W) -> SvgWriter<W>247 pub fn new(upstream: W) -> SvgWriter<W> { 248 SvgWriter { 249 upstream, 250 color: ColorSpec::new(), 251 } 252 } 253 } 254 255 impl<W: Write> Write for SvgWriter<W> { write(&mut self, buf: &[u8]) -> io::Result<usize>256 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 257 self.upstream.write(buf) 258 } 259 flush(&mut self) -> io::Result<()>260 fn flush(&mut self) -> io::Result<()> { 261 self.upstream.flush() 262 } 263 } 264 265 impl<W: Write> WriteColor for SvgWriter<W> { supports_color(&self) -> bool266 fn supports_color(&self) -> bool { 267 true 268 } 269 set_color(&mut self, spec: &ColorSpec) -> io::Result<()>270 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { 271 #![allow(unused_assignments)] 272 273 if self.color == *spec { 274 return Ok(()); 275 } else { 276 if !self.color.is_none() { 277 write!(self, "</span>")?; 278 } 279 self.color = spec.clone(); 280 } 281 282 if spec.is_none() { 283 write!(self, "</span>")?; 284 return Ok(()); 285 } else { 286 write!(self, "<span class=\"")?; 287 } 288 289 let mut first = true; 290 291 fn write_first<W: Write>(first: bool, writer: &mut SvgWriter<W>) -> io::Result<bool> { 292 if !first { 293 write!(writer, " ")?; 294 } 295 296 Ok(false) 297 }; 298 299 fn write_color<W: Write>(color: &Color, writer: &mut SvgWriter<W>) -> io::Result<()> { 300 match color { 301 Color::Black => write!(writer, "black"), 302 Color::Blue => write!(writer, "blue"), 303 Color::Green => write!(writer, "green"), 304 Color::Red => write!(writer, "red"), 305 Color::Cyan => write!(writer, "cyan"), 306 Color::Magenta => write!(writer, "magenta"), 307 Color::Yellow => write!(writer, "yellow"), 308 Color::White => write!(writer, "white"), 309 // TODO: other colors 310 _ => Ok(()), 311 } 312 }; 313 314 if let Some(fg) = spec.fg() { 315 first = write_first(first, self)?; 316 write!(self, "fg ")?; 317 write_color(fg, self)?; 318 } 319 320 if let Some(bg) = spec.bg() { 321 first = write_first(first, self)?; 322 write!(self, "bg ")?; 323 write_color(bg, self)?; 324 } 325 326 if spec.bold() { 327 first = write_first(first, self)?; 328 write!(self, "bold")?; 329 } 330 331 if spec.underline() { 332 first = write_first(first, self)?; 333 write!(self, "underline")?; 334 } 335 336 if spec.intense() { 337 first = write_first(first, self)?; 338 write!(self, "bright")?; 339 } 340 341 write!(self, "\">")?; 342 343 Ok(()) 344 } 345 reset(&mut self) -> io::Result<()>346 fn reset(&mut self) -> io::Result<()> { 347 let color = self.color.clone(); 348 349 if color != ColorSpec::new() { 350 write!(self, "</span>")?; 351 self.color = ColorSpec::new(); 352 } 353 354 Ok(()) 355 } 356 } 357