Skip to content

Commit 06a396e

Browse files
committed
feat: enhance machine selection and user interaction in TUI
- Add new dependencies for `skim` and `fuzzy-matcher` in `Cargo.toml` - Remove `cargo fetch` from `devbox.json` script - Refactor imports in `machine.rs` for better organization - Introduce a new `pick` module for handling machine selection - Update `mod.rs` to include the new `pick` module and handle its commands - Adjust the functionality of the TUI in `pick.rs` to enable user interaction with a list of options Signed-off-by: Trim Bresilla <trim.bresilla@gmail.com>
1 parent 8a81bad commit 06a396e

8 files changed

Lines changed: 746 additions & 108 deletions

File tree

Cargo.lock

Lines changed: 479 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ hostname = "0.4.0"
2525
regex = "1.10.5"
2626
tabled = { version = "0.15.0"}
2727
russh = "0.49.2"
28+
skim = "0.16.0"
29+
fuzzy-matcher = "0.3.7"

devbox.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
"export CARGO_HOME=$cargoHome",
1717
"export LIBRARY_PATH=$LIBRARY_PATH:\"$projectDir/.devbox/nix/profile/default/lib\"",
1818
"export PATH=$PATH:$projectDir/target/release",
19-
"cargo fetch"
2019
],
2120
"scripts": {
2221
"test": "cargo test -- --show-output",

helix_25.1.1-1_amd64.deb

14.3 MB
Binary file not shown.

src/arguments/machine.rs

Lines changed: 88 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
use clap::{Command, Arg, ArgAction};
1+
use clap::{Arg, ArgAction, Command};
22
use std::env;
33

44
extern crate interfaces;
55
use interfaces::Interface;
66

77
pub fn cmd() -> Command {
8-
98
let _username = env::var("USER").unwrap_or_else(|_| String::from("root"));
109

1110
Command::new("machine")
@@ -15,88 +14,97 @@ pub fn cmd() -> Command {
1514
.arg_required_else_help(true)
1615
.subcommand(
1716
Command::new("add")
18-
.about("Add a new machine")
19-
.aliases(["a", "new"])
20-
.arg_required_else_help(true)
21-
.arg(
22-
Arg::new("name")
23-
.help("Name of the machine")
24-
.value_name("MACHINE_NAME")
25-
)
26-
.arg(
27-
Arg::new("host")
28-
.help("ip:port:iface of the machine")
29-
.value_name("IP:PORT:IFACE")
30-
.num_args(1..=10)
31-
.action(ArgAction::Append)
32-
.value_parser(|v: &str| {
33-
34-
let ifs = Interface::get_all().expect("could not get interfaces");
17+
.about("Add a new machine")
18+
.aliases(["a", "new"])
19+
.arg_required_else_help(true)
20+
.arg(
21+
Arg::new("name")
22+
.help("Name of the machine")
23+
.value_name("MACHINE_NAME"),
24+
)
25+
.arg(
26+
Arg::new("host")
27+
.help("ip:port:iface of the machine")
28+
.value_name("IP:PORT:IFACE")
29+
.num_args(1..=10)
30+
.action(ArgAction::Append)
31+
.value_parser(|v: &str| {
32+
let ifs = Interface::get_all().expect("could not get interfaces");
3533

36-
let parts: Vec<&str> = v.split(":").collect();
37-
if parts.len() < 3 {
38-
let mut port: String = String::from("22");
39-
let mut iface: String = String::from("local");
40-
if parts[0].parse::<std::net::IpAddr>().is_err() {
41-
return Err(String::from("Invalid ip format"));
42-
}
43-
if parts.len() == 3 {
44-
if parts[1].parse::<u16>().is_err() {
45-
return Err(String::from("Invalid port format"));
46-
}
47-
port = parts[1].to_string();
48-
//chekc if iface exists in the system
49-
if !ifs.iter().any(|i| i.name == parts[2]) {
50-
return Err(String::from("Invalid iface name"));
34+
let parts: Vec<&str> = v.split(":").collect();
35+
if parts.len() < 3 {
36+
let mut port: String = String::from("22");
37+
let mut iface: String = String::from("local");
38+
if parts[0].parse::<std::net::IpAddr>().is_err() {
39+
return Err(String::from("Invalid ip format"));
40+
}
41+
if parts.len() == 3 {
42+
if parts[1].parse::<u16>().is_err() {
43+
return Err(String::from("Invalid port format"));
44+
}
45+
port = parts[1].to_string();
46+
//chekc if iface exists in the system
47+
if !ifs.iter().any(|i| i.name == parts[2]) {
48+
return Err(String::from("Invalid iface name"));
49+
}
50+
iface = parts[2].to_string();
51+
} else if parts.len() == 2 {
52+
if !ifs.iter().any(|i| i.name == parts[1]) {
53+
return Err(String::from("Invalid iface name"));
54+
}
55+
iface = parts[1].to_string();
56+
}
57+
return Ok((parts[0].to_string(), port, iface));
5158
}
52-
iface = parts[2].to_string();
53-
} else if parts.len() == 2 {
54-
if !ifs.iter().any(|i| i.name == parts[1]) {
55-
return Err(String::from("Invalid iface name"));
56-
}
57-
iface = parts[1].to_string();
58-
}
59-
return Ok((parts[0].to_string(), port, iface));
60-
}
61-
Err(String::from("Invalid ip:port format"))
62-
})
63-
)
64-
.arg(
65-
Arg::new("username")
66-
.help("Username to use for ssh")
67-
.short('u')
68-
.long("username")
69-
.value_name("USERNAME")
70-
// .default_value("root")
71-
.conflicts_with("interactive")
72-
)
73-
.arg(
74-
Arg::new("key")
75-
.help("Path to the ssh key")
76-
.short('k')
77-
.long("key")
78-
.value_name("KEY_PATH")
79-
.default_value("~/.ssh/id_rsa")
80-
)
59+
Err(String::from("Invalid ip:port format"))
60+
}),
61+
)
62+
.arg(
63+
Arg::new("username")
64+
.help("Username to use for ssh")
65+
.short('u')
66+
.long("username")
67+
.value_name("USERNAME")
68+
// .default_value("root")
69+
.conflicts_with("interactive"),
70+
)
71+
.arg(
72+
Arg::new("key")
73+
.help("Path to the ssh key")
74+
.short('k')
75+
.long("key")
76+
.value_name("KEY_PATH")
77+
.default_value("~/.ssh/id_rsa"),
78+
),
8179
)
8280
.subcommand(
8381
Command::new("list")
84-
.about("List all machines")
85-
.aliases(["l", "ls"])
86-
// .arg_required_else_help(true)
87-
.arg(
88-
Arg::new("raw")
89-
.help("Raw mode")
90-
.short('r')
91-
.long("raw")
92-
.action(ArgAction::SetTrue)
93-
)
94-
.arg(
95-
Arg::new("hosty")
96-
.help("Hostname ready mode")
97-
.short('h')
98-
.long("hosty")
99-
.action(ArgAction::SetTrue)
100-
)
82+
.about("List all machines")
83+
.aliases(["l", "ls"])
84+
// .arg_required_else_help(true)
85+
.arg(
86+
Arg::new("raw")
87+
.help("Raw mode")
88+
.short('r')
89+
.long("raw")
90+
.action(ArgAction::SetTrue),
91+
)
92+
.arg(
93+
Arg::new("hosty")
94+
.help("Hostname ready mode")
95+
.short('h')
96+
.long("hosty")
97+
.action(ArgAction::SetTrue),
98+
),
99+
)
100+
.subcommand(
101+
Command::new("pick")
102+
.about("Pick a machine")
103+
.aliases(["p", "select"])
104+
.arg(
105+
Arg::new("name")
106+
.help("Name of the machine")
107+
.value_name("MACHINE_NAME"),
108+
),
101109
)
102110
}

src/commands/machine/list.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
use crate::commands::{machine::Machines, TerminalSize};
22
extern crate directories;
3-
use directories::ProjectDirs;
43
use clap::ArgMatches;
4+
use directories::ProjectDirs;
5+
use figment::{
6+
providers::{Format, Toml},
7+
Figment,
8+
};
59
use std::path::PathBuf;
6-
use figment::{providers::{Format, Toml}, Figment};
7-
810

9-
pub fn handle(matches: ArgMatches, machines_file: PathBuf, terminal_size: TerminalSize){
11+
pub fn handle(matches: ArgMatches, machines_file: PathBuf, terminal_size: TerminalSize) {
1012
if let Some(proj_dirs) = ProjectDirs::from("com", "bresilla", "dotpilot") {
1113
proj_dirs.config_dir();
1214
}
1315
let machines: Machines = Figment::new()
1416
.merge(Toml::file(&machines_file))
15-
.extract().unwrap();
17+
.extract()
18+
.unwrap();
1619

1720
if matches.get_flag("raw") {
1821
println!("{}", machines.to_listed());

src/commands/machine/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use tabled::{
1414

1515
mod add;
1616
mod list;
17+
mod pick;
1718

1819
#[derive(Debug, Deserialize, Serialize)]
1920
struct Host {
@@ -312,6 +313,10 @@ pub fn handle(matches: ArgMatches, terminal_size: TerminalSize) {
312313
Some(("list", args)) => {
313314
list::handle(args.clone(), machines_file, terminal_size);
314315
}
316+
317+
Some(("pick", args)) => {
318+
pick::handle(args.clone(), machines_file, terminal_size);
319+
}
315320
_ => unreachable!("UNREACHABLE"),
316321
}
317322
}

0 commit comments

Comments
 (0)