use crate::tui::model::{
jobs::JobsModel,
query::{EditorMode, QueryModel},
};
use crate::tui::view::syntax_textarea::SyntaxTextArea;
use ratatui::{
layout::Rect,
style::{Color, Modifier, Style},
text::{Line, Span},
widgets::{Block, Borders, Clear, List, ListItem, ListState},
Frame,
};
pub fn render(f: &mut Frame, model: &QueryModel, jobs_model: &JobsModel, area: Rect) {
let mode_indicator = match model.mode {
EditorMode::Normal => " [NORMAL] ",
EditorMode::Insert => " [INSERT] ",
EditorMode::Visual => " [VISUAL] ",
};
let mode_style = match model.mode {
EditorMode::Normal => Style::default()
.fg(Color::Cyan)
.add_modifier(Modifier::BOLD),
EditorMode::Insert => Style::default()
.fg(Color::Green)
.add_modifier(Modifier::BOLD),
EditorMode::Visual => Style::default()
.fg(Color::LightMagenta)
.add_modifier(Modifier::BOLD),
};
let help_text = match model.mode {
EditorMode::Normal => {
if model.pack_context.is_some() {
" | [:PREV ]:NEXT l:LOAD i:INSERT v:VISUAL ^J:EXECUTE"
} else {
" | l:LOAD i:INSERT v:VISUAL ^J:EXECUTE ^U:UNDO ^R:REDO"
}
}
EditorMode::Insert => " | esc:NORMAL ^J:EXECUTE ^U:UNDO ^R:REDO",
EditorMode::Visual => " | y:YANK d:DELETE esc:NORMAL",
};
let mut title_spans = vec![Span::raw("Query ")];
if let Some(pack_context) = &model.pack_context {
title_spans.push(Span::styled(
format!("[Pack: {}] ", pack_context.display_string()),
Style::default().fg(Color::Green),
));
}
title_spans.push(Span::styled(mode_indicator, mode_style));
title_spans.push(Span::raw(help_text));
let block = Block::default().borders(Borders::ALL).title(title_spans);
let widget = SyntaxTextArea::new(&model.textarea).block(block);
f.render_widget(widget, area);
if let Some(panel_state) = &model.load_panel {
render_load_panel(f, panel_state, jobs_model, area);
}
}
fn render_load_panel(
f: &mut Frame,
panel_state: &crate::tui::model::query::LoadPanelState,
jobs_model: &JobsModel,
parent_area: Rect,
) {
let panel_width = (parent_area.width * 40) / 100;
let panel_area = Rect {
x: parent_area.x + parent_area.width - panel_width,
y: parent_area.y,
width: panel_width,
height: parent_area.height,
};
let sorted_indices = &panel_state.sorted_indices;
let items: Vec<ListItem> = sorted_indices
.iter()
.enumerate()
.filter_map(|(display_idx, &original_idx)| {
let job = jobs_model.jobs.get(original_idx)?;
let status_indicator = format!("[{}]", job.status.as_str());
let job_name = format!("Job #{}", original_idx + 1);
let line = Line::from(vec![
Span::styled(status_indicator, Style::default().fg(job.status.color())),
Span::raw(" "),
Span::raw(job_name),
Span::raw(" - "),
Span::raw(&job.workspace_name),
]);
let mut item = ListItem::new(line);
if display_idx == panel_state.selected {
item = item.style(Style::default().bg(Color::DarkGray));
}
Some(item)
})
.collect();
let sort_text = format!(
"Sort: {} {}",
panel_state.sort.as_str(),
if panel_state.inverted { "↓" } else { "↑" }
);
let title = format!("Load Query ({}) | {}", sorted_indices.len(), sort_text);
let list = List::new(items).block(
Block::default()
.borders(Borders::ALL)
.title(title)
.title_bottom("↑↓:Navigate Tab:Sort i:Invert Enter:Load Esc:Cancel")
.style(Style::default().bg(Color::Black)),
);
let mut list_state = ListState::default();
list_state.select(Some(panel_state.selected));
f.render_widget(Clear, panel_area);
f.render_stateful_widget(list, panel_area, &mut list_state);
}