use super::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct SystemPromptCard {
pub(crate) title: String,
pub(crate) content: String,
pub(crate) tokens: usize,
}
impl SystemPromptCard {
pub(crate) fn text(&self) -> ratatui::text::Text<'_> {
use ratatui::text::Line;
let mut lines = vec![
Line::from(self.title.as_str()),
Line::from(format!("~{} tokens", self.tokens)),
Line::default(),
];
lines.extend(self.content.trim_matches('\n').split('\n').map(Line::from));
lines.into()
}
pub(crate) fn text_width(card_width: u16) -> u16 {
card_width.saturating_sub(4).max(1)
}
pub(crate) fn visual_rows(&self, card_width: u16) -> usize {
ratatui::widgets::Paragraph::new(self.text())
.wrap(ratatui::widgets::Wrap { trim: false })
.line_count(Self::text_width(card_width))
.saturating_add(2)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct SystemPromptModalState {
pub(crate) content: String,
pub(crate) sections: Vec<SystemPromptCard>,
}
impl SystemPromptModalState {
pub(crate) fn visual_rows(&self, width: u16) -> usize {
self.sections.iter().fold(
crate::tui::transcript::ratatui_wrapped_visual_rows(&self.content, width.max(1)),
|rows, section| {
rows.saturating_add(1)
.saturating_add(section.visual_rows(width))
},
)
}
}
impl MissionControlState {
pub(crate) fn open_system_prompt_modal(&mut self, content: String) {
self.show_system_prompt_sections(SystemPromptModalState {
content,
sections: Vec::new(),
});
}
pub(crate) fn show_system_prompt_sections(&mut self, modal: SystemPromptModalState) {
self.modals.system_prompt_modal = Some(modal);
self.set_scroll_offset(&self.scroll_views.system_prompt, 0);
self.hide_autocomplete();
}
pub(crate) fn close_system_prompt_modal(&mut self) -> bool {
self.modals.system_prompt_modal.take().is_some()
}
pub(crate) fn system_prompt_modal_visible(&self) -> bool {
self.modals.system_prompt_modal.is_some()
}
pub(crate) fn scroll_system_prompt_up_by(
&mut self,
rows: u16,
visible_rows: u16,
wrap_width: u16,
) -> bool {
let before = self.scroll_offset(&self.scroll_views.system_prompt);
let overflow = self.system_prompt_scroll_overflow(visible_rows, wrap_width);
self.set_scroll_offset(
&self.scroll_views.system_prompt,
before.saturating_sub(usize::from(rows)).min(overflow),
);
self.scroll_offset(&self.scroll_views.system_prompt) != before
}
pub(crate) fn scroll_system_prompt_down_by(
&mut self,
rows: u16,
visible_rows: u16,
wrap_width: u16,
) -> bool {
let before = self.scroll_offset(&self.scroll_views.system_prompt);
let overflow = self.system_prompt_scroll_overflow(visible_rows, wrap_width);
self.set_scroll_offset(
&self.scroll_views.system_prompt,
before.saturating_add(usize::from(rows)).min(overflow),
);
self.scroll_offset(&self.scroll_views.system_prompt) != before
}
pub(crate) fn system_prompt_scroll_overflow(
&self,
visible_rows: u16,
wrap_width: u16,
) -> usize {
let Some(modal) = &self.modals.system_prompt_modal else {
return 0;
};
modal
.visual_rows(wrap_width)
.min(usize::from(u16::MAX))
.saturating_sub(visible_rows.max(1) as usize)
}
}