generated from GarandPLG/rust-flake-template
Refactor keybindings and add validated CLI arguments
Extracted common quit/esc handling into `common_keybindings`. Introduced `Group::CtrlMovement` for Ctrl‑arrow keys and updated keybinding definitions. Removed duplicated quit logic in main_menu and skirmish modules. Bumped clap to 4.6.0 and updated Cargo.lock. Added range‑checked parsers for map size, resources, supply limit, XP modifier and skill points in the CLI.
This commit is contained in:
Generated
+12
-12
@@ -19,9 +19,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.21"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
|
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"anstyle-parse",
|
"anstyle-parse",
|
||||||
@@ -40,9 +40,9 @@ checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-parse"
|
name = "anstyle-parse"
|
||||||
version = "0.2.7"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"utf8parse",
|
"utf8parse",
|
||||||
]
|
]
|
||||||
@@ -165,9 +165,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.60"
|
version = "4.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
|
checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -175,9 +175,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.60"
|
version = "4.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
|
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -187,9 +187,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.5.55"
|
version = "4.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
|
checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -963,9 +963,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.44"
|
version = "1.0.45"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
|
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -12,6 +12,5 @@ strip = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.5.53", features = ["derive"] }
|
clap = { version = "4.5.53", features = ["derive"] }
|
||||||
ratatui = "0.30.0"
|
ratatui = "0.30.0"
|
||||||
|
|
||||||
log = "0.4.29"
|
log = "0.4.29"
|
||||||
simplelog = "0.12.2"
|
simplelog = "0.12.2"
|
||||||
|
|||||||
+5
-7
@@ -69,21 +69,19 @@ pub fn handle_input_events(tx: mpsc::Sender<Event>) {
|
|||||||
loop {
|
loop {
|
||||||
match event::read() {
|
match event::read() {
|
||||||
Ok(ev) => match ev {
|
Ok(ev) => match ev {
|
||||||
event::Event::Key(key_event) => {
|
event::Event::Key(key) => {
|
||||||
if tx.send(Event::Input(key_event)).is_err() {
|
if tx.send(Event::Input(key)).is_err() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
event::Event::Resize(cols, rows) => {
|
event::Event::Resize(c, r) => {
|
||||||
if tx.send(Event::Resize(cols, rows)).is_err() {
|
if tx.send(Event::Resize(c, r)).is_err() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
Err(_) => {
|
Err(_) => continue,
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,16 @@ use crate::app::{
|
|||||||
};
|
};
|
||||||
use ratatui::crossterm::event::KeyEvent;
|
use ratatui::crossterm::event::KeyEvent;
|
||||||
|
|
||||||
pub fn default_keybindings(app: &mut App, key_event: &KeyEvent) {
|
pub fn common_keybindings(app: &mut App, action: Action) {
|
||||||
if let Some(action) = event_to_action(&key_event) {
|
match action {
|
||||||
match action {
|
Action::Quit | Action::Quit2 => app.exit = true,
|
||||||
Action::Quit => app.exit = true,
|
Action::Esc => app.view = View::MainMenu,
|
||||||
Action::Quit2 => app.exit = true,
|
_ => (),
|
||||||
Action::Esc => app.view = View::MainMenu,
|
}
|
||||||
_ => (),
|
}
|
||||||
}
|
|
||||||
|
pub fn default_keybindings(app: &mut App, key_event: &KeyEvent) {
|
||||||
|
if let Some(action) = event_to_action(&key_event) {
|
||||||
|
common_keybindings(app, action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ pub enum Action {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)]
|
||||||
pub enum Group {
|
pub enum Group {
|
||||||
|
CtrlMovement,
|
||||||
Movement,
|
Movement,
|
||||||
Scroll,
|
Scroll,
|
||||||
Select,
|
Select,
|
||||||
@@ -100,7 +101,7 @@ pub static KEYBINDINGS: &[KeyBinding] = &[
|
|||||||
code: KeyCode::Up,
|
code: KeyCode::Up,
|
||||||
kind: KeyEventKind::Press,
|
kind: KeyEventKind::Press,
|
||||||
modifiers: KeyModifiers::CONTROL,
|
modifiers: KeyModifiers::CONTROL,
|
||||||
group: Group::Movement,
|
group: Group::CtrlMovement,
|
||||||
symbol: "Ctrl + ↑",
|
symbol: "Ctrl + ↑",
|
||||||
description: "Scroll Up ",
|
description: "Scroll Up ",
|
||||||
},
|
},
|
||||||
@@ -109,7 +110,7 @@ pub static KEYBINDINGS: &[KeyBinding] = &[
|
|||||||
code: KeyCode::Down,
|
code: KeyCode::Down,
|
||||||
kind: KeyEventKind::Press,
|
kind: KeyEventKind::Press,
|
||||||
modifiers: KeyModifiers::CONTROL,
|
modifiers: KeyModifiers::CONTROL,
|
||||||
group: Group::Movement,
|
group: Group::CtrlMovement,
|
||||||
symbol: "Ctrl + ↓",
|
symbol: "Ctrl + ↓",
|
||||||
description: "Scroll Down",
|
description: "Scroll Down",
|
||||||
},
|
},
|
||||||
@@ -118,7 +119,7 @@ pub static KEYBINDINGS: &[KeyBinding] = &[
|
|||||||
code: KeyCode::Left,
|
code: KeyCode::Left,
|
||||||
kind: KeyEventKind::Press,
|
kind: KeyEventKind::Press,
|
||||||
modifiers: KeyModifiers::CONTROL,
|
modifiers: KeyModifiers::CONTROL,
|
||||||
group: Group::Movement,
|
group: Group::CtrlMovement,
|
||||||
symbol: "Ctrl + ←",
|
symbol: "Ctrl + ←",
|
||||||
description: "Scroll Left",
|
description: "Scroll Left",
|
||||||
},
|
},
|
||||||
@@ -127,7 +128,7 @@ pub static KEYBINDINGS: &[KeyBinding] = &[
|
|||||||
code: KeyCode::Right,
|
code: KeyCode::Right,
|
||||||
kind: KeyEventKind::Press,
|
kind: KeyEventKind::Press,
|
||||||
modifiers: KeyModifiers::CONTROL,
|
modifiers: KeyModifiers::CONTROL,
|
||||||
group: Group::Movement,
|
group: Group::CtrlMovement,
|
||||||
symbol: "Ctrl + →",
|
symbol: "Ctrl + →",
|
||||||
description: "Scroll Right",
|
description: "Scroll Right",
|
||||||
},
|
},
|
||||||
@@ -156,7 +157,7 @@ pub static KEYBINDINGS: &[KeyBinding] = &[
|
|||||||
modifiers: KeyModifiers::NONE,
|
modifiers: KeyModifiers::NONE,
|
||||||
group: Group::Movement,
|
group: Group::Movement,
|
||||||
symbol: "Esc",
|
symbol: "Esc",
|
||||||
description: "Go back",
|
description: "Go back to main menu",
|
||||||
},
|
},
|
||||||
KeyBinding {
|
KeyBinding {
|
||||||
action: Action::Backspace,
|
action: Action::Backspace,
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
use crate::app::{
|
use crate::app::{
|
||||||
App, View,
|
App, View,
|
||||||
keybindings::{Action, event_to_action},
|
keybindings::{Action, common_keybindings, event_to_action},
|
||||||
};
|
};
|
||||||
use ratatui::crossterm::event::KeyEvent;
|
use ratatui::crossterm::event::KeyEvent;
|
||||||
|
|
||||||
pub fn main_menu_keybindings(app: &mut App, event: &KeyEvent) {
|
pub fn main_menu_keybindings(app: &mut App, event: &KeyEvent) {
|
||||||
if let Some(action) = event_to_action(&event) {
|
if let Some(action) = event_to_action(&event) {
|
||||||
|
common_keybindings(app, action);
|
||||||
match action {
|
match action {
|
||||||
Action::Quit => app.exit = true,
|
|
||||||
Action::Quit2 => app.exit = true,
|
|
||||||
Action::Up => {
|
Action::Up => {
|
||||||
app.states.main_menu.selected_view =
|
app.states.main_menu.selected_view =
|
||||||
app.states.main_menu.selected_view.saturating_sub(1).max(1);
|
app.states.main_menu.selected_view.saturating_sub(1).max(1);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ pub mod keybindings;
|
|||||||
pub mod main_menu;
|
pub mod main_menu;
|
||||||
pub mod skirmish;
|
pub mod skirmish;
|
||||||
|
|
||||||
pub use default::default_keybindings;
|
pub use default::{common_keybindings, default_keybindings};
|
||||||
pub use keybindings::{Action, Group, KEYBINDINGS, KeyBinding, binding_for, event_to_action};
|
pub use keybindings::{Action, Group, KEYBINDINGS, KeyBinding, binding_for, event_to_action};
|
||||||
pub use main_menu::main_menu_keybindings;
|
pub use main_menu::main_menu_keybindings;
|
||||||
pub use skirmish::skirmish_keybindings;
|
pub use skirmish::skirmish_keybindings;
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
use crate::app::{
|
use crate::app::{
|
||||||
App, View,
|
App,
|
||||||
keybindings::{Action, event_to_action},
|
keybindings::{Action, common_keybindings, event_to_action},
|
||||||
};
|
};
|
||||||
use ratatui::crossterm::event::KeyEvent;
|
use ratatui::crossterm::event::KeyEvent;
|
||||||
|
|
||||||
pub fn skirmish_keybindings(app: &mut App, key_event: &KeyEvent) {
|
pub fn skirmish_keybindings(app: &mut App, key_event: &KeyEvent) {
|
||||||
if let Some(action) = event_to_action(&key_event) {
|
if let Some(action) = event_to_action(&key_event) {
|
||||||
|
common_keybindings(app, action);
|
||||||
match action {
|
match action {
|
||||||
Action::ScrollUp => app.states.skirmish.vertical_offset.prev(),
|
Action::ScrollUp => app.states.skirmish.vertical_offset.prev(),
|
||||||
Action::ScrollDown => app.states.skirmish.vertical_offset.next(),
|
Action::ScrollDown => app.states.skirmish.vertical_offset.next(),
|
||||||
Action::ScrollLeft => app.states.skirmish.horizontal_offset.prev(),
|
Action::ScrollLeft => app.states.skirmish.horizontal_offset.prev(),
|
||||||
Action::ScrollRight => app.states.skirmish.horizontal_offset.next(),
|
Action::ScrollRight => app.states.skirmish.horizontal_offset.next(),
|
||||||
Action::Quit => app.exit = true,
|
|
||||||
Action::Quit2 => app.exit = true,
|
|
||||||
Action::Esc => app.view = View::MainMenu,
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-11
@@ -2,7 +2,8 @@ use crate::app::{
|
|||||||
states::{GameMode, PerkDecks},
|
states::{GameMode, PerkDecks},
|
||||||
view::View,
|
view::View,
|
||||||
};
|
};
|
||||||
use clap::Parser;
|
use clap::{Error, Parser, error::ErrorKind, value_parser};
|
||||||
|
use std::num::ParseFloatError;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(version, about = "War in Tunnels", long_about = "War in Tunnels")]
|
#[command(version, about = "War in Tunnels", long_about = "War in Tunnels")]
|
||||||
@@ -37,7 +38,8 @@ pub struct Cli {
|
|||||||
long,
|
long,
|
||||||
help = "Map width",
|
help = "Map width",
|
||||||
value_name = "Positive integer [20; 100]",
|
value_name = "Positive integer [20; 100]",
|
||||||
default_value = "50"
|
default_value = "50",
|
||||||
|
value_parser = value_parser!(u8).range(20..=100)
|
||||||
)]
|
)]
|
||||||
pub map_width: u8,
|
pub map_width: u8,
|
||||||
|
|
||||||
@@ -45,7 +47,8 @@ pub struct Cli {
|
|||||||
long,
|
long,
|
||||||
help = "Map height",
|
help = "Map height",
|
||||||
value_name = "Positive integer [11; 50]",
|
value_name = "Positive integer [11; 50]",
|
||||||
default_value = "25"
|
default_value = "25",
|
||||||
|
value_parser = value_parser!(u8).range(25..=50)
|
||||||
)]
|
)]
|
||||||
pub map_height: u8,
|
pub map_height: u8,
|
||||||
|
|
||||||
@@ -61,24 +64,27 @@ pub struct Cli {
|
|||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
help = "Starting wood",
|
help = "Starting wood",
|
||||||
value_name = "Positive integer",
|
value_name = "Positive integer [1; 150]",
|
||||||
default_value = "50"
|
default_value = "50",
|
||||||
|
value_parser = value_parser!(u16).range(1..=150)
|
||||||
)]
|
)]
|
||||||
pub starting_wood: u16,
|
pub starting_wood: u16,
|
||||||
|
|
||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
help = "Starting iron",
|
help = "Starting iron",
|
||||||
value_name = "Positive integer",
|
value_name = "Positive integer [1; 150]",
|
||||||
default_value = "25"
|
default_value = "25",
|
||||||
|
value_parser = value_parser!(u16).range(1..=150)
|
||||||
)]
|
)]
|
||||||
pub starting_iron: u16,
|
pub starting_iron: u16,
|
||||||
|
|
||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
help = "Supply limit",
|
help = "Supply limit",
|
||||||
value_name = "Positive integer",
|
value_name = "Positive integer [49; 149]",
|
||||||
default_value = "99"
|
default_value = "99",
|
||||||
|
value_parser = value_parser!(u8).range(49..=149)
|
||||||
)]
|
)]
|
||||||
pub supply_limit: u8,
|
pub supply_limit: u8,
|
||||||
|
|
||||||
@@ -86,7 +92,8 @@ pub struct Cli {
|
|||||||
long,
|
long,
|
||||||
help = "XP modifier",
|
help = "XP modifier",
|
||||||
value_name = "Float [0.5; 2.0]",
|
value_name = "Float [0.5; 2.0]",
|
||||||
default_value = "1.0"
|
default_value = "1.0",
|
||||||
|
value_parser = parse_xp
|
||||||
)]
|
)]
|
||||||
pub xp_modifier: f32,
|
pub xp_modifier: f32,
|
||||||
|
|
||||||
@@ -94,7 +101,8 @@ pub struct Cli {
|
|||||||
long,
|
long,
|
||||||
help = "Skill points limit",
|
help = "Skill points limit",
|
||||||
value_name = "Positive integer [120; 690]",
|
value_name = "Positive integer [120; 690]",
|
||||||
default_value = "120"
|
default_value = "120",
|
||||||
|
value_parser = value_parser!(u16).range(120..=690)
|
||||||
)]
|
)]
|
||||||
pub skill_points_limit: u16,
|
pub skill_points_limit: u16,
|
||||||
|
|
||||||
@@ -109,3 +117,17 @@ pub struct Cli {
|
|||||||
pub fn get_args() -> Cli {
|
pub fn get_args() -> Cli {
|
||||||
Cli::parse()
|
Cli::parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_xp(s: &str) -> Result<f32, Error> {
|
||||||
|
let v: f32 = s
|
||||||
|
.parse()
|
||||||
|
.map_err(|e: ParseFloatError| Error::raw(ErrorKind::InvalidValue, e.to_string()))?;
|
||||||
|
if (0.5..=2.0).contains(&v) {
|
||||||
|
Ok(v)
|
||||||
|
} else {
|
||||||
|
Err(Error::raw(
|
||||||
|
ErrorKind::InvalidValue,
|
||||||
|
format!("Value {} is out of range 0.5..=2.0", v),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user