feat: Improve markdown rendering with enhanced line wrapping and indentation for code blocks
This commit is contained in:
+2
-3
@@ -18,7 +18,7 @@
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::style::{Color, Style, Modifier};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Block, BorderType, Borders, Paragraph, Wrap};
|
||||
use ratatui::widgets::{Block, BorderType, Borders, Paragraph};
|
||||
use ratatui::Frame;
|
||||
use super::theme::Theme;
|
||||
use crate::dto::chat::message::Role;
|
||||
@@ -253,8 +253,7 @@ pub fn draw_chat(frame: &mut Frame, area: Rect, state: &crate::app::state::rest:
|
||||
|
||||
let paragraph = Paragraph::new(visible)
|
||||
.block(block)
|
||||
.style(Style::default().bg(Theme::BG))
|
||||
.wrap(Wrap { trim: false });
|
||||
.style(Style::default().bg(Theme::BG));
|
||||
|
||||
frame.render_widget(paragraph, area);
|
||||
}
|
||||
|
||||
+48
-16
@@ -120,8 +120,9 @@ pub fn render_markdown(text: &str, width: u16) -> Vec<Span<'static>> {
|
||||
pulldown_cmark::Event::Text(text) => {
|
||||
let s = text.to_string();
|
||||
if in_code_block {
|
||||
let indented = format!(" {}", s.replace('\n', "\n "));
|
||||
spans.push(Span::styled(
|
||||
format!(" {s}"),
|
||||
indented,
|
||||
Style::default().fg(Theme::ACCENT_TEAL).bg(Theme::CODE_BG),
|
||||
));
|
||||
} else if in_heading {
|
||||
@@ -164,23 +165,54 @@ pub fn render_markdown(text: &str, width: u16) -> Vec<Span<'static>> {
|
||||
let mut line_len = 0;
|
||||
let effective_width = (width as usize).saturating_sub(2); // leave margin
|
||||
|
||||
for span in &spans {
|
||||
for span in spans {
|
||||
let style = span.style;
|
||||
let s = span.content.clone();
|
||||
let text_str = s.as_ref();
|
||||
let remaining = text_str.len();
|
||||
|
||||
if line_len + remaining > effective_width && line_len > 0 {
|
||||
spans_out.push(Span::raw("\n"));
|
||||
line_len = 0;
|
||||
let text = span.content.as_ref();
|
||||
|
||||
let mut current = String::new();
|
||||
let mut tokens = Vec::new();
|
||||
for c in text.chars() {
|
||||
if c == ' ' {
|
||||
if !current.is_empty() { tokens.push(current.clone()); current.clear(); }
|
||||
tokens.push(" ".to_string());
|
||||
} else if c == '\n' {
|
||||
if !current.is_empty() { tokens.push(current.clone()); current.clear(); }
|
||||
tokens.push("\n".to_string());
|
||||
} else {
|
||||
current.push(c);
|
||||
}
|
||||
}
|
||||
|
||||
spans_out.push(Span::styled(text_str.to_string(), style));
|
||||
|
||||
if text_str.contains('\n') {
|
||||
line_len = text_str.split('\n').next_back().unwrap_or("").len();
|
||||
} else {
|
||||
line_len += remaining;
|
||||
if !current.is_empty() { tokens.push(current); }
|
||||
|
||||
for token in tokens {
|
||||
if token == "\n" {
|
||||
spans_out.push(Span::styled("\n", style));
|
||||
line_len = 0;
|
||||
} else if token == " " {
|
||||
if line_len > 0 && line_len < effective_width {
|
||||
spans_out.push(Span::styled(" ", style));
|
||||
line_len += 1;
|
||||
}
|
||||
} else {
|
||||
let token_len = token.chars().count();
|
||||
if line_len + token_len > effective_width && line_len > 0 {
|
||||
spans_out.push(Span::raw("\n"));
|
||||
line_len = 0;
|
||||
}
|
||||
if token_len > effective_width {
|
||||
for c in token.chars() {
|
||||
if line_len >= effective_width {
|
||||
spans_out.push(Span::raw("\n"));
|
||||
line_len = 0;
|
||||
}
|
||||
spans_out.push(Span::styled(c.to_string(), style));
|
||||
line_len += 1;
|
||||
}
|
||||
} else {
|
||||
spans_out.push(Span::styled(token, style));
|
||||
line_len += token_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
spans = spans_out;
|
||||
|
||||
Reference in New Issue
Block a user