#[allow(clippy::wildcard_imports)]
use super::*;
pub(in crate::app) fn render_form_picker(
app: &App,
picker: &FormPicker,
f: &mut ratatui::Frame,
area: Rect,
bindings: &EffectiveBindings,
) {
let rect = crate::ui::modal::modal_rect(area);
let picker_rect = Rect::new(
rect.x.saturating_add(2),
rect.y.saturating_add(2),
rect.width.saturating_sub(4).max(10),
rect.height.saturating_sub(4).max(5),
);
f.render_widget(Clear, picker_rect);
let mut lines = Vec::new();
lines.push(Line::from(format!("Filter: {}", picker.state.filter)));
lines.push(Line::from(""));
if picker.state.mode == PickerMode::InlineCreate {
lines.push(Line::from(Span::styled(
format!("Create: {}_", picker.state.create_buffer),
Style::default().fg(Color::Yellow),
)));
} else {
let visible = picker.state.visible_indices();
for (pos, idx) in visible.into_iter().take(8).enumerate() {
let item = &picker.state.options[idx];
let selected = match &picker.state.selection {
SelectionModel::Single(current) => current.as_deref() == Some(item.id.as_str()),
SelectionModel::Multi(current) => current.contains(&item.id),
};
let cursor = if pos == picker.state.cursor { ">" } else { " " };
let mark = if selected { "[x]" } else { "[ ]" };
lines.push(Line::from(format!("{cursor} {mark} {}", item.label)));
}
}
lines.push(Line::from(""));
let create_hint = if picker.field.allows_inline_create() {
format!(
" | {} create",
bindings.label(
InputContext::FormPicker,
crate::keybindings::TuiAction::Create
)
)
} else {
String::new()
};
lines.push(Line::from(Span::styled(
format!(
"{}/{} close | {} select{create_hint}",
bindings.label(
InputContext::FormPicker,
crate::keybindings::TuiAction::OpenPicker
),
bindings.label(
InputContext::FormPicker,
crate::keybindings::TuiAction::Cancel
),
bindings.label(
InputContext::FormPicker,
crate::keybindings::TuiAction::Submit
),
),
Style::default().fg(Color::DarkGray),
)));
let title = match picker.field {
FormPickerField::Status => "Status picker",
FormPickerField::Priority => "Priority picker",
FormPickerField::Labels => "Labels picker",
FormPickerField::Assignee => "Assignee picker",
FormPickerField::Cycles => "Cycles picker",
FormPickerField::Milestones => "Milestones picker",
FormPickerField::Reviewer => "Reviewer picker",
FormPickerField::Parent => "Parent picker",
FormPickerField::Project => "Projects picker",
FormPickerField::Epic => "Epics picker",
FormPickerField::Template => "Template picker",
};
let para = Paragraph::new(lines).block(Block::default().borders(Borders::ALL).title(title));
f.render_widget(para, picker_rect);
if picker.field == FormPickerField::Template && picker.state.mode != PickerMode::InlineCreate {
for (pos, _idx) in picker
.state
.visible_indices()
.into_iter()
.take(8)
.enumerate()
{
let row = Rect {
x: picker_rect.x.saturating_add(1),
y: picker_rect
.y
.saturating_add(3)
.saturating_add(u16::try_from(pos).unwrap_or(0)),
width: picker_rect.width.saturating_sub(2),
height: 1,
};
app.record_region(row, Action::TemplatePickOption(pos));
}
}
}
#[allow(clippy::too_many_arguments)]
pub(in crate::app) fn render_edit_repair(
app: &App,
f: &mut ratatui::Frame,
area: Rect,
filename: &str,
message: &str,
key: Option<&str>,
problems: &[EditProblem],
temp: Option<&std::path::Path>,
discard_armed: bool,
) {
let label = |action| app.bindings.label(InputContext::EditRepair, action);
render_board(app, f, area, commandbar::MODE_BOARD);
let rect = crate::ui::modal::modal_rect(area);
f.render_widget(Clear, rect);
let mut lines = vec![
Line::from(Span::styled("Edit Repair", Style::default().fg(Color::Red))),
Line::from(Span::raw(filename.to_string())),
];
if problems.is_empty() {
lines.push(Line::from(Span::styled(
message.to_string(),
Style::default().fg(Color::Yellow),
)));
} else {
for problem in problems {
lines.push(Line::from(Span::styled(
problem.message.clone(),
Style::default().fg(Color::Yellow),
)));
lines.push(Line::from(Span::styled(
format!("\u{2192} {}", problem.proposal_text()),
Style::default().fg(Color::Green),
)));
}
}
if let Some(key) = key {
lines.push(Line::from(Span::styled(
format!(
"{}: declare `{key}` in [custom_attributes] in tix.toml",
label(crate::keybindings::TuiAction::Confirm)
),
Style::default().fg(Color::Green),
)));
}
lines.push(Line::from(""));
lines.push(Line::from(Span::styled(
format!(
"{}: apply the fix · {}: re-edit · {}: ignore",
label(crate::keybindings::TuiAction::Confirm),
label(crate::keybindings::TuiAction::Reedit),
label(crate::keybindings::TuiAction::Ignore),
),
Style::default().fg(Color::DarkGray),
)));
let discard = if discard_armed {
format!(
"{}: press again to discard the retained copy",
label(crate::keybindings::TuiAction::Discard)
)
} else {
format!(
"{}: discard the edit (asks again)",
label(crate::keybindings::TuiAction::Discard)
)
};
let retained = match temp {
Some(path) => format!("retained copy: {}", path.display()),
None => "the edit is already on disk".to_string(),
};
lines.push(Line::from(Span::styled(
format!("{discard} · {retained}"),
Style::default().fg(Color::Red),
)));
let para = Paragraph::new(lines).wrap(Wrap { trim: true }).block(
Block::default()
.borders(Borders::ALL)
.title("Edit Repair")
.style(Style::default().fg(Color::Red)),
);
f.render_widget(para, rect);
}
pub(in crate::app) fn render_edit_conflict(
app: &App,
f: &mut ratatui::Frame,
area: Rect,
filename: &str,
temp: &std::path::Path,
disk_path: &std::path::Path,
) {
render_board(app, f, area, commandbar::MODE_BOARD);
let rect = crate::ui::modal::modal_rect(area);
f.render_widget(Clear, rect);
let mut lines = vec![
Line::from(Span::styled(
"The issue changed on disk while the editor was open",
Style::default().fg(Color::Red),
)),
Line::from(Span::raw(filename.to_string())),
Line::from(Span::styled(
format!("your edit: {}", temp.display()),
Style::default().fg(Color::Yellow),
)),
Line::from(Span::styled(
format!("on disk (new): {}", disk_path.display()),
Style::default().fg(Color::Yellow),
)),
Line::from(Span::styled(
"nothing has been written yet".to_string(),
Style::default().fg(Color::DarkGray),
)),
Line::from(""),
];
for action in [TuiAction::Confirm, TuiAction::Ignore, TuiAction::Reedit] {
lines.push(Line::from(format!(
"{}: {}",
app.bindings.label(InputContext::EditConflict, action),
action.description_in(InputContext::EditConflict)
)));
}
let para = Paragraph::new(lines).wrap(Wrap { trim: true }).block(
Block::default()
.borders(Borders::ALL)
.title("Edit Conflict")
.style(Style::default().fg(Color::Red)),
);
f.render_widget(para, rect);
}