fm/modes/menu/
temp_marks.rs1use std::{
2 cmp::min,
3 path::{Path, PathBuf},
4};
5
6use ratatui::{
7 layout::Rect,
8 style::Color,
9 text::Line,
10 widgets::{Paragraph, Widget},
11 Frame,
12};
13
14use crate::config::{ColorG, Gradient, MENU_STYLES};
15use crate::io::Offseted;
16use crate::log_info;
17use crate::modes::ContentWindow;
18use crate::{colored_skip_take, impl_content, impl_selectable};
19
20pub struct TempMarks {
25 content: Vec<Option<PathBuf>>,
26 pub index: usize,
27}
28
29impl Default for TempMarks {
30 fn default() -> Self {
31 let content = vec![None; Self::NB_TEMP_MARKS];
32 let index = 0;
33 Self { content, index }
34 }
35}
36
37impl TempMarks {
38 const NB_TEMP_MARKS: usize = 10;
39
40 fn log_index_error(index: usize) {
41 log_info!(
42 "index {index} is too big for a temp mark. Should be between 0 and {NB_TEMP_MARKS} excluded",
43 NB_TEMP_MARKS=Self::NB_TEMP_MARKS
44 );
45 }
46
47 pub fn set_mark(&mut self, index: usize, path: PathBuf) {
49 self.remove_path(&path);
50 if index >= Self::NB_TEMP_MARKS {
51 Self::log_index_error(index);
52 return;
53 }
54 self.content[index] = Some(path);
55 }
56
57 pub fn erase_current_mark(&mut self) {
59 self.content[self.index] = None;
60 }
61
62 pub fn get_mark(&self, index: usize) -> &Option<PathBuf> {
64 if index >= Self::NB_TEMP_MARKS {
65 Self::log_index_error(index);
66 return &None;
67 }
68 &self.content[index]
69 }
70
71 pub fn draw_menu(&self, f: &mut Frame, rect: &Rect, window: &ContentWindow) {
74 let mut p_rect = rect.offseted(2, 3);
75 p_rect.height = p_rect.height.saturating_sub(2);
76 let content = self.content();
77 let lines: Vec<_> = colored_skip_take!(content, window)
78 .filter(|(index, _, _)| {
79 (*index) as u16 + ContentWindow::WINDOW_MARGIN_TOP_U16 + 1 - window.top as u16 + 2
80 <= rect.height
81 })
82 .map(|(index, opt_path, style)| {
83 let content = if let Some(path) = opt_path {
84 format!("{index} {p}", p = path.display())
85 } else {
86 format!("{index} ")
87 };
88 Line::styled(content, self.style(index, &style))
89 })
90 .collect();
91 Paragraph::new(lines).render(p_rect, f.buffer_mut());
92 }
93
94 pub fn digit_for(&self, path: &Path) -> Option<usize> {
95 for (index, marked_path) in self.content.iter().enumerate() {
96 match marked_path {
97 Some(p) if p == path => return Some(index),
98 _ => (),
99 }
100 }
101 None
102 }
103
104 pub fn move_path(&mut self, old_path: &Path, new_path: &Path) {
107 let Some(index) = self.digit_for(old_path) else {
108 return;
109 };
110 self.set_mark(index, new_path.to_path_buf());
111 }
112
113 pub fn remove_path(&mut self, old_path: &Path) {
116 for index in 0..Self::NB_TEMP_MARKS {
117 match &self.content[index] {
118 Some(path) if path == old_path => self.content[index] = None,
119 _ => (),
120 }
121 }
122 }
123}
124
125type Opb = Option<PathBuf>;
126
127impl_content!(TempMarks, Opb);