fm/modes/menu/
temp_marks.rs

1use std::{cmp::min, path::PathBuf};
2
3use ratatui::{
4    layout::Rect,
5    style::Color,
6    text::Line,
7    widgets::{Paragraph, Widget},
8    Frame,
9};
10
11use crate::config::{ColorG, Gradient, MENU_STYLES};
12use crate::io::Offseted;
13use crate::log_info;
14use crate::modes::ContentWindow;
15use crate::{colored_skip_take, impl_content, impl_selectable};
16
17/// Temporary marks are saved in memory and reset when the application quit.
18///
19/// We save a fixed size vector of pathbufs.
20/// The user can set a mark (default bind alt+") and jump to it (default bind ").
21pub struct TempMarks {
22    content: Vec<Option<PathBuf>>,
23    pub index: usize,
24}
25
26impl Default for TempMarks {
27    fn default() -> Self {
28        let content = vec![None; Self::NB_TEMP_MARKS];
29        let index = 0;
30        Self { content, index }
31    }
32}
33
34impl TempMarks {
35    const NB_TEMP_MARKS: usize = 10;
36
37    fn log_index_error(index: usize) {
38        log_info!(
39            "index {index} is too big for a temp mark. Should be between 0 and {NB_TEMP_MARKS} exclusive", 
40            NB_TEMP_MARKS=Self::NB_TEMP_MARKS
41        );
42    }
43
44    /// Set the mark at given index to the given path.
45    pub fn set_mark(&mut self, index: usize, path: PathBuf) {
46        if index >= Self::NB_TEMP_MARKS {
47            Self::log_index_error(index);
48            return;
49        }
50        self.content[index] = Some(path);
51    }
52
53    /// Reset the selected mark to `None`
54    pub fn erase_current_mark(&mut self) {
55        self.content[self.index] = None;
56    }
57
58    /// Get the indexed mark. `None` if the mark isn't set.
59    pub fn get_mark(&self, index: usize) -> &Option<PathBuf> {
60        if index >= Self::NB_TEMP_MARKS {
61            Self::log_index_error(index);
62            return &None;
63        }
64        &self.content[index]
65    }
66
67    /// Render the marks on the screen.
68    /// Can't use the common trait nor the macro since `Option<PathBuf>` doesn't implement `CowStr`.
69    pub fn draw_menu(&self, f: &mut Frame, rect: &Rect, window: &ContentWindow) {
70        let mut p_rect = rect.offseted(2, 3);
71        p_rect.height = p_rect.height.saturating_sub(2);
72        let content = self.content();
73        let lines: Vec<_> = colored_skip_take!(content, window)
74            .filter(|(index, _, _)| {
75                (*index) as u16 + ContentWindow::WINDOW_MARGIN_TOP_U16 + 1 - window.top as u16 + 2
76                    <= rect.height
77            })
78            .map(|(index, opt_path, style)| {
79                let content = if let Some(path) = opt_path {
80                    format!("{index} {p}", p = path.display())
81                } else {
82                    format!("{index} ")
83                };
84                Line::styled(content, self.style(index, &style))
85            })
86            .collect();
87        Paragraph::new(lines).render(p_rect, f.buffer_mut());
88    }
89}
90
91type Opb = Option<PathBuf>;
92
93impl_selectable!(TempMarks);
94impl_content!(TempMarks, Opb);