use ratatui::text::Span;
use crate::{
formats::json::chat::ChatRole, load::ViewFile, transform::FormatKind,
tui::palette::gutter_style,
};
use super::footer::gutter_digits;
const WRAP_GUTTER_MINOR_TICK_ROWS: usize = 8;
const WRAP_GUTTER_MAJOR_TICK_ROWS: usize = 64;
const CHAT_ROLE_GUTTER_WIDTH: usize = 12;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(in crate::viewer) struct GutterLayout {
line_digits: usize,
chat_role: bool,
}
impl GutterLayout {
pub(in crate::viewer) fn new(line_digits: usize, chat_role: bool) -> Self {
Self {
line_digits,
chat_role: chat_role && line_digits > 0,
}
}
pub(in crate::viewer) fn for_view(
file: &dyn ViewFile,
selection_mode: bool,
mode: FormatKind,
) -> Self {
let line_digits = gutter_digits(file, selection_mode);
Self::new(
line_digits,
matches!(mode, FormatKind::Json | FormatKind::Jsonl),
)
}
pub(in crate::viewer) fn width(self) -> usize {
self.line_number_width()
.saturating_add(self.chat_role_width())
}
pub(in crate::viewer) fn content_start(self) -> usize {
self.width()
}
pub(in crate::viewer) fn line_number(self, line_number: usize) -> Span<'static> {
if self.line_digits == 0 {
return Span::raw("");
}
Span::styled(
format!("{line_number:>width$} │ ", width = self.line_digits),
gutter_style(),
)
}
pub(in crate::viewer) fn continuation(self, row_index: usize) -> Span<'static> {
if self.line_digits == 0 {
return Span::raw("");
}
let marker = continuation_gutter_marker(row_index);
Span::styled(
format!("{:>width$} {marker} ", "", width = self.line_digits),
gutter_style(),
)
}
pub(in crate::viewer) fn chat_role(self, role: Option<ChatRole>) -> Span<'static> {
if !self.chat_role {
return Span::raw("");
}
match role {
Some(role) => Span::styled(format!("{:<9} │ ", role.label()), role.style()),
None => Span::styled(format!("{:<9} │ ", ""), gutter_style()),
}
}
pub(in crate::viewer) fn chat_role_enabled(self) -> bool {
self.chat_role
}
fn line_number_width(self) -> usize {
if self.line_digits == 0 {
0
} else {
self.line_digits + 3
}
}
fn chat_role_width(self) -> usize {
if self.chat_role {
CHAT_ROLE_GUTTER_WIDTH
} else {
0
}
}
}
#[cfg(test)]
pub(in crate::viewer) fn line_number_gutter(
line_number: usize,
gutter_digits: usize,
) -> Span<'static> {
GutterLayout::new(gutter_digits, false).line_number(line_number)
}
#[cfg(test)]
pub(in crate::viewer) fn continuation_gutter(
row_index: usize,
gutter_digits: usize,
) -> Span<'static> {
GutterLayout::new(gutter_digits, false).continuation(row_index)
}
pub(in crate::viewer) fn continuation_gutter_marker(row_index: usize) -> char {
if row_index > 0 && row_index % WRAP_GUTTER_MAJOR_TICK_ROWS == 0 {
'┠'
} else if row_index > 0 && row_index % WRAP_GUTTER_MINOR_TICK_ROWS == 0 {
'┊'
} else {
'┆'
}
}