tangled
alpha
login
or
join now
eldridge.cam
/
paper-terminal
0
fork
atom
Print Markdown to a paper in your terminal
0
fork
atom
overview
issues
pulls
pipelines
Update pulldown-cmark
eldridge.cam
5 years ago
435fe488
0febb5a4
+220
-130
3 changed files
expand all
collapse all
unified
split
Cargo.lock
Cargo.toml
src
printer.rs
+2
-2
Cargo.lock
···
520
520
521
521
[[package]]
522
522
name = "pulldown-cmark"
523
523
-
version = "0.4.1"
523
523
+
version = "0.8.0"
524
524
source = "registry+https://github.com/rust-lang/crates.io-index"
525
525
-
checksum = "d1b74cc784b038a9921fd1a48310cc2e238101aa8ae0b94201e2d85121dd68b5"
525
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
22
-
pulldown-cmark = "0.4"
22
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
1
-
use std::convert::{TryInto, TryFrom};
2
2
-
use std::io::{Read as _, Write as _};
3
3
-
use std::process::{Command, Stdio};
4
4
-
use ansi_term::Style;
5
5
-
use pulldown_cmark::{Alignment, Event, Tag};
6
6
-
use image::{self, GenericImageView as _};
7
7
-
use console::{measure_text_width, AnsiCodeIterator};
8
8
-
use syncat_stylesheet::{Stylesheet, Query};
1
1
+
use crate::table::Table;
9
2
use crate::termpix;
10
3
use crate::words::Words;
11
11
-
use crate::table::Table;
4
4
+
use ansi_term::Style;
5
5
+
use console::{measure_text_width, AnsiCodeIterator};
6
6
+
use image::{self, GenericImageView as _};
7
7
+
use pulldown_cmark::{Alignment, CodeBlockKind, Event, Tag};
8
8
+
use std::convert::{TryFrom, TryInto};
9
9
+
use std::io::{Read as _, Write as _};
10
10
+
use std::process::{Command, Stdio};
11
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
22
-
Rule,
23
22
FootnoteDefinition,
24
23
FootnoteReference,
25
24
FootnoteContent,
26
26
-
List(Option<usize>),
27
27
-
ListItem(Option<usize>, bool),
25
25
+
List(Option<u64>),
26
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
35
-
Heading(i32),
34
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
48
-
_ => 0
47
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
85
-
_ => 0
84
84
+
_ => 0,
86
85
}
87
86
}
88
87
···
105
104
Strikethrough => "strikethrough",
106
105
Link => "link",
107
106
Caption => "caption",
108
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
147
-
pub fn new(centering: &'a str, margin: &'a str, width: usize, stylesheet: &'a Stylesheet, opts: &'a crate::Opts) -> Printer<'a> {
145
145
+
pub fn new(
146
146
+
centering: &'a str,
147
147
+
margin: &'a str,
148
148
+
width: usize,
149
149
+
stylesheet: &'a Stylesheet,
150
150
+
opts: &'a crate::Opts,
151
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
221
-
if scopes.is_empty() { return Style::default(); }
225
225
+
if scopes.is_empty() {
226
226
+
return Style::default();
227
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
228
-
stylesheet.style(&query).unwrap_or_default().try_into().unwrap_or_default()
234
234
+
stylesheet
235
235
+
.style(&query)
236
236
+
.unwrap_or_default()
237
237
+
.try_into()
238
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
240
-
format!("{}", Style::try_from(self.stylesheet.style(&"shadow".into()).unwrap_or_default()).unwrap_or_default().paint(" "))
250
250
+
format!(
251
251
+
"{}",
252
252
+
Style::try_from(self.stylesheet.style(&"shadow".into()).unwrap_or_default())
253
253
+
.unwrap_or_default()
254
254
+
.paint(" ")
255
255
+
)
241
256
}
242
257
243
258
fn paper_style(&self) -> Style {
244
244
-
Style::try_from(self.stylesheet.style(&"paper".into()).unwrap_or_default()).unwrap_or_default()
259
259
+
Style::try_from(self.stylesheet.style(&"paper".into()).unwrap_or_default())
260
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
259
-
self.paper_style().paint(" ".repeat(self.width - prefix_len - suffix_len)),
275
275
+
self.paper_style()
276
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
275
-
self.style().paint("─".repeat(self.width - prefix_len - suffix_len)),
292
292
+
self.style()
293
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
285
-
} else { return };
303
303
+
} else {
304
304
+
return;
305
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
288
-
let table_str = Table::new(heading, rows, available_width)
289
289
-
.print(self.paper_style(), alignments);
308
308
+
let table_str =
309
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
299
-
self.paper_style().paint(" ".repeat(available_width - measure_text_width(line))),
319
319
+
self.paper_style()
320
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
355
-
format!("{}{}{}\n", output, line, " ".repeat(available_width - line.chars().count()))
376
376
+
format!(
377
377
+
"{}{}{}\n",
378
378
+
output,
379
379
+
line,
380
380
+
" ".repeat(available_width - line.chars().count())
381
381
+
)
356
382
})
357
383
.collect()
358
384
};
359
385
360
360
-
let (prefix, _) = first_prefix.take().unwrap_or_else(|| self.prefix2(Some(&[&language_context[..]])));
361
361
-
let (suffix, _) = first_suffix.take().unwrap_or_else(|| self.suffix2(Some(&[&language_context[..]])));
386
386
+
let (prefix, _) = first_prefix
387
387
+
.take()
388
388
+
.unwrap_or_else(|| self.prefix2(Some(&[&language_context[..]])));
389
389
+
let (suffix, _) = first_suffix
390
390
+
.take()
391
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
404
-
let (prefix, _) = first_prefix.take().unwrap_or_else(|| self.prefix2(Some(&[&language_context[..]])));
405
405
-
let (suffix, _) = first_suffix.take().unwrap_or_else(|| self.suffix2(Some(&[&language_context[..]])));
434
434
+
let (prefix, _) = first_prefix
435
435
+
.take()
436
436
+
.unwrap_or_else(|| self.prefix2(Some(&[&language_context[..]])));
437
437
+
let (suffix, _) = first_suffix
438
438
+
.take()
439
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
411
-
format!("{}{}",
412
412
-
style.paint(" ".repeat(available_width - lang.chars().count())),
413
413
-
self.style3(Some(&[&language_context[..]]), Some("lang-tag")).paint(lang)
445
445
+
format!(
446
446
+
"{}{}",
447
447
+
style.paint(" ".repeat(available_width - lang.chars().count())),
448
448
+
self.style3(Some(&[&language_context[..]]), Some("lang-tag"))
449
449
+
.paint(lang)
414
450
),
415
451
suffix,
416
452
self.margin,
417
453
self.shadow(),
418
454
);
419
419
-
420
455
}
421
456
_ => {}
422
457
}
···
426
461
if !self.buffer.is_empty() {
427
462
return;
428
463
}
429
429
-
if self.scope.iter().find(|scope| if let Scope::Table(..) = scope { true } else { false }).is_some() {
464
464
+
if self
465
465
+
.scope
466
466
+
.iter()
467
467
+
.find(|scope| {
468
468
+
if let Scope::Table(..) = scope {
469
469
+
true
470
470
+
} else {
471
471
+
false
472
472
+
}
473
473
+
})
474
474
+
.is_some()
475
475
+
{
476
476
+
return;
477
477
+
}
478
478
+
if self.content.is_empty() {
430
479
return;
431
480
}
432
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
442
-
self.paper_style().paint(" ".repeat(self.width - measure_text_width(&self.content) - prefix_len - suffix_len)),
490
490
+
self.paper_style().paint(
491
491
+
" ".repeat(
492
492
+
self.width - measure_text_width(&self.content) - prefix_len - suffix_len
493
493
+
)
494
494
+
),
443
495
self.margin,
444
496
self.shadow(),
445
497
);
···
447
499
}
448
500
449
501
fn target(&mut self) -> &mut String {
450
450
-
if self.scope.iter().find(|scope| *scope == &Scope::TableHead).is_some() {
502
502
+
if self
503
503
+
.scope
504
504
+
.iter()
505
505
+
.find(|scope| *scope == &Scope::TableHead)
506
506
+
.is_some()
507
507
+
{
451
508
self.table.0.last_mut().unwrap()
452
452
-
} else if self.scope.iter().find(|scope| *scope == &Scope::TableRow).is_some() {
509
509
+
} else if self
510
510
+
.scope
511
511
+
.iter()
512
512
+
.find(|scope| *scope == &Scope::TableRow)
513
513
+
.is_some()
514
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
459
-
fn handle_text<S>(&mut self, text: S) where S: AsRef<str> {
521
521
+
fn handle_text<S>(&mut self, text: S)
522
522
+
where
523
523
+
S: AsRef<str>,
524
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
467
-
if measure_text_width(&self.content) + word.len() + self.prefix_len() + self.suffix_len() > self.width {
532
532
+
if measure_text_width(&self.content)
533
533
+
+ word.len()
534
534
+
+ self.prefix_len()
535
535
+
+ self.suffix_len()
536
536
+
> self.width
537
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
494
-
Tag::Paragraph => { self.flush(); }
495
495
-
Tag::Rule => {
564
564
+
Tag::Paragraph => {
496
565
self.flush();
497
497
-
self.scope.push(Scope::Rule);
498
566
}
499
499
-
Tag::Header(level) => {
567
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
510
-
Tag::CodeBlock(language) => {
578
578
+
Tag::CodeBlock(CodeBlockKind::Indented) => {
579
579
+
self.flush();
580
580
+
self.scope.push(Scope::CodeBlock("".to_string()));
581
581
+
}
582
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
534
-
Tag::HtmlBlock => { /* do nothing */ }
535
535
-
Tag::Table(columns) => { self.scope.push(Scope::Table(columns)) }
606
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
545
-
if self.scope.iter().find(|scope| *scope == &Scope::TableHead).is_some() {
616
616
+
if self
617
617
+
.scope
618
618
+
.iter()
619
619
+
.find(|scope| *scope == &Scope::TableHead)
620
620
+
.is_some()
621
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
551
-
Tag::Emphasis => { self.scope.push(Scope::Italic); }
552
552
-
Tag::Strong => { self.scope.push(Scope::Bold); }
553
553
-
Tag::Strikethrough => { self.scope.push(Scope::Strikethrough); }
554
554
-
Tag::Code => { self.scope.push(Scope::Code); }
627
627
+
Tag::Emphasis => {
628
628
+
self.scope.push(Scope::Italic);
629
629
+
}
630
630
+
Tag::Strong => {
631
631
+
self.scope.push(Scope::Bold);
632
632
+
}
633
633
+
Tag::Strikethrough => {
634
634
+
self.scope.push(Scope::Strikethrough);
635
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
562
-
let available_width = self.width - self.prefix_len() - self.suffix_len();
643
643
+
let available_width =
644
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
629
-
Event::End(tag) => {
630
630
-
match tag {
631
631
-
Tag::Paragraph => {
632
632
-
self.flush();
633
633
-
self.queue_empty();
634
634
-
}
635
635
-
Tag::Header(level) => {
636
636
-
self.flush();
637
637
-
self.scope.pop();
638
638
-
if level == 1 {
639
639
-
self.print_rule();
640
640
-
}
641
641
-
self.queue_empty();
642
642
-
}
643
643
-
Tag::Rule => {
644
644
-
self.flush();
711
711
+
Event::End(tag) => match tag {
712
712
+
Tag::Paragraph => {
713
713
+
self.flush();
714
714
+
self.queue_empty();
715
715
+
}
716
716
+
Tag::Heading(level) => {
717
717
+
self.flush();
718
718
+
self.scope.pop();
719
719
+
if level == 1 {
645
720
self.print_rule();
646
646
-
self.scope.pop();
647
647
-
}
648
648
-
Tag::List(..) => {
649
649
-
self.flush();
650
650
-
self.scope.pop();
651
651
-
self.queue_empty();
652
652
-
}
653
653
-
Tag::Item => {
654
654
-
self.flush();
655
655
-
self.scope.pop();
656
656
-
if let Some(Scope::List(index)) = self.scope.last_mut() {
657
657
-
*index = index.map(|x| x + 1);
658
658
-
}
659
659
-
},
660
660
-
Tag::BlockQuote => {
661
661
-
self.flush();
662
662
-
self.scope.pop();
663
663
-
self.queue_empty();
664
721
}
665
665
-
Tag::Table(..) => {
666
666
-
self.print_table();
667
667
-
self.scope.pop();
668
668
-
self.queue_empty();
669
669
-
}
670
670
-
Tag::CodeBlock(..) => {
671
671
-
self.flush_buffer();
672
672
-
self.scope.pop();
673
673
-
self.queue_empty();
674
674
-
}
675
675
-
Tag::Link(_link_type, destination, title) => {
676
676
-
if !title.is_empty() && !destination.is_empty() && !self.opts.hide_urls {
677
677
-
self.handle_text(format!(" <{}: {}>", title, destination));
678
678
-
} else if !destination.is_empty() && !self.opts.hide_urls {
679
679
-
self.handle_text(format!(" <{}>", destination));
680
680
-
} else if !title.is_empty() {
681
681
-
self.handle_text(format!(" <{}>", title));
682
682
-
}
683
683
-
self.scope.pop();
684
684
-
}
685
685
-
Tag::Image(_link_type, _destination, _title) => {
686
686
-
self.flush();
687
687
-
self.scope.pop();
688
688
-
self.scope.pop();
689
689
-
self.queue_empty();
722
722
+
self.queue_empty();
723
723
+
}
724
724
+
Tag::List(..) => {
725
725
+
self.flush();
726
726
+
self.scope.pop();
727
727
+
self.queue_empty();
728
728
+
}
729
729
+
Tag::Item => {
730
730
+
self.flush();
731
731
+
self.scope.pop();
732
732
+
if let Some(Scope::List(index)) = self.scope.last_mut() {
733
733
+
*index = index.map(|x| x + 1);
690
734
}
691
691
-
Tag::FootnoteDefinition(..) => {
692
692
-
self.flush();
693
693
-
self.scope.pop();
694
694
-
self.queue_empty();
735
735
+
}
736
736
+
Tag::BlockQuote => {
737
737
+
self.flush();
738
738
+
self.scope.pop();
739
739
+
self.queue_empty();
740
740
+
}
741
741
+
Tag::Table(..) => {
742
742
+
self.print_table();
743
743
+
self.scope.pop();
744
744
+
self.queue_empty();
745
745
+
}
746
746
+
Tag::CodeBlock(..) => {
747
747
+
self.flush_buffer();
748
748
+
self.scope.pop();
749
749
+
self.queue_empty();
750
750
+
}
751
751
+
Tag::Link(_link_type, destination, title) => {
752
752
+
if !title.is_empty() && !destination.is_empty() && !self.opts.hide_urls {
753
753
+
self.handle_text(format!(" <{}: {}>", title, destination));
754
754
+
} else if !destination.is_empty() && !self.opts.hide_urls {
755
755
+
self.handle_text(format!(" <{}>", destination));
756
756
+
} else if !title.is_empty() {
757
757
+
self.handle_text(format!(" <{}>", title));
695
758
}
696
696
-
Tag::HtmlBlock => { /* do nothing */ }
697
697
-
_ => { self.scope.pop(); }
759
759
+
self.scope.pop();
760
760
+
}
761
761
+
Tag::Image(_link_type, _destination, _title) => {
762
762
+
self.flush();
763
763
+
self.scope.pop();
764
764
+
self.scope.pop();
765
765
+
self.queue_empty();
698
766
}
767
767
+
Tag::FootnoteDefinition(..) => {
768
768
+
self.flush();
769
769
+
self.scope.pop();
770
770
+
self.queue_empty();
771
771
+
}
772
772
+
_ => {
773
773
+
self.scope.pop();
774
774
+
}
775
775
+
},
776
776
+
Event::Rule => {
777
777
+
self.flush();
778
778
+
self.print_rule();
699
779
}
700
700
-
Event::Text(text) => { self.handle_text(text); }
780
780
+
Event::Text(text) => {
781
781
+
self.handle_text(text);
782
782
+
}
783
783
+
Event::Code(text) => {
784
784
+
self.scope.push(Scope::Code);
785
785
+
self.handle_text(text);
786
786
+
self.scope.pop();
787
787
+
}
701
788
Event::Html(_text) => { /* unimplemented */ }
702
702
-
Event::InlineHtml(_text) => { /* unimplemented */ }
703
703
-
Event::FootnoteReference(text) => {
789
789
+
Event::FootnoteReference(text) => {
704
790
self.scope.push(Scope::FootnoteReference);
705
705
-
self.handle_text(&format!("[{}]", text));
791
791
+
self.handle_text(&format!("[{}]", text));
706
792
self.scope.pop();
707
793
}
708
708
-
Event::SoftBreak => { self.handle_text(" "); }
709
709
-
Event::HardBreak => { self.flush(); }
794
794
+
Event::SoftBreak => {
795
795
+
self.handle_text(" ");
796
796
+
}
797
797
+
Event::HardBreak => {
798
798
+
self.flush();
799
799
+
}
710
800
Event::TaskListMarker(checked) => {
711
801
self.handle_text(if checked { "[✓] " } else { "[ ] " });
712
802
}