use ratatui::widgets::{Block, Borders, Paragraph, Clear, Scrollbar, ScrollbarState, ScrollbarOrientation};
use ratatui::style::Style;
use ratatui::Frame;
use ratatui::layout::{Rect, Alignment, Constraint, Layout, Flex, Direction};
use ratatui::text::{Text, Line, Span};
use crate::Config;
use crate::tui::widgets::color::parse_color;
use ratskin::RatSkin;
use termimad::minimad::Text as MinimadText;
use std::cmp;
pub fn render_markdown_help(f: &mut Frame, area: Rect, config: &Config, example_scroll: usize, rendered_scroll: usize) {
let active_theme = config.get_active_theme();
let fg_color = parse_color(&active_theme.fg);
let bg_color = parse_color(&active_theme.bg);
let popup_area = popup_area(area, 90, 85);
f.render_widget(Clear, popup_area);
let outer_block = Block::default()
.borders(Borders::ALL)
.title("Markdown Help")
.title_alignment(Alignment::Center)
.style(Style::default().fg(fg_color).bg(bg_color));
let inner_area = outer_block.inner(popup_area);
f.render_widget(outer_block, popup_area);
let columns = Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Percentage(50), Constraint::Percentage(50), ])
.split(inner_area);
let example_area = columns[0];
let rendered_area = columns[1];
let example_text = get_example_markdown();
let example_lines: Vec<&str> = example_text.lines().collect();
let example_total_lines = example_lines.len();
let example_viewport_height = example_area.height.saturating_sub(2) as usize;
let example_max_scroll = example_total_lines.saturating_sub(example_viewport_height);
let example_scroll = cmp::min(example_scroll, example_max_scroll);
let example_start = example_scroll;
let example_end = cmp::min(example_start + example_viewport_height, example_total_lines);
let visible_example_lines = if example_start < example_total_lines {
example_lines[example_start..example_end].join("\n")
} else {
String::new()
};
let (example_content_area, example_scrollbar_area) = if example_total_lines > example_viewport_height {
let horizontal = Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Min(1),
Constraint::Length(1), ])
.split(example_area);
(horizontal[0], Some(horizontal[1]))
} else {
(example_area, None)
};
let example_paragraph = Paragraph::new(visible_example_lines)
.block(Block::default()
.borders(Borders::ALL)
.title("Example")
.title_alignment(Alignment::Center)
.style(Style::default().fg(fg_color).bg(bg_color)))
.style(Style::default().fg(fg_color).bg(bg_color))
.wrap(ratatui::widgets::Wrap { trim: false });
f.render_widget(example_paragraph, example_content_area);
if let Some(scrollbar_area) = example_scrollbar_area {
if scrollbar_area.width > 0 && example_content_area.height > 2 {
let scrollbar_inner_area = Rect::new(
scrollbar_area.x,
example_content_area.y + 1,
scrollbar_area.width,
example_content_area.height.saturating_sub(2),
);
if scrollbar_inner_area.width > 0 && scrollbar_inner_area.height > 0 {
let mut scrollbar_state = ScrollbarState::new(example_total_lines)
.viewport_content_length(example_viewport_height)
.position(example_scroll);
let scrollbar = Scrollbar::new(ScrollbarOrientation::VerticalRight)
.begin_symbol(Some("↑"))
.end_symbol(Some("↓"))
.track_symbol(Some("│"))
.thumb_symbol("█");
f.render_stateful_widget(scrollbar, scrollbar_inner_area, &mut scrollbar_state);
}
}
}
let text_width = (rendered_area.width.saturating_sub(2)) as usize;
let text_width_u16: u16 = text_width.try_into().unwrap_or(u16::MAX);
let content_text_input = MinimadText::from(example_text.as_str());
let content_lines = RatSkin::default().parse(content_text_input, text_width_u16);
let ratatui_lines: Vec<Line> = content_lines.into_iter().map(|line| {
let spans: Vec<Span> = line.spans.into_iter().map(|span| {
Span::styled(
span.content.to_string(),
span.style
)
}).collect();
Line::from(spans)
}).collect();
let rendered_text = Text::from(ratatui_lines);
let rendered_total_lines = rendered_text.lines.len();
let rendered_viewport_height = rendered_area.height.saturating_sub(2) as usize;
let rendered_max_scroll = rendered_total_lines.saturating_sub(rendered_viewport_height);
let rendered_scroll = cmp::min(rendered_scroll, rendered_max_scroll);
let rendered_start = rendered_scroll;
let rendered_end = cmp::min(rendered_start + rendered_viewport_height, rendered_total_lines);
let visible_rendered_text = if rendered_start < rendered_total_lines {
Text::from(rendered_text.lines[rendered_start..rendered_end].to_vec())
} else {
Text::default()
};
let (rendered_content_area, rendered_scrollbar_area) = if rendered_total_lines > rendered_viewport_height {
let horizontal = Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Min(1),
Constraint::Length(1), ])
.split(rendered_area);
(horizontal[0], Some(horizontal[1]))
} else {
(rendered_area, None)
};
let base_style = Style::default().fg(fg_color);
let rendered_paragraph = Paragraph::new(visible_rendered_text)
.block(Block::default()
.borders(Borders::ALL)
.title("Rendered")
.title_alignment(Alignment::Center)
.style(Style::default().fg(fg_color).bg(bg_color)))
.style(base_style)
.wrap(ratatui::widgets::Wrap { trim: false });
f.render_widget(rendered_paragraph, rendered_content_area);
if let Some(scrollbar_area) = rendered_scrollbar_area {
if scrollbar_area.width > 0 && rendered_content_area.height > 2 {
let scrollbar_inner_area = Rect::new(
scrollbar_area.x,
rendered_content_area.y + 1,
scrollbar_area.width,
rendered_content_area.height.saturating_sub(2),
);
if scrollbar_inner_area.width > 0 && scrollbar_inner_area.height > 0 {
let mut scrollbar_state = ScrollbarState::new(rendered_total_lines)
.viewport_content_length(rendered_viewport_height)
.position(rendered_scroll);
let scrollbar = Scrollbar::new(ScrollbarOrientation::VerticalRight)
.begin_symbol(Some("↑"))
.end_symbol(Some("↓"))
.track_symbol(Some("│"))
.thumb_symbol("█");
f.render_stateful_widget(scrollbar, scrollbar_inner_area, &mut scrollbar_state);
}
}
}
}
fn popup_area(area: Rect, percent_x: u16, percent_y: u16) -> Rect {
let vertical = Layout::vertical([Constraint::Percentage(percent_y)]).flex(Flex::Center);
let horizontal = Layout::horizontal([Constraint::Percentage(percent_x)]).flex(Flex::Center);
let [area] = vertical.areas(area);
let [area] = horizontal.areas(area);
area
}
pub fn get_example_markdown() -> String {
r#"# Heading 1
## Heading 2
**Bold Text**
*Italicized Test*
***Bold and Iitalics***
**Ordered List**
1. Item 1
2. Item 2
1. Sub-Item 1
**Unordered List**
* Item 1
* Item 2
* Item 1
**Unordered List **
- Item 1
- Sub-Item 1
- Sub-Item 2
- Item 2
```
//Code Block
int i = 0;
```
|:-:|-
|**feature**|**details**|
|-:|-
| tables | pipe based, with or without alignments
| italic, bold | star based |
| inline code | `with backquotes` (it works in tables too)
| code bloc |with tabs or code fences
| crossed text| ~~like this~~
| horizontal rule | Use 3 or more dashes (`---`)
| lists |* unordered lists supported
| |* ordered lists *not* supported
| quotes |> What a wonderful time to be alive!
|-"#.to_string()
}