@@ -17,6 +17,95 @@ use helix_view::{
20+fn styled_multiline_text<'a>(text: String, style: Style) -> Text<'a> {
21+ let spans: Vec<_> = text
23+ .map(|line| Span::styled(line.to_string(), style))
29+pub fn highlighted_code_block<'a>(
32+ theme: Option<&Theme>,
33+ config_loader: Arc<syntax::Loader>,
35+ let mut spans = Vec::new();
36+ let mut lines = Vec::new();
38+ let get_theme = |key: &str| -> Style { theme.map(|t| t.get(key)).unwrap_or_default() };
39+ let text_style = get_theme(Markdown::TEXT_STYLE);
40+ let code_style = get_theme(Markdown::BLOCK_STYLE);
42+ let theme = match theme {
44+ None => return styled_multiline_text(text, code_style),
47+ let rope = Rope::from(text.as_ref());
48+ let syntax = config_loader
49+ .language_configuration_for_injection_string(language)
50+ .and_then(|config| config.highlight_config(theme.scopes()))
51+ .map(|config| Syntax::new(&rope, config, Arc::clone(&config_loader)));
53+ let syntax = match syntax {
55+ None => return styled_multiline_text(text, code_style),
58+ let mut highlights = Vec::new();
60+ for event in syntax.highlight_iter(rope.slice(..), None, None) {
61+ match event.unwrap() {
62+ HighlightEvent::HighlightStart(span) => {
63+ highlights.push(span);
65+ HighlightEvent::HighlightEnd => {
68+ HighlightEvent::Source { start, end } => {
69+ let style = match highlights.first() {
70+ Some(span) => theme.get(&theme.scopes()[span.0]),
74+ let mut slice = &text[start..end];
75+ // TODO: do we need to handle all unicode line endings
76+ // here, or is just '\n' okay?
77+ while let Some(end) = slice.find('\n') {
78+ // emit span up to newline
79+ let text = &slice[..end];
80+ let text = text.replace('\t', " "); // replace tabs
81+ let span = Span::styled(text, style);
84+ // truncate slice to after newline
85+ slice = &slice[end + 1..];
88+ let spans = std::mem::take(&mut spans);
89+ lines.push(Spans::from(spans));
92+ // if there's anything left, emit it too
93+ if !slice.is_empty() {
94+ let span = Span::styled(slice.replace('\t', " "), style);
101+ if !spans.is_empty() {
102+ let spans = std::mem::take(&mut spans);
103+ lines.push(Spans::from(spans));
20pub struct Markdown {
109pub struct Markdown {
21 contents: String,
110 contents: String,
@@ -101,75 +190,13 @@ impl Markdown {
101 Event::Text(text) => {
190 Event::Text(text) => {
102 // TODO: temp workaround
191 // TODO: temp workaround
103 if let Some(Tag::CodeBlock(CodeBlockKind::Fenced(language))) = tags.last() {
192 if let Some(Tag::CodeBlock(CodeBlockKind::Fenced(language))) = tags.last() {
104− if let Some(theme) = theme {
193+ let tui_text = highlighted_code_block(
105− let rope = Rope::from(text.as_ref());
194+ text.to_string(),
106− let syntax = self
195+ language,
107− .config_loader
196+ theme,
108− .language_configuration_for_injection_string(language)
197+ Arc::clone(&self.config_loader),
109− .and_then(|config| config.highlight_config(theme.scopes()))
198+ );
110− .map(|config| {
199+ lines.extend(tui_text.lines.into_iter());
111− Syntax::new(&rope, config, self.config_loader.clone())
114− if let Some(syntax) = syntax {
115− // if we have a syntax available, highlight_iter and generate spans
116− let mut highlights = Vec::new();
118− for event in syntax.highlight_iter(rope.slice(..), None, None) {
119− match event.unwrap() {
120− HighlightEvent::HighlightStart(span) => {
121− highlights.push(span);
123− HighlightEvent::HighlightEnd => {
126− HighlightEvent::Source { start, end } => {
127− let style = match highlights.first() {
128− Some(span) => theme.get(&theme.scopes()[span.0]),
132− let mut slice = &text[start..end];
133− // TODO: do we need to handle all unicode line endings
134− // here, or is just '\n' okay?
135− while let Some(end) = slice.find('\n') {
136− // emit span up to newline
137− let text = &slice[..end];
138− let text = text.replace('\t', " "); // replace tabs
139− let span = Span::styled(text, style);
142− // truncate slice to after newline
143− slice = &slice[end + 1..];
146− let spans = std::mem::take(&mut spans);
147− lines.push(Spans::from(spans));
150− // if there's anything left, emit it too
151− if !slice.is_empty() {
152− let span = Span::styled(
153− slice.replace('\t', " "),
162− for line in text.lines() {
163− let span = Span::styled(line.to_string(), code_style);
164− lines.push(Spans::from(span));
168− for line in text.lines() {
169− let span = Span::styled(line.to_string(), code_style);
170− lines.push(Spans::from(span));
174 let style = if let Some(Tag::Heading(level, ..)) = tags.last() {
201 let style = if let Some(Tag::Heading(level, ..)) = tags.last() {
175 match level {
202 match level {