use {
super::*,
crate::verb::{
Internal,
VerbStore,
},
};
pub struct StandardStatus {
tree_top_focus: String, tree_dir_focus: String,
tree_dir_cd: Option<String>, tree_file_open_stay: Option<String>,
tree_file_open_stay_long: Option<String>,
tree_file_open_leave: Option<String>,
tree_unfiltered: String,
tree_filtered: String,
preview_unfiltered: String, preview_filtered: Option<String>,
preview_restorable_filter: Option<String>,
not_first_state: String, help: String,
no_verb: String,
pub all_files_hidden: Option<String>,
pub all_files_ignored: Option<String>,
}
impl StandardStatus {
#[must_use]
pub fn new(verb_store: &VerbStore) -> Self {
let tree_top_focus = "*enter* to go up".to_string(); let tree_dir_focus = "*enter* to focus".to_string();
let tree_dir_cd = verb_store
.key_desc_of_internal_stype(Internal::open_leave, SelectionType::Directory)
.map(|k| format!("*{k}* to cd"));
let tree_file_open_stay = verb_store
.key_desc_of_internal_stype(Internal::open_stay, SelectionType::File)
.map(|k| format!("*{k}* to open"));
let tree_file_open_stay_long = verb_store
.key_desc_of_internal_stype(Internal::open_stay, SelectionType::File)
.map(|k| format!("*{k}* to open the file"));
let tree_file_open_leave = verb_store
.key_desc_of_internal_stype(Internal::open_leave, SelectionType::File)
.map(|k| format!("*{k}* to open and quit"));
let tree_unfiltered = "a few letters to search".to_string();
let tree_filtered = "*esc* to clear the filter".to_string();
let preview_unfiltered = "a pattern to filter".to_string();
let preview_filtered = verb_store
.key_desc_of_internal(Internal::panel_right)
.map(|k| format!("*{k}* to reveal the text"));
let preview_restorable_filter = verb_store
.key_desc_of_internal(Internal::panel_left_no_open)
.map(|k| format!("*{k}* to restore the filter"));
let not_first_state = "*esc* to go back".to_string();
let help = "*?* for help".to_string();
let no_verb = "a space then a verb".to_string();
let all_files_hidden = verb_store
.key_desc_of_internal(Internal::toggle_hidden)
.map(|k| format!("Some files are hidden, use *{k}* to display them"));
let all_files_ignored = verb_store
.key_desc_of_internal(Internal::toggle_ignore)
.or(verb_store.key_desc_of_internal(Internal::toggle_git_ignore))
.map(|k| format!("Some files are ignored, use *{k}* to display them"));
Self {
tree_top_focus,
tree_dir_focus,
tree_dir_cd,
tree_file_open_stay,
tree_file_open_stay_long,
tree_file_open_leave,
tree_unfiltered,
tree_filtered,
preview_unfiltered,
preview_filtered,
preview_restorable_filter,
not_first_state,
help,
no_verb,
all_files_hidden,
all_files_ignored,
}
}
#[must_use]
pub fn builder<'s>(
&'s self,
state_type: PanelStateType,
selection: Selection<'s>,
width: usize, ) -> StandardStatusBuilder<'s> {
StandardStatusBuilder::new(self, state_type, selection, width)
}
}
#[derive(Default)]
struct StatusParts<'b> {
md_parts: Vec<&'b str>,
}
impl<'b> StatusParts<'b> {
fn add(
&mut self,
md: &'b str,
) {
self.md_parts.push(md);
}
fn addo(
&mut self,
md: &'b Option<String>,
) {
if let Some(md) = md {
self.md_parts.push(md);
}
}
fn len(&self) -> usize {
self.md_parts.len()
}
fn to_status(
&self,
available_width: usize,
) -> Status {
let mut md = String::new();
let mut sum_len = 0;
let max_len = available_width + 3;
for (i, p) in self.md_parts.iter().enumerate() {
let sep = if i == 0 {
"Hit "
} else if i == self.md_parts.len() - 1 {
", or "
} else {
", "
};
sum_len += sep.len() + p.len() - 2; if i > 0 && sum_len > max_len {
break;
}
md.push_str(sep);
md.push_str(p);
}
Status::from_message(md)
}
}
pub struct StandardStatusBuilder<'s> {
ss: &'s StandardStatus,
state_type: PanelStateType,
selection: Selection<'s>,
pub has_previous_state: bool,
pub is_filtered: bool,
pub has_removed_pattern: bool,
pub on_tree_root: bool, pub width: usize, }
impl<'s> StandardStatusBuilder<'s> {
fn new(
ss: &'s StandardStatus,
state_type: PanelStateType,
selection: Selection<'s>,
width: usize, ) -> Self {
Self {
ss,
state_type,
selection,
has_previous_state: true,
is_filtered: false,
has_removed_pattern: false,
on_tree_root: false,
width,
}
}
pub fn status(self) -> Status {
let ss = &self.ss;
let mut parts = StatusParts::default();
if self.has_previous_state && !self.is_filtered {
parts.add(&ss.not_first_state);
}
match self.state_type {
PanelStateType::Tree => {
if self.on_tree_root {
if self.selection.path.file_name().is_some() {
parts.add(&ss.tree_top_focus);
}
} else if self.selection.stype == SelectionType::Directory {
parts.add(&ss.tree_dir_focus);
parts.addo(&ss.tree_dir_cd);
} else if self.selection.stype == SelectionType::File {
if self.width > 105 {
parts.addo(&ss.tree_file_open_stay_long);
} else {
parts.addo(&ss.tree_file_open_stay);
}
parts.addo(&ss.tree_file_open_leave);
}
if self.is_filtered {
parts.add(&ss.tree_filtered);
}
if parts.len() < 3 {
parts.add(&ss.help);
}
if parts.len() < 4 {
if self.on_tree_root && !self.is_filtered {
parts.add(&ss.tree_unfiltered);
} else {
parts.add(&ss.no_verb);
}
}
}
PanelStateType::Preview => {
if self.is_filtered {
parts.addo(&ss.preview_filtered);
} else if self.has_removed_pattern {
parts.addo(&ss.preview_restorable_filter);
} else {
parts.add(&ss.preview_unfiltered);
}
parts.add(&ss.no_verb);
}
PanelStateType::Help => {
if parts.len() < 4 {
parts.add(&ss.no_verb);
}
}
PanelStateType::Fs => {
}
PanelStateType::Stage => {
}
PanelStateType::Trash => {
}
}
parts.to_status(self.width)
}
}