Skip to content

Commit 9f2b824

Browse files
committed
feat: refactor item selection and improve user interaction in app
- Remove the fuzzy-matcher dependency from Cargo.toml - Simplify the pick.rs file by removing unused imports and functions - Integrate the Skim library for improved item selection - Update the handle function to utilize Skim for listing items - Adjust the run_app function to enhance user interaction and terminal management Signed-off-by: Trim Bresilla <trim.bresilla@gmail.com>
1 parent 06a396e commit 9f2b824

3 files changed

Lines changed: 21 additions & 145 deletions

File tree

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,3 @@ regex = "1.10.5"
2626
tabled = { version = "0.15.0"}
2727
russh = "0.49.2"
2828
skim = "0.16.0"
29-
fuzzy-matcher = "0.3.7"

src/commands/machine/pick.rs

Lines changed: 21 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -8,157 +8,35 @@ use figment::{
88
};
99
use std::path::PathBuf;
1010

11-
use crossterm::{
12-
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
13-
execute,
14-
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
15-
};
16-
use ratatui::{
17-
backend::CrosstermBackend,
18-
layout::{Constraint, Direction, Layout},
19-
style::{Color, Modifier, Style},
20-
text::Span,
21-
widgets::{Block, Borders, List, ListItem, ListState},
22-
Terminal,
23-
};
24-
use std::{error::Error, io};
25-
26-
/// Main event loop for our TUI
27-
fn run_app(
28-
terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
29-
menu_items: Vec<&str>,
30-
list_state: &mut ListState,
31-
) -> Result<(), Box<dyn Error>> {
32-
loop {
33-
// Draw the UI
34-
terminal.draw(|f| {
35-
let size = f.size();
36-
37-
// Split the layout if you want multiple sections, but here we just use one
38-
let chunks = Layout::default()
39-
.direction(Direction::Vertical)
40-
.margin(1)
41-
.constraints([Constraint::Min(0)].as_ref())
42-
.split(size);
43-
44-
// Prepare list items
45-
let items: Vec<ListItem> = menu_items
46-
.iter()
47-
.map(|item| ListItem::new(Span::raw(*item)))
48-
.collect();
49-
50-
// Create the list widget
51-
let list = List::new(items)
52-
.block(
53-
Block::default()
54-
.title("Ratatui List Selector")
55-
.borders(Borders::ALL),
56-
)
57-
.highlight_style(
58-
Style::default()
59-
.fg(Color::Yellow)
60-
.add_modifier(Modifier::BOLD),
61-
)
62-
.highlight_symbol(">> ");
63-
64-
// Render the stateful list widget
65-
f.render_stateful_widget(list, chunks[0], list_state);
66-
})?;
67-
68-
// Handle input
69-
if crossterm::event::poll(std::time::Duration::from_millis(100))? {
70-
if let Event::Key(key) = event::read()? {
71-
match key.code {
72-
KeyCode::Up => {
73-
// Move selection up
74-
let i = match list_state.selected() {
75-
Some(i) => {
76-
if i == 0 {
77-
menu_items.len() - 1
78-
} else {
79-
i - 1
80-
}
81-
}
82-
None => 0,
83-
};
84-
list_state.select(Some(i));
85-
}
86-
KeyCode::Down => {
87-
// Move selection down
88-
let i = match list_state.selected() {
89-
Some(i) => {
90-
if i >= menu_items.len() - 1 {
91-
0
92-
} else {
93-
i + 1
94-
}
95-
}
96-
None => 0,
97-
};
98-
list_state.select(Some(i));
99-
}
100-
KeyCode::Char('q') => {
101-
// Quit on 'q'
102-
return Ok(());
103-
}
104-
KeyCode::Enter => {
105-
// If you want to handle pressing Enter on a selection,
106-
// you could do so here.
107-
if let Some(selected) = list_state.selected() {
108-
println!("You selected: {}", menu_items[selected]);
109-
return Ok(());
110-
}
111-
}
112-
_ => {}
113-
}
114-
}
115-
}
116-
}
117-
}
118-
119-
fn run() -> Result<(), Box<dyn Error>> {
120-
// Set up the terminal
121-
enable_raw_mode()?;
122-
let mut stdout = io::stdout();
123-
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
124-
let backend = CrosstermBackend::new(stdout);
125-
let mut terminal = Terminal::new(backend)?;
126-
127-
// Create application state
128-
let menu_items = vec!["Option 1", "Option 2", "Option 3", "Option 4", "Option 5"];
129-
let mut list_state = ListState::default();
130-
// By default, select the first item
131-
list_state.select(Some(0));
11+
extern crate skim;
12+
use skim::prelude::*;
13+
use std::io::Cursor;
13214

133-
// Main loop
134-
let res = run_app(&mut terminal, menu_items, &mut list_state);
135-
136-
// Restore the terminal
137-
disable_raw_mode()?;
138-
execute!(
139-
terminal.backend_mut(),
140-
LeaveAlternateScreen,
141-
DisableMouseCapture
142-
)?;
143-
terminal.show_cursor()?;
144-
145-
// If there was an error inside the TUI, return it
146-
if let Err(err) = res {
147-
println!("{:?}", err)
148-
}
149-
150-
Ok(())
151-
}
152-
153-
pub fn handle(matches: ArgMatches, machines_file: PathBuf, terminal_size: TerminalSize) {
15+
pub fn handle(_matches: ArgMatches, machines_file: PathBuf, _terminal_size: TerminalSize) {
15416
if let Some(proj_dirs) = ProjectDirs::from("com", "bresilla", "dotpilot") {
15517
proj_dirs.config_dir();
15618
}
15719

20+
let options = SkimOptionsBuilder::default()
21+
.height(String::from("100%"))
22+
.multi(true)
23+
.build()
24+
.unwrap();
25+
15826
let machines: Machines = Figment::new()
15927
.merge(Toml::file(&machines_file))
16028
.extract()
16129
.unwrap();
16230

163-
run().unwrap();
31+
let item_reader = SkimItemReader::default();
32+
let items = item_reader.of_bufread(Cursor::new(machines.to_listed()));
33+
34+
// `run_with` would read and show items from the stream
35+
let selected_items = Skim::run_with(&options, Some(items))
36+
.map(|out| out.selected_items)
37+
.unwrap_or_else(|| Vec::new());
38+
39+
for item in selected_items.iter() {
40+
println!("{}", item.output());
41+
}
16442
}

0 commit comments

Comments
 (0)