use ratatui::Frame;
use ratatui::layout::Rect;
use ratatui::style::Modifier;
use ratatui::text::{Line, Span};
use ratatui::widgets::Paragraph;
use super::super::{panel, wrap};
use crate::tui::app::App;
use crate::tui::lib_fields;
use crate::tui::theme;
pub fn draw(f: &mut Frame, app: &App, area: Rect) {
let Some(recipe) = app.lib.config_recipe() else {
f.render_widget(panel("SETTINGS ─".into(), true), area);
return;
};
let edited = app.lib.overrides.len() + app.lib.removed.len();
let title = if edited == 0 {
format!("{} ─ SETTINGS ─", recipe.id.to_uppercase())
} else {
format!(
"{} ─ SETTINGS ─ {edited} changed ─",
recipe.id.to_uppercase()
)
};
let block = panel(title, true);
let inner = block.inner(area);
f.render_widget(block, area);
let width = inner.width.saturating_sub(4) as usize;
let mut head: Vec<Line> = Vec::new();
head.push(Line::from(vec![
Span::styled(" model ", theme::dim()),
Span::styled(recipe.model.clone(), theme::text()),
]));
if let Some(provenance) = &recipe.starting_point {
head.push(Line::from(Span::styled(
format!(" starting point — {provenance}; unverified on this model"),
theme::warn(),
)));
}
if let Some(borrowed) = &app.lib.borrowed {
head.push(Line::from(Span::styled(
format!(" borrowed — values from {borrowed}; not a measurement for this model"),
theme::warn(),
)));
}
head.push(Line::from(""));
let mut body: Vec<Line> = Vec::new();
let mut anchor_end = 0usize;
for (i, row) in app.lib.config_rows().into_iter().enumerate() {
let selected = i == app.lib.row;
let editing = selected && app.lib.editing && app.lib.pending_add.is_none();
let marker = if selected { "▌" } else { " " };
let (change_mark, mark_style) = if row.removed {
("✗", theme::dim())
} else if row.added {
("+", theme::brand_green())
} else if row.changed {
("•", theme::brand_green())
} else {
(" ", theme::dim())
};
let value_style = if editing {
theme::brand_cyan().add_modifier(Modifier::BOLD)
} else if row.removed {
theme::dim().add_modifier(Modifier::DIM)
} else if row.changed {
theme::brand_green()
} else {
theme::text()
};
let shown = if editing {
format!("{}▏", app.lib.edit_buffer)
} else if row.removed {
match lib_fields::spec_for_key(&row.key).and_then(|s| s.default.clone()) {
Some(d) => format!("removed — server default {d}"),
None => "removed — flag not passed".to_string(),
}
} else {
row.value.clone()
};
let key_style = if row.removed {
theme::dim().add_modifier(Modifier::DIM | Modifier::CROSSED_OUT)
} else {
theme::text2()
};
let mut line = Line::from(vec![
Span::styled(marker, theme::brand_purple()),
Span::styled(change_mark, mark_style),
Span::styled(format!(" {:<26}", row.key), key_style),
Span::styled(shown, value_style),
]);
if selected {
line = line.style(theme::selected());
}
body.push(line);
if let Some(err) = app.lib.error.as_ref().filter(|_| selected && !editing) {
body.extend(wrap(&format!(" {err}"), width, theme::error()));
}
if selected {
anchor_end = body.len();
}
}
if let (Some(key), true) = (&app.lib.pending_add, app.lib.editing) {
body.push(
Line::from(vec![
Span::styled("▌", theme::brand_purple()),
Span::styled("+", theme::brand_green()),
Span::styled(format!(" {key:<26}"), theme::text2()),
Span::styled(
format!("{}▏", app.lib.edit_buffer),
theme::brand_cyan().add_modifier(Modifier::BOLD),
),
])
.style(theme::selected()),
);
anchor_end = body.len();
}
let mut tail: Vec<Line> = vec![Line::from("")];
match app.lib.preview_argv() {
Some(argv) => {
tail.push(Line::from(Span::styled(" COMMAND", theme::dim())));
let rendered = argv.iter().skip(1).cloned().collect::<Vec<_>>().join(" ");
tail.extend(wrap(&format!("met {rendered}"), width, theme::text2()));
}
None => tail.push(Line::from(Span::styled(
" this recipe cannot be launched from here",
theme::warn(),
))),
}
let body_h = (inner.height as usize)
.saturating_sub(head.len() + tail.len())
.max(1);
let off = anchor_end.saturating_sub(body_h);
let mut lines = head;
lines.extend(body.into_iter().skip(off).take(body_h));
lines.extend(tail);
f.render_widget(Paragraph::new(lines), inner);
}