ced/src/ui/central_panel/line_numbers.rs

98 lines
2.8 KiB
Rust
Raw Normal View History

2025-07-05 14:42:45 -04:00
use eframe::egui;
fn format_line_number(line_number: usize, line_side: bool, line_count_width: usize) -> String {
if line_side {
format!("{:<width$}", line_number, width = line_count_width)
} else {
format!("{:>width$}", line_number, width = line_count_width)
2025-07-05 14:42:45 -04:00
}
}
pub(super) fn calculate_visual_line_mapping(
2025-07-05 14:42:45 -04:00
ui: &egui::Ui,
content: &str,
available_width: f32,
font_id: egui::FontId,
2025-07-05 14:42:45 -04:00
) -> Vec<Option<usize>> {
let mut visual_lines = Vec::new();
for (line_num, line) in content.lines().enumerate() {
if line.is_empty() {
visual_lines.push(Some(line_num + 1));
continue;
}
let galley = ui.fonts(|fonts| {
fonts.layout(
line.to_string(),
2025-07-16 17:20:09 -04:00
font_id.to_owned(),
2025-07-05 14:42:45 -04:00
egui::Color32::WHITE,
available_width - font_id.size,
2025-07-05 14:42:45 -04:00
)
});
let wrapped_line_count = galley.rows.len().max(1);
visual_lines.push(Some(line_num + 1));
for _ in 1..wrapped_line_count {
visual_lines.push(None);
}
}
if content.ends_with('\n') && !content.is_empty() {
let line_num = content.lines().count();
visual_lines.push(Some(line_num + 1));
}
2025-07-05 14:42:45 -04:00
visual_lines
}
pub(super) fn render_line_numbers(
ui: &mut egui::Ui,
line_count: usize,
visual_line_mapping: &[Option<usize>],
line_number_width: f32,
word_wrap: bool,
line_side: bool,
2025-07-05 14:42:45 -04:00
font_size: f32,
) {
ui.vertical(|ui| {
ui.disable();
2025-07-05 14:42:45 -04:00
ui.set_width(line_number_width);
ui.spacing_mut().item_spacing.y = 0.0;
ui.add_space(2.0); // Text Editor default top margin
2025-07-05 14:42:45 -04:00
let text_color = ui.visuals().weak_text_color();
let bg_color = ui.visuals().extreme_bg_color;
let line_numbers_rect = ui.available_rect_before_wrap();
ui.painter().rect_filled(line_numbers_rect, 0.0, bg_color);
2025-07-05 14:42:45 -04:00
let font_id = egui::FontId::monospace(font_size);
let line_count_width = line_count.to_string().len();
let line_texts = if word_wrap {
visual_line_mapping
.into_iter()
.map(|line_number_opt| {
line_number_opt.map_or_else(
|| " ".repeat(line_count_width),
|line_number| format_line_number(line_number, line_side, line_count_width),
)
})
.collect::<Vec<_>>()
2025-07-05 14:42:45 -04:00
} else {
(1..=line_count)
.map(|i| format_line_number(i, line_side, line_count_width))
.collect::<Vec<_>>()
};
for text in line_texts {
ui.label(
egui::RichText::new(text)
.font(font_id.to_owned())
.color(text_color),
);
2025-07-05 14:42:45 -04:00
}
});
}