Use b for building and r for recruitment
Nix package / build (push) Successful in 8m22s
Linux package builds (test) / linux (push) Successful in 2m17s
Rust checks / check (push) Successful in 3m20s
Linux package builds (test) / aur (push) Successful in 7m34s

- Replace Ctrl+Space with `b` and Alt+Space with `r` in README and
  documentation.
- Remove the old Alt+Space recruitment keybinding and adjust key
  handling code.
- Revamp skirmish view to display colored lines and updated status
  messages.
- Increase test suite to 83 tests and update test expectations for new
  shortcuts.
- Update flake.lock with the latest revision and hash.
This commit is contained in:
GarandPLG committed 2026-10-23 11:29:25 +02:00
1 parent 73f544d5d6
commit 6c1141a711
12 files changed
+169 -95

No files matched your search

+2 -2
View File
@@ -82,8 +82,8 @@ fn key_release_does_not_trigger_quit() {
fn music_keys_send_commands_without_opening_audio_device() {
let (mut app, rx) = app();
press(&mut app, KeyCode::Char('m'));
press(&mut app, KeyCode::Char('b'));
press(&mut app, KeyCode::Char('n'));
press(&mut app, KeyCode::Char('+'));
press(&mut app, KeyCode::Char('-'));
assert!(matches!(rx.try_recv().unwrap(), AudioCmd::Mute));
assert!(matches!(rx.try_recv().unwrap(), AudioCmd::VolumeUp));
assert!(matches!(rx.try_recv().unwrap(), AudioCmd::VolumeDown));
+3 -3
View File
@@ -145,7 +145,7 @@ fn construction_view_starts_paid_build_on_enter_and_stays_open() -> () {
}
handle_keybindings(
&mut app,
KeyEvent::new(KeyCode::Char(' '), KeyModifiers::CONTROL),
KeyEvent::new(KeyCode::Char('b'), KeyModifiers::NONE),
);
assert!(
available_skirmish_actions(&app.states_ref().unwrap().skirmish).contains(&Action::Enter)
@@ -361,7 +361,7 @@ fn panel_shows_progress_and_delete_cancels_while_escape_only_closes_panel() -> (
}
handle_keybindings(
&mut app,
KeyEvent::new(KeyCode::Char(' '), KeyModifiers::CONTROL),
KeyEvent::new(KeyCode::Char('b'), KeyModifiers::NONE),
);
handle_keybindings(&mut app, KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE));
assert!(
@@ -395,7 +395,7 @@ fn panel_shows_progress_and_delete_cancels_while_escape_only_closes_panel() -> (
));
handle_keybindings(
&mut app,
KeyEvent::new(KeyCode::Char(' '), KeyModifiers::CONTROL),
KeyEvent::new(KeyCode::Char('b'), KeyModifiers::NONE),
);
handle_keybindings(&mut app, KeyEvent::new(KeyCode::Delete, KeyModifiers::NONE));
assert!(matches!(
+53 -8
View File
@@ -5,6 +5,7 @@ use ratatui::{
buffer::Cell,
crossterm::event::{KeyCode, KeyEvent, KeyModifiers},
layout::Rect,
style::Color,
};
use std::sync::mpsc::{Receiver, Sender, channel};
use war_in_tunnels::{
@@ -45,7 +46,7 @@ fn selecting_miner_switches_help_and_escape_cancels_only_the_route() -> () {
assert!(actions.contains(&Action::Delete));
assert!(!actions.contains(&Action::Building));
assert!(!actions.contains(&Action::ZoomIn));
press(&mut app, KeyCode::Char(' '), KeyModifiers::CONTROL);
press(&mut app, KeyCode::Char('b'), KeyModifiers::NONE);
assert!(!app.states_ref().unwrap().skirmish.building_view);
press(&mut app, KeyCode::Esc, KeyModifiers::NONE);
assert_eq!(app.view, View::Skirmish);
@@ -72,7 +73,7 @@ fn building_view_has_its_own_help_and_does_not_build_on_invalid_tile() -> () {
let mut app: App = app();
let before: war_in_tunnels::app::states::skirmish_states::BoardState =
app.states_ref().unwrap().skirmish.board.clone();
press(&mut app, KeyCode::Char(' '), KeyModifiers::CONTROL);
press(&mut app, KeyCode::Char('b'), KeyModifiers::NONE);
assert!(app.states_ref().unwrap().skirmish.building_view);
assert_eq!(
available_skirmish_actions(&app.states_ref().unwrap().skirmish),
@@ -109,13 +110,17 @@ fn building_view_has_its_own_help_and_does_not_build_on_invalid_tile() -> () {
}
#[test]
fn legacy_control_space_and_quit_work_in_building_view() -> () {
fn building_key_toggles_panel_and_old_shortcuts_do_not_open_it() -> () {
let mut app: App = app();
press(&mut app, KeyCode::Null, KeyModifiers::NONE);
assert!(app.states_ref().unwrap().skirmish.building_view);
press(&mut app, KeyCode::Null, KeyModifiers::CONTROL);
press(&mut app, KeyCode::Char(' '), KeyModifiers::CONTROL);
press(&mut app, KeyCode::Char(' '), KeyModifiers::ALT);
assert!(!app.states_ref().unwrap().skirmish.building_view);
press(&mut app, KeyCode::Null, KeyModifiers::NONE);
press(&mut app, KeyCode::Char('b'), KeyModifiers::NONE);
assert!(app.states_ref().unwrap().skirmish.building_view);
press(&mut app, KeyCode::Char('b'), KeyModifiers::NONE);
assert!(!app.states_ref().unwrap().skirmish.building_view);
press(&mut app, KeyCode::Char('b'), KeyModifiers::NONE);
press(&mut app, KeyCode::Char('c'), KeyModifiers::CONTROL);
assert!(app.exit);
}
@@ -138,7 +143,7 @@ fn contextual_help_fits_normal_terminal_and_changes_when_route_is_selected() ->
.iter()
.map(|cell: &Cell| -> &str { cell.symbol() })
.collect();
assert!(text.contains("Ctrl + Space - Build"));
assert!(text.contains("b - Build"));
assert!(text.contains("Space - Select miner"));
press(&mut app, KeyCode::Char(' '), KeyModifiers::NONE);
terminal
@@ -155,6 +160,46 @@ fn contextual_help_fits_normal_terminal_and_changes_when_route_is_selected() ->
.collect();
assert!(text.contains("Space - Confirm route"));
assert!(text.contains("Esc - Cancel route"));
assert!(!text.contains("Ctrl + Space"));
assert!(!text.contains("b - Build"));
assert!(!text.contains("Zoom in"));
}
#[test]
fn construction_and_recruitment_popups_render_semantic_text_colors() -> () {
for (key, name, status, status_color) in [
('b', "Mine", "Construction unavailable", Color::Red),
('r', "Miner", "Enter: queue Miner", Color::Green),
] {
let mut app: App = app();
if key == 'r' {
press(&mut app, KeyCode::Left, KeyModifiers::NONE);
}
press(&mut app, KeyCode::Char(key), KeyModifiers::NONE);
let mut terminal: Terminal<TestBackend> = Terminal::new(TestBackend::new(160, 40)).unwrap();
terminal
.draw(|frame: &mut ratatui::Frame<'_>| -> () {
frame.render_widget(&mut app, frame.area());
})
.unwrap();
let cells: &[Cell] = &terminal.backend().buffer().content;
for (text, color) in [
(name, Color::Yellow),
("Cost:", Color::Yellow),
(status, status_color),
] {
assert!(
cells.windows(text.len()).any(|window: &[Cell]| -> bool {
window
.iter()
.map(|cell: &Cell| -> &str { cell.symbol() })
.collect::<String>()
== text
&& window
.iter()
.all(|cell: &Cell| -> bool { cell.fg == color })
}),
"missing colored text: {text}"
);
}
}
}
+10 -8
View File
@@ -234,7 +234,7 @@ fn recruitment_panel_queues_with_enter_shows_ready_state_and_closes_without_losi
available_skirmish_actions(&app.states_ref().unwrap().skirmish)
.contains(&Action::Recruitment)
);
press(&mut app, KeyCode::Char(' '), KeyModifiers::ALT);
press(&mut app, KeyCode::Char('r'), KeyModifiers::NONE);
assert!(app.states_ref().unwrap().skirmish.recruitment_view);
press(&mut app, KeyCode::Enter, KeyModifiers::NONE);
press(&mut app, KeyCode::Enter, KeyModifiers::NONE);
@@ -246,7 +246,7 @@ fn recruitment_panel_queues_with_enter_shows_ready_state_and_closes_without_losi
!available_skirmish_actions(&app.states_ref().unwrap().skirmish).contains(&Action::Enter)
);
press(&mut app, KeyCode::Right, KeyModifiers::NONE);
press(&mut app, KeyCode::Char(' '), KeyModifiers::CONTROL);
press(&mut app, KeyCode::Char('b'), KeyModifiers::NONE);
assert_eq!(
app.states_ref()
.unwrap()
@@ -281,8 +281,8 @@ fn recruitment_panel_queues_with_enter_shows_ready_state_and_closes_without_losi
press(&mut app, KeyCode::Esc, KeyModifiers::NONE);
assert!(!app.states_ref().unwrap().skirmish.recruitment_view);
assert_eq!(app.view, View::Skirmish);
press(&mut app, KeyCode::Char(' '), KeyModifiers::ALT);
press(&mut app, KeyCode::Char(' '), KeyModifiers::ALT);
press(&mut app, KeyCode::Char('r'), KeyModifiers::NONE);
press(&mut app, KeyCode::Char('r'), KeyModifiers::NONE);
assert!(!app.states_ref().unwrap().skirmish.recruitment_view);
assert_eq!(
base(&app.states_ref().unwrap().skirmish, (5, 2)).queued_miners(),
@@ -295,13 +295,13 @@ fn recruitment_panel_is_unavailable_off_base_and_during_route_selection() -> ()
let mut app: App = app();
press(&mut app, KeyCode::Char('r'), KeyModifiers::NONE);
assert!(!app.states_ref().unwrap().skirmish.recruitment_view);
press(&mut app, KeyCode::Char(' '), KeyModifiers::ALT);
press(&mut app, KeyCode::Char('r'), KeyModifiers::NONE);
assert!(!app.states_ref().unwrap().skirmish.recruitment_view);
press(&mut app, KeyCode::Left, KeyModifiers::NONE);
press(&mut app, KeyCode::Char(' '), KeyModifiers::NONE);
press(&mut app, KeyCode::Char('r'), KeyModifiers::NONE);
assert!(!app.states_ref().unwrap().skirmish.recruitment_view);
press(&mut app, KeyCode::Char(' '), KeyModifiers::ALT);
press(&mut app, KeyCode::Char('r'), KeyModifiers::NONE);
assert!(!app.states_ref().unwrap().skirmish.recruitment_view);
assert!(
app.states_ref()
@@ -312,15 +312,17 @@ fn recruitment_panel_is_unavailable_off_base_and_during_route_selection() -> ()
.marking_cells
);
press(&mut app, KeyCode::Esc, KeyModifiers::NONE);
press(&mut app, KeyCode::Char(' '), KeyModifiers::ALT);
press(&mut app, KeyCode::Char('r'), KeyModifiers::NONE);
press(&mut app, KeyCode::Char('c'), KeyModifiers::CONTROL);
assert!(app.exit);
}
#[test]
fn recruitment_fallback_opens_queues_and_closes_on_own_base() -> () {
fn recruitment_key_opens_queues_and_closes_on_own_base() -> () {
let mut app: App = app();
press(&mut app, KeyCode::Left, KeyModifiers::NONE);
press(&mut app, KeyCode::Char(' '), KeyModifiers::ALT);
assert!(!app.states_ref().unwrap().skirmish.recruitment_view);
press(&mut app, KeyCode::Char('r'), KeyModifiers::NONE);
assert!(app.states_ref().unwrap().skirmish.recruitment_view);
press(&mut app, KeyCode::Enter, KeyModifiers::NONE);