1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
use crate::{repl::ReplyStreamEvent, utils::dump};
use anyhow::Result;
use crossbeam::channel::Receiver;
use mdcat::{
push_tty,
terminal::{TerminalProgram, TerminalSize},
Environment, ResourceAccess, Settings,
};
use pulldown_cmark::Parser;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use syntect::parsing::SyntaxSet;
pub fn render_stream(
rx: Receiver<ReplyStreamEvent>,
ctrlc: Arc<AtomicBool>,
markdown_render: Arc<MarkdownRender>,
) -> Result<()> {
let mut buffer = String::new();
let mut line_index = 0;
loop {
if ctrlc.load(Ordering::SeqCst) {
return Ok(());
}
if let Ok(evt) = rx.try_recv() {
match evt {
ReplyStreamEvent::Text(text) => {
buffer.push_str(&text);
if text.contains('\n') {
let markdown = markdown_render.render(&buffer)?;
let lines: Vec<&str> = markdown.lines().collect();
let (_, print_lines) = lines.split_at(line_index);
let mut print_lines = print_lines.to_vec();
print_lines.pop();
if !print_lines.is_empty() {
line_index += print_lines.len();
dump(print_lines.join("\n").to_string(), 1);
}
}
}
ReplyStreamEvent::Done => {
let markdown = markdown_render.render(&buffer)?;
let tail = markdown
.lines()
.skip(line_index)
.collect::<Vec<&str>>()
.join("\n");
dump(tail, 2);
break;
}
}
}
}
Ok(())
}
pub struct MarkdownRender {
env: Environment,
settings: Settings,
}
impl MarkdownRender {
pub fn init() -> Result<Self> {
let terminal = TerminalProgram::detect();
let env =
Environment::for_local_directory(&std::env::current_dir().expect("Working directory"))?;
let settings = Settings {
resource_access: ResourceAccess::LocalOnly,
syntax_set: SyntaxSet::load_defaults_newlines(),
terminal_capabilities: terminal.capabilities(),
terminal_size: TerminalSize::default(),
};
Ok(Self { env, settings })
}
pub fn print(&self, input: &str) -> Result<()> {
let markdown = self.render(input)?;
dump(markdown, 0);
Ok(())
}
pub fn render(&self, input: &str) -> Result<String> {
let source = Parser::new(input);
let mut sink = Vec::new();
push_tty(&self.settings, &self.env, &mut sink, source)?;
Ok(String::from_utf8_lossy(&sink).into())
}
}
|