use ratatui::{
Frame,
layout::Rect,
style::{Color, Style},
text::{Line, Span},
widgets::Paragraph,
};
use crate::tui::state::{AppMode, AppState, TableMode, TextMode};
pub fn render(frame: &mut Frame, area: Rect, state: &AppState) {
if let Some(ref loading) = state.cmdline.loading {
let line = Line::from(Span::styled(
loading.as_str(),
Style::default().fg(Color::Yellow),
));
frame.render_widget(Paragraph::new(vec![line]), area);
return;
}
if let Some(ref err) = state.cmdline.error {
let line = Line::from(Span::styled(
format!("{err}"),
Style::default().fg(Color::Red),
));
frame.render_widget(Paragraph::new(vec![line]), area);
return;
}
if let Some(ref form) = state.form {
let line = match form.text_mode {
TextMode::Normal => Line::from(Span::styled(
" NORMAL ",
Style::default().fg(Color::Magenta).bold(),
)),
TextMode::Insert => Line::from(Span::styled(
" INSERT ",
Style::default().fg(Color::Green).bold(),
)),
};
frame.render_widget(Paragraph::new(vec![line]), area);
return;
}
let mut spans: Vec<Span> = vec![];
let mut right_text = String::new();
match state.mode {
AppMode::Home => {
spans.push(Span::styled(
" NORMAL ",
Style::default().fg(Color::Magenta).bold(),
));
}
AppMode::Dashboard => {
if let Some(tab) = state.active_tab() {
let active_id = tab.tree.active_pane;
let active = tab.tree.panes.get(&active_id);
let (mode_label, mode_color) = if let Some(pane) = active {
if pane.kind == crate::tui::state::PaneType::QueryEditor
&& pane.query_visual_anchor.is_some()
{
if pane.query_visual_line_mode {
(" VISUAL LINE ", Color::Yellow)
} else {
(" VISUAL ", Color::Yellow)
}
} else {
match pane.mode {
TableMode::Normal => (" NORMAL ", Color::Magenta),
TableMode::VisualRow | TableMode::VisualColumn => {
(" VISUAL ", Color::Yellow)
}
TableMode::Insert => (" INSERT ", Color::Green),
}
}
} else {
(" NORMAL ", Color::Magenta)
};
spans.push(Span::styled(
mode_label,
Style::default().fg(mode_color).bold(),
));
if !state.tabs.is_empty() {
spans.push(Span::styled(" ", Style::default()));
for (i, tab) in state.tabs.iter().enumerate() {
let active_pane = tab.tree.panes.get(&tab.tree.active_pane);
let type_name = active_pane.map_or("list", |p| match p.kind {
crate::tui::state::PaneType::TableList => "list",
crate::tui::state::PaneType::SchemaPicker => "schema",
crate::tui::state::PaneType::TableView => "table",
crate::tui::state::PaneType::SchemaView => "schema",
crate::tui::state::PaneType::QueryEditor => "editor",
crate::tui::state::PaneType::QueryResults => "results",
});
let is_active = i == state.active_tab;
let style = if is_active {
Style::default().fg(Color::White).bold()
} else {
Style::default().fg(Color::DarkGray)
};
let suffix = if is_active { "*" } else { "" };
spans.push(Span::styled(format!("{i}:{type_name}{suffix}"), style));
spans.push(Span::styled(" ", Style::default()));
}
}
if let Some(pane) = active {
if let Some(ref search) = pane.last_search {
if !search.matches.is_empty() {
right_text =
format!("[{}/{}]", search.current_idx + 1, search.matches.len());
}
}
if pane.kind == crate::tui::state::PaneType::TableView
|| pane.kind == crate::tui::state::PaneType::QueryResults
{
let (headers, rows) = match pane.kind {
crate::tui::state::PaneType::TableView => {
if let Some(ref name) = pane.bound_table {
if let Some(ref loaded) = state.table_cache.get(name) {
(
loaded.headers.len(),
pane.total_table_rows(loaded.rows.len()),
)
} else {
(0, 0)
}
} else {
(0, 0)
}
}
crate::tui::state::PaneType::QueryResults => {
if let Some(idx) = pane.bound_query_idx {
if let Some(ref qr) = tab.query_results.get(idx) {
(qr.headers.len(), qr.rows.len())
} else {
(0, 0)
}
} else {
(0, 0)
}
}
_ => (0, 0),
};
if headers > 0 {
let row_pos = if rows == 0 {
0
} else {
pane.row_cursor.min(rows.saturating_sub(1)) + 1
};
let col_pos = pane.cursor_col.min(headers.saturating_sub(1)) + 1;
let pos_text =
format!("Row {}/{}, Col {}/{}", row_pos, rows, col_pos, headers);
if right_text.is_empty() {
right_text = pos_text;
} else {
right_text = format!("{} {}", right_text, pos_text);
}
}
}
}
} else {
spans.push(Span::styled(
" NORMAL ",
Style::default().fg(Color::Blue).bold(),
));
}
}
}
let conn_text = state.connection.as_ref().map(|c| format!(" {} ", c.name));
let right_width =
right_text.chars().count() + conn_text.as_ref().map_or(0, |s| s.chars().count());
let left_width: usize = spans.iter().map(|s| s.width()).sum();
let gap = (area.width as usize)
.saturating_sub(left_width)
.saturating_sub(right_width);
if gap > 0 {
spans.push(Span::styled(" ".repeat(gap), Style::default()));
}
if !right_text.is_empty() {
spans.push(Span::styled(
right_text,
Style::default().fg(Color::DarkGray),
));
}
if let Some(text) = conn_text {
spans.push(Span::styled(text, Style::default().fg(Color::Green)));
}
let line = Line::from(spans);
frame.render_widget(Paragraph::new(vec![line]), area);
}