mirror of
https://github.com/ChrisTitusTech/linutil.git
synced 2024-12-25 04:49:44 +00:00
Refactor various components of Rust code (#490)
* refactor: Simplify hint code, replacing while loop with fold iterator * refactor: Add spacing to lines in a separate function * refactor: Replace if let with map_or for better readability * refactor: Remove unnecessary duplicate body from is_cmd function * refactor: Create generic function to replace duplicate get_selected code * refactor: Remove duplicate code, remove unnecessary nesting * refactor: Move style into its own variable * refactor: Use constants for min width and height * refactor: Remove pointless duplicate variable --------- Co-authored-by: Chris Titus <contact@christitus.com>
This commit is contained in:
parent
a747f80c85
commit
a5b3df0776
|
@ -50,15 +50,7 @@ impl Float {
|
|||
|
||||
pub fn draw(&mut self, frame: &mut Frame, parent_area: Rect) {
|
||||
let popup_area = self.floating_window(parent_area);
|
||||
|
||||
let content_area = Rect {
|
||||
x: popup_area.x,
|
||||
y: popup_area.y,
|
||||
width: popup_area.width,
|
||||
height: popup_area.height,
|
||||
};
|
||||
|
||||
self.content.draw(frame, content_area);
|
||||
self.content.draw(frame, popup_area);
|
||||
}
|
||||
|
||||
// Returns true if the floating window is finished.
|
||||
|
|
|
@ -20,6 +20,15 @@ pub struct Shortcut {
|
|||
pub desc: &'static str,
|
||||
}
|
||||
|
||||
fn add_spacing(list: Vec<Vec<Span>>) -> Line {
|
||||
list.into_iter()
|
||||
.flat_map(|mut s| {
|
||||
s.push(Span::default().content(" "));
|
||||
s
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn span_vec_len(span_vec: &[Span]) -> usize {
|
||||
span_vec.iter().rfold(0, |init, s| init + s.width())
|
||||
}
|
||||
|
@ -29,15 +38,14 @@ impl ShortcutList {
|
|||
.title(self.scope_name)
|
||||
.borders(Borders::all());
|
||||
let inner_area = area.inner(Margin::new(1, 1));
|
||||
let mut shortcut_list: Vec<Vec<Span>> = self.hints.iter().map(|h| h.to_spans()).collect();
|
||||
let shortcut_spans: Vec<Vec<Span>> = self.hints.iter().map(|h| h.to_spans()).collect();
|
||||
|
||||
let mut lines = vec![Line::default(); SHORTCUT_LINES];
|
||||
let mut idx = 0;
|
||||
let mut lines: Vec<Line> = Vec::with_capacity(SHORTCUT_LINES);
|
||||
|
||||
while idx < SHORTCUT_LINES - 1 {
|
||||
let split_idx = shortcut_list
|
||||
let shortcut_list = (0..SHORTCUT_LINES - 1).fold(shortcut_spans, |mut acc, _| {
|
||||
let split_idx = acc
|
||||
.iter()
|
||||
.scan(0usize, |total_len, s| {
|
||||
.scan(0_usize, |total_len, s| {
|
||||
*total_len += span_vec_len(s);
|
||||
if *total_len > inner_area.width as usize {
|
||||
None
|
||||
|
@ -47,25 +55,13 @@ impl ShortcutList {
|
|||
}
|
||||
})
|
||||
.count();
|
||||
let new_shortcut_list = shortcut_list.split_off(split_idx);
|
||||
let line: Vec<_> = shortcut_list
|
||||
.into_iter()
|
||||
.flat_map(|mut s| {
|
||||
s.push(Span::default().content(" "));
|
||||
s
|
||||
})
|
||||
.collect();
|
||||
shortcut_list = new_shortcut_list;
|
||||
lines[idx] = line.into();
|
||||
idx += 1;
|
||||
}
|
||||
lines[idx] = shortcut_list
|
||||
.into_iter()
|
||||
.flat_map(|mut s| {
|
||||
s.push(Span::default().content(" "));
|
||||
s
|
||||
})
|
||||
.collect();
|
||||
|
||||
let new_shortcut_list = acc.split_off(split_idx);
|
||||
lines.push(add_spacing(acc));
|
||||
|
||||
new_shortcut_list
|
||||
});
|
||||
lines.push(add_spacing(shortcut_list));
|
||||
|
||||
let p = Paragraph::new(lines).block(block);
|
||||
frame.render_widget(p, area);
|
||||
|
|
|
@ -17,6 +17,9 @@ use ratatui::{
|
|||
Frame,
|
||||
};
|
||||
|
||||
const MIN_WIDTH: u16 = 77;
|
||||
const MIN_HEIGHT: u16 = 19;
|
||||
|
||||
pub struct AppState {
|
||||
/// Selected theme
|
||||
theme: Theme,
|
||||
|
@ -72,16 +75,14 @@ impl AppState {
|
|||
}
|
||||
pub fn draw(&mut self, frame: &mut Frame) {
|
||||
let terminal_size = frame.area();
|
||||
let min_width = 77; // Minimum width threshold
|
||||
let min_height = 19; // Minimum height threshold
|
||||
|
||||
if terminal_size.width < min_width || terminal_size.height < min_height {
|
||||
if terminal_size.width < MIN_WIDTH || terminal_size.height < MIN_HEIGHT {
|
||||
let size_warning_message = format!(
|
||||
"Terminal size too small:\nWidth = {} Height = {}\n\nMinimum size:\nWidth = {} Height = {}",
|
||||
terminal_size.width,
|
||||
terminal_size.height,
|
||||
min_width,
|
||||
min_height,
|
||||
MIN_WIDTH,
|
||||
MIN_HEIGHT,
|
||||
);
|
||||
|
||||
let warning_paragraph = Paragraph::new(size_warning_message.clone())
|
||||
|
@ -230,6 +231,12 @@ impl AppState {
|
|||
},
|
||||
));
|
||||
|
||||
let style = if let Focus::List = self.focus {
|
||||
Style::default().reversed()
|
||||
} else {
|
||||
Style::new()
|
||||
};
|
||||
|
||||
// Create the list widget with items
|
||||
let list = List::new(items)
|
||||
.highlight_style(if let Focus::List = self.focus {
|
||||
|
@ -259,12 +266,12 @@ impl AppState {
|
|||
pub fn handle_key(&mut self, key: &KeyEvent) -> bool {
|
||||
// This should be defined first to allow closing
|
||||
// the application even when not drawable ( If terminal is small )
|
||||
if matches!(self.focus, Focus::TabList | Focus::List) {
|
||||
if key.code == KeyCode::Char('q')
|
||||
|| key.code == KeyCode::Char('c') && key.modifiers.contains(KeyModifiers::CONTROL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Exit on 'q' or 'Ctrl-c' input
|
||||
if matches!(self.focus, Focus::TabList | Focus::List)
|
||||
&& (key.code == KeyCode::Char('q')
|
||||
|| key.modifiers.contains(KeyModifiers::CONTROL) && key.code == KeyCode::Char('c'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If UI is not drawable returning true will mark as the key handled
|
||||
|
@ -303,20 +310,11 @@ impl AppState {
|
|||
self.focus = Focus::List;
|
||||
}
|
||||
}
|
||||
|
||||
Focus::Search => match self.filter.handle_key(key) {
|
||||
SearchAction::Exit => self.exit_search(),
|
||||
SearchAction::Update => self.update_items(),
|
||||
_ => {}
|
||||
},
|
||||
|
||||
_ if key.code == KeyCode::Char('q')
|
||||
|| key.code == KeyCode::Char('c')
|
||||
&& key.modifiers.contains(KeyModifiers::CONTROL) =>
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Focus::TabList => match key.code {
|
||||
KeyCode::Enter | KeyCode::Char('l') | KeyCode::Right => self.focus = Focus::List,
|
||||
|
||||
|
@ -337,7 +335,6 @@ impl AppState {
|
|||
KeyCode::Char('T') => self.theme.prev(),
|
||||
_ => {}
|
||||
},
|
||||
|
||||
Focus::List if key.kind != KeyEventKind::Release => match key.code {
|
||||
KeyCode::Char('j') | KeyCode::Down => self.selection.select_next(),
|
||||
KeyCode::Char('k') | KeyCode::Up => self.selection.select_previous(),
|
||||
|
@ -358,7 +355,6 @@ impl AppState {
|
|||
KeyCode::Char(' ') if self.multi_select => self.toggle_selection(),
|
||||
_ => {}
|
||||
},
|
||||
|
||||
_ => (),
|
||||
};
|
||||
true
|
||||
|
@ -410,7 +406,7 @@ impl AppState {
|
|||
self.selection.select(Some(0));
|
||||
self.update_items();
|
||||
}
|
||||
pub fn get_selected_command(&self) -> Option<Command> {
|
||||
fn get_selected_node(&self) -> Option<&ListNode> {
|
||||
let mut selected_index = self.selection.selected().unwrap_or(0);
|
||||
|
||||
if !self.at_root() && selected_index == 0 {
|
||||
|
@ -422,27 +418,17 @@ impl AppState {
|
|||
|
||||
if let Some(item) = self.filter.item_list().get(selected_index) {
|
||||
if !item.has_children {
|
||||
return Some(item.node.command.clone());
|
||||
return Some(&item.node);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
fn get_selected_description(&mut self) -> Option<String> {
|
||||
let mut selected_index = self.selection.selected().unwrap_or(0);
|
||||
|
||||
if !self.at_root() && selected_index == 0 {
|
||||
return None;
|
||||
}
|
||||
if !self.at_root() {
|
||||
selected_index = selected_index.saturating_sub(1);
|
||||
}
|
||||
|
||||
if let Some(item) = self.filter.item_list().get(selected_index) {
|
||||
if !item.has_children {
|
||||
return Some(item.node.description.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
pub fn get_selected_command(&self) -> Option<Command> {
|
||||
self.get_selected_node().map(|node| node.command.clone())
|
||||
}
|
||||
fn get_selected_description(&self) -> Option<String> {
|
||||
self.get_selected_node()
|
||||
.map(|node| node.description.clone())
|
||||
}
|
||||
pub fn go_to_selected_dir(&mut self) {
|
||||
let mut selected_index = self.selection.selected().unwrap_or(0);
|
||||
|
@ -475,29 +461,14 @@ impl AppState {
|
|||
selected_index = selected_index.saturating_sub(1);
|
||||
}
|
||||
|
||||
if let Some(item) = self.filter.item_list().get(selected_index) {
|
||||
item.has_children
|
||||
} else {
|
||||
false
|
||||
}
|
||||
self.filter
|
||||
.item_list()
|
||||
.get(selected_index)
|
||||
.map_or(false, |item| item.has_children)
|
||||
}
|
||||
|
||||
pub fn selected_item_is_cmd(&self) -> bool {
|
||||
let mut selected_index = self.selection.selected().unwrap_or(0);
|
||||
|
||||
if !self.at_root() && selected_index == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
if !self.at_root() {
|
||||
selected_index = selected_index.saturating_sub(1);
|
||||
}
|
||||
|
||||
if let Some(item) = self.filter.item_list().get(selected_index) {
|
||||
!item.has_children
|
||||
} else {
|
||||
false
|
||||
}
|
||||
!self.selected_item_is_dir()
|
||||
}
|
||||
pub fn selected_item_is_up_dir(&self) -> bool {
|
||||
let selected_index = self.selection.selected().unwrap_or(0);
|
||||
|
|
Loading…
Reference in New Issue
Block a user