Print Markdown to a paper in your terminal

Update pulldown-cmark

+220 -130
+2 -2
Cargo.lock
··· 520 520 521 521 [[package]] 522 522 name = "pulldown-cmark" 523 - version = "0.4.1" 523 + version = "0.8.0" 524 524 source = "registry+https://github.com/rust-lang/crates.io-index" 525 - checksum = "d1b74cc784b038a9921fd1a48310cc2e238101aa8ae0b94201e2d85121dd68b5" 525 + checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" 526 526 dependencies = [ 527 527 "bitflags", 528 528 "getopts",
+1 -1
Cargo.toml
··· 19 19 [dependencies] 20 20 structopt = "0.3" 21 21 terminal_size = "0.1" 22 - pulldown-cmark = "0.4" 22 + pulldown-cmark = "0.8" 23 23 ansi_term = "0.12" 24 24 image = "0.23" 25 25 console = "0.13"
+217 -127
src/printer.rs
··· 1 - use std::convert::{TryInto, TryFrom}; 2 - use std::io::{Read as _, Write as _}; 3 - use std::process::{Command, Stdio}; 4 - use ansi_term::Style; 5 - use pulldown_cmark::{Alignment, Event, Tag}; 6 - use image::{self, GenericImageView as _}; 7 - use console::{measure_text_width, AnsiCodeIterator}; 8 - use syncat_stylesheet::{Stylesheet, Query}; 1 + use crate::table::Table; 9 2 use crate::termpix; 10 3 use crate::words::Words; 11 - use crate::table::Table; 4 + use ansi_term::Style; 5 + use console::{measure_text_width, AnsiCodeIterator}; 6 + use image::{self, GenericImageView as _}; 7 + use pulldown_cmark::{Alignment, CodeBlockKind, Event, Tag}; 8 + use std::convert::{TryFrom, TryInto}; 9 + use std::io::{Read as _, Write as _}; 10 + use std::process::{Command, Stdio}; 11 + use syncat_stylesheet::{Query, Stylesheet}; 12 12 13 13 #[derive(Debug, PartialEq)] 14 14 enum Scope { ··· 19 19 Strikethrough, 20 20 Link, 21 21 Caption, 22 - Rule, 23 22 FootnoteDefinition, 24 23 FootnoteReference, 25 24 FootnoteContent, 26 - List(Option<usize>), 27 - ListItem(Option<usize>, bool), 25 + List(Option<u64>), 26 + ListItem(Option<u64>, bool), 28 27 Code, 29 28 CodeBlock(String), 30 29 BlockQuote, ··· 32 31 TableHead, 33 32 TableRow, 34 33 TableCell, 35 - Heading(i32), 34 + Heading(u32), 36 35 } 37 36 38 37 impl Scope { ··· 45 44 Scope::BlockQuote => 4, 46 45 Scope::Heading(2) => 5, 47 46 Scope::Heading(..) => 4, 48 - _ => 0 47 + _ => 0, 49 48 } 50 49 } 51 50 ··· 82 81 Scope::CodeBlock(..) => 2, 83 82 Scope::Heading(2) => 5, 84 83 Scope::Heading(..) => 4, 85 - _ => 0 84 + _ => 0, 86 85 } 87 86 } 88 87 ··· 105 104 Strikethrough => "strikethrough", 106 105 Link => "link", 107 106 Caption => "caption", 108 - Rule => "hr", 109 107 FootnoteDefinition => "footnote-def", 110 108 FootnoteReference => "footnote-ref", 111 109 FootnoteContent => "footnote", ··· 144 142 } 145 143 146 144 impl<'a> Printer<'a> { 147 - pub fn new(centering: &'a str, margin: &'a str, width: usize, stylesheet: &'a Stylesheet, opts: &'a crate::Opts) -> Printer<'a> { 145 + pub fn new( 146 + centering: &'a str, 147 + margin: &'a str, 148 + width: usize, 149 + stylesheet: &'a Stylesheet, 150 + opts: &'a crate::Opts, 151 + ) -> Printer<'a> { 148 152 Printer { 149 153 centering, 150 154 margin, ··· 218 222 } 219 223 220 224 fn resolve_scopes(stylesheet: &Stylesheet, scopes: &[&str], token: Option<&str>) -> Style { 221 - if scopes.is_empty() { return Style::default(); } 225 + if scopes.is_empty() { 226 + return Style::default(); 227 + } 222 228 let mut query = Query::new(scopes[0], token.unwrap_or(scopes[0])); 223 229 let mut index = vec![]; 224 230 for scope in &scopes[1..] { 225 231 query[&index[..]].add_child(Query::new(*scope, token.unwrap_or(scope))); 226 232 index.push(0); 227 233 } 228 - stylesheet.style(&query).unwrap_or_default().try_into().unwrap_or_default() 234 + stylesheet 235 + .style(&query) 236 + .unwrap_or_default() 237 + .try_into() 238 + .unwrap_or_default() 229 239 } 230 240 231 241 fn style2(&self, token: Option<&str>) -> Style { ··· 237 247 } 238 248 239 249 fn shadow(&self) -> String { 240 - format!("{}", Style::try_from(self.stylesheet.style(&"shadow".into()).unwrap_or_default()).unwrap_or_default().paint(" ")) 250 + format!( 251 + "{}", 252 + Style::try_from(self.stylesheet.style(&"shadow".into()).unwrap_or_default()) 253 + .unwrap_or_default() 254 + .paint(" ") 255 + ) 241 256 } 242 257 243 258 fn paper_style(&self) -> Style { 244 - Style::try_from(self.stylesheet.style(&"paper".into()).unwrap_or_default()).unwrap_or_default() 259 + Style::try_from(self.stylesheet.style(&"paper".into()).unwrap_or_default()) 260 + .unwrap_or_default() 245 261 } 246 262 247 263 fn queue_empty(&mut self) { ··· 256 272 self.centering, 257 273 self.margin, 258 274 prefix, 259 - self.paper_style().paint(" ".repeat(self.width - prefix_len - suffix_len)), 275 + self.paper_style() 276 + .paint(" ".repeat(self.width - prefix_len - suffix_len)), 260 277 suffix, 261 278 self.margin, 262 279 self.shadow(), ··· 272 289 self.centering, 273 290 self.margin, 274 291 prefix, 275 - self.style().paint("─".repeat(self.width - prefix_len - suffix_len)), 292 + self.style() 293 + .paint("─".repeat(self.width - prefix_len - suffix_len)), 276 294 suffix, 277 295 self.margin, 278 296 self.shadow(), ··· 282 300 fn print_table(&mut self) { 283 301 let alignments = if let Some(Scope::Table(alignments)) = self.scope.last() { 284 302 alignments 285 - } else { return }; 303 + } else { 304 + return; 305 + }; 286 306 let (heading, rows) = std::mem::replace(&mut self.table, (vec![], vec![])); 287 307 let available_width = self.width - self.prefix_len() - self.suffix_len(); 288 - let table_str = Table::new(heading, rows, available_width) 289 - .print(self.paper_style(), alignments); 308 + let table_str = 309 + Table::new(heading, rows, available_width).print(self.paper_style(), alignments); 290 310 for line in table_str.lines() { 291 311 let (prefix, _) = self.prefix(); 292 312 let (suffix, _) = self.suffix(); ··· 296 316 self.margin, 297 317 line, 298 318 prefix, 299 - self.paper_style().paint(" ".repeat(available_width - measure_text_width(line))), 319 + self.paper_style() 320 + .paint(" ".repeat(available_width - measure_text_width(line))), 300 321 suffix, 301 322 self.margin, 302 323 self.shadow(), ··· 352 373 output = format!("{}{}\n", output, prefix); 353 374 line = &line[prefix.len()..]; 354 375 } 355 - format!("{}{}{}\n", output, line, " ".repeat(available_width - line.chars().count())) 376 + format!( 377 + "{}{}{}\n", 378 + output, 379 + line, 380 + " ".repeat(available_width - line.chars().count()) 381 + ) 356 382 }) 357 383 .collect() 358 384 }; 359 385 360 - let (prefix, _) = first_prefix.take().unwrap_or_else(|| self.prefix2(Some(&[&language_context[..]]))); 361 - let (suffix, _) = first_suffix.take().unwrap_or_else(|| self.suffix2(Some(&[&language_context[..]]))); 386 + let (prefix, _) = first_prefix 387 + .take() 388 + .unwrap_or_else(|| self.prefix2(Some(&[&language_context[..]]))); 389 + let (suffix, _) = first_suffix 390 + .take() 391 + .unwrap_or_else(|| self.suffix2(Some(&[&language_context[..]]))); 362 392 println!( 363 393 "{}{}{}{}{}{}{}", 364 394 self.centering, ··· 401 431 ); 402 432 } 403 433 404 - let (prefix, _) = first_prefix.take().unwrap_or_else(|| self.prefix2(Some(&[&language_context[..]]))); 405 - let (suffix, _) = first_suffix.take().unwrap_or_else(|| self.suffix2(Some(&[&language_context[..]]))); 434 + let (prefix, _) = first_prefix 435 + .take() 436 + .unwrap_or_else(|| self.prefix2(Some(&[&language_context[..]]))); 437 + let (suffix, _) = first_suffix 438 + .take() 439 + .unwrap_or_else(|| self.suffix2(Some(&[&language_context[..]]))); 406 440 println!( 407 441 "{}{}{}{}{}{}{}", 408 442 self.centering, 409 443 self.margin, 410 444 prefix, 411 - format!("{}{}", 412 - style.paint(" ".repeat(available_width - lang.chars().count())), 413 - self.style3(Some(&[&language_context[..]]), Some("lang-tag")).paint(lang) 445 + format!( 446 + "{}{}", 447 + style.paint(" ".repeat(available_width - lang.chars().count())), 448 + self.style3(Some(&[&language_context[..]]), Some("lang-tag")) 449 + .paint(lang) 414 450 ), 415 451 suffix, 416 452 self.margin, 417 453 self.shadow(), 418 454 ); 419 - 420 455 } 421 456 _ => {} 422 457 } ··· 426 461 if !self.buffer.is_empty() { 427 462 return; 428 463 } 429 - if self.scope.iter().find(|scope| if let Scope::Table(..) = scope { true } else { false }).is_some() { 464 + if self 465 + .scope 466 + .iter() 467 + .find(|scope| { 468 + if let Scope::Table(..) = scope { 469 + true 470 + } else { 471 + false 472 + } 473 + }) 474 + .is_some() 475 + { 476 + return; 477 + } 478 + if self.content.is_empty() { 430 479 return; 431 480 } 432 - if self.content.is_empty() { return } 433 481 let (prefix, prefix_len) = self.prefix(); 434 482 let (suffix, suffix_len) = self.suffix(); 435 483 println!( ··· 439 487 prefix, 440 488 self.content, 441 489 suffix, 442 - self.paper_style().paint(" ".repeat(self.width - measure_text_width(&self.content) - prefix_len - suffix_len)), 490 + self.paper_style().paint( 491 + " ".repeat( 492 + self.width - measure_text_width(&self.content) - prefix_len - suffix_len 493 + ) 494 + ), 443 495 self.margin, 444 496 self.shadow(), 445 497 ); ··· 447 499 } 448 500 449 501 fn target(&mut self) -> &mut String { 450 - if self.scope.iter().find(|scope| *scope == &Scope::TableHead).is_some() { 502 + if self 503 + .scope 504 + .iter() 505 + .find(|scope| *scope == &Scope::TableHead) 506 + .is_some() 507 + { 451 508 self.table.0.last_mut().unwrap() 452 - } else if self.scope.iter().find(|scope| *scope == &Scope::TableRow).is_some() { 509 + } else if self 510 + .scope 511 + .iter() 512 + .find(|scope| *scope == &Scope::TableRow) 513 + .is_some() 514 + { 453 515 self.table.1.last_mut().unwrap().last_mut().unwrap() 454 516 } else { 455 517 &mut self.content 456 518 } 457 519 } 458 520 459 - fn handle_text<S>(&mut self, text: S) where S: AsRef<str> { 521 + fn handle_text<S>(&mut self, text: S) 522 + where 523 + S: AsRef<str>, 524 + { 460 525 let s = text.as_ref(); 461 526 if let Some(Scope::CodeBlock(..)) = self.scope.last() { 462 527 self.buffer += s; ··· 464 529 } 465 530 let style = self.style(); 466 531 for word in Words::new(s) { 467 - if measure_text_width(&self.content) + word.len() + self.prefix_len() + self.suffix_len() > self.width { 532 + if measure_text_width(&self.content) 533 + + word.len() 534 + + self.prefix_len() 535 + + self.suffix_len() 536 + > self.width 537 + { 468 538 self.flush(); 469 539 } 470 540 let mut word = if self.target().is_empty() { ··· 491 561 self.empty(); 492 562 } 493 563 match tag { 494 - Tag::Paragraph => { self.flush(); } 495 - Tag::Rule => { 564 + Tag::Paragraph => { 496 565 self.flush(); 497 - self.scope.push(Scope::Rule); 498 566 } 499 - Tag::Header(level) => { 567 + Tag::Heading(level) => { 500 568 self.flush(); 501 569 if level == 1 { 502 570 self.print_rule(); ··· 507 575 self.flush(); 508 576 self.scope.push(Scope::BlockQuote); 509 577 } 510 - Tag::CodeBlock(language) => { 578 + Tag::CodeBlock(CodeBlockKind::Indented) => { 579 + self.flush(); 580 + self.scope.push(Scope::CodeBlock("".to_string())); 581 + } 582 + Tag::CodeBlock(CodeBlockKind::Fenced(language)) => { 511 583 self.flush(); 512 584 self.scope.push(Scope::CodeBlock(language.to_string())); 513 585 } ··· 531 603 self.flush(); 532 604 self.scope.push(Scope::FootnoteContent); 533 605 } 534 - Tag::HtmlBlock => { /* do nothing */ } 535 - Tag::Table(columns) => { self.scope.push(Scope::Table(columns)) } 606 + Tag::Table(columns) => self.scope.push(Scope::Table(columns)), 536 607 Tag::TableHead => { 537 608 self.scope.push(Scope::TableHead); 538 609 } ··· 542 613 } 543 614 Tag::TableCell => { 544 615 self.scope.push(Scope::TableCell); 545 - if self.scope.iter().find(|scope| *scope == &Scope::TableHead).is_some() { 616 + if self 617 + .scope 618 + .iter() 619 + .find(|scope| *scope == &Scope::TableHead) 620 + .is_some() 621 + { 546 622 self.table.0.push(String::new()); 547 623 } else { 548 624 self.table.1.last_mut().unwrap().push(String::new()); 549 625 } 550 626 } 551 - Tag::Emphasis => { self.scope.push(Scope::Italic); } 552 - Tag::Strong => { self.scope.push(Scope::Bold); } 553 - Tag::Strikethrough => { self.scope.push(Scope::Strikethrough); } 554 - Tag::Code => { self.scope.push(Scope::Code); } 627 + Tag::Emphasis => { 628 + self.scope.push(Scope::Italic); 629 + } 630 + Tag::Strong => { 631 + self.scope.push(Scope::Bold); 632 + } 633 + Tag::Strikethrough => { 634 + self.scope.push(Scope::Strikethrough); 635 + } 555 636 Tag::Link(_link_type, _destination, _title) => { 556 637 self.scope.push(Scope::Link); 557 638 } ··· 559 640 self.flush(); 560 641 561 642 if !self.opts.no_images { 562 - let available_width = self.width - self.prefix_len() - self.suffix_len(); 643 + let available_width = 644 + self.width - self.prefix_len() - self.suffix_len(); 563 645 match image::open(destination.as_ref()) { 564 646 Ok(image) => { 565 647 let (mut width, mut height) = image.dimensions(); ··· 626 708 } 627 709 } 628 710 629 - Event::End(tag) => { 630 - match tag { 631 - Tag::Paragraph => { 632 - self.flush(); 633 - self.queue_empty(); 634 - } 635 - Tag::Header(level) => { 636 - self.flush(); 637 - self.scope.pop(); 638 - if level == 1 { 639 - self.print_rule(); 640 - } 641 - self.queue_empty(); 642 - } 643 - Tag::Rule => { 644 - self.flush(); 711 + Event::End(tag) => match tag { 712 + Tag::Paragraph => { 713 + self.flush(); 714 + self.queue_empty(); 715 + } 716 + Tag::Heading(level) => { 717 + self.flush(); 718 + self.scope.pop(); 719 + if level == 1 { 645 720 self.print_rule(); 646 - self.scope.pop(); 647 - } 648 - Tag::List(..) => { 649 - self.flush(); 650 - self.scope.pop(); 651 - self.queue_empty(); 652 - } 653 - Tag::Item => { 654 - self.flush(); 655 - self.scope.pop(); 656 - if let Some(Scope::List(index)) = self.scope.last_mut() { 657 - *index = index.map(|x| x + 1); 658 - } 659 - }, 660 - Tag::BlockQuote => { 661 - self.flush(); 662 - self.scope.pop(); 663 - self.queue_empty(); 664 721 } 665 - Tag::Table(..) => { 666 - self.print_table(); 667 - self.scope.pop(); 668 - self.queue_empty(); 669 - } 670 - Tag::CodeBlock(..) => { 671 - self.flush_buffer(); 672 - self.scope.pop(); 673 - self.queue_empty(); 674 - } 675 - Tag::Link(_link_type, destination, title) => { 676 - if !title.is_empty() && !destination.is_empty() && !self.opts.hide_urls { 677 - self.handle_text(format!(" <{}: {}>", title, destination)); 678 - } else if !destination.is_empty() && !self.opts.hide_urls { 679 - self.handle_text(format!(" <{}>", destination)); 680 - } else if !title.is_empty() { 681 - self.handle_text(format!(" <{}>", title)); 682 - } 683 - self.scope.pop(); 684 - } 685 - Tag::Image(_link_type, _destination, _title) => { 686 - self.flush(); 687 - self.scope.pop(); 688 - self.scope.pop(); 689 - self.queue_empty(); 722 + self.queue_empty(); 723 + } 724 + Tag::List(..) => { 725 + self.flush(); 726 + self.scope.pop(); 727 + self.queue_empty(); 728 + } 729 + Tag::Item => { 730 + self.flush(); 731 + self.scope.pop(); 732 + if let Some(Scope::List(index)) = self.scope.last_mut() { 733 + *index = index.map(|x| x + 1); 690 734 } 691 - Tag::FootnoteDefinition(..) => { 692 - self.flush(); 693 - self.scope.pop(); 694 - self.queue_empty(); 735 + } 736 + Tag::BlockQuote => { 737 + self.flush(); 738 + self.scope.pop(); 739 + self.queue_empty(); 740 + } 741 + Tag::Table(..) => { 742 + self.print_table(); 743 + self.scope.pop(); 744 + self.queue_empty(); 745 + } 746 + Tag::CodeBlock(..) => { 747 + self.flush_buffer(); 748 + self.scope.pop(); 749 + self.queue_empty(); 750 + } 751 + Tag::Link(_link_type, destination, title) => { 752 + if !title.is_empty() && !destination.is_empty() && !self.opts.hide_urls { 753 + self.handle_text(format!(" <{}: {}>", title, destination)); 754 + } else if !destination.is_empty() && !self.opts.hide_urls { 755 + self.handle_text(format!(" <{}>", destination)); 756 + } else if !title.is_empty() { 757 + self.handle_text(format!(" <{}>", title)); 695 758 } 696 - Tag::HtmlBlock => { /* do nothing */ } 697 - _ => { self.scope.pop(); } 759 + self.scope.pop(); 760 + } 761 + Tag::Image(_link_type, _destination, _title) => { 762 + self.flush(); 763 + self.scope.pop(); 764 + self.scope.pop(); 765 + self.queue_empty(); 698 766 } 767 + Tag::FootnoteDefinition(..) => { 768 + self.flush(); 769 + self.scope.pop(); 770 + self.queue_empty(); 771 + } 772 + _ => { 773 + self.scope.pop(); 774 + } 775 + }, 776 + Event::Rule => { 777 + self.flush(); 778 + self.print_rule(); 699 779 } 700 - Event::Text(text) => { self.handle_text(text); } 780 + Event::Text(text) => { 781 + self.handle_text(text); 782 + } 783 + Event::Code(text) => { 784 + self.scope.push(Scope::Code); 785 + self.handle_text(text); 786 + self.scope.pop(); 787 + } 701 788 Event::Html(_text) => { /* unimplemented */ } 702 - Event::InlineHtml(_text) => { /* unimplemented */ } 703 - Event::FootnoteReference(text) => { 789 + Event::FootnoteReference(text) => { 704 790 self.scope.push(Scope::FootnoteReference); 705 - self.handle_text(&format!("[{}]", text)); 791 + self.handle_text(&format!("[{}]", text)); 706 792 self.scope.pop(); 707 793 } 708 - Event::SoftBreak => { self.handle_text(" "); } 709 - Event::HardBreak => { self.flush(); } 794 + Event::SoftBreak => { 795 + self.handle_text(" "); 796 + } 797 + Event::HardBreak => { 798 + self.flush(); 799 + } 710 800 Event::TaskListMarker(checked) => { 711 801 self.handle_text(if checked { "[✓] " } else { "[ ] " }); 712 802 }