summaryrefslogtreecommitdiffstats
path: root/src/client/ui.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/ui.rs')
-rw-r--r--src/client/ui.rs143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/client/ui.rs b/src/client/ui.rs
new file mode 100644
index 0000000..036c36a
--- /dev/null
+++ b/src/client/ui.rs
@@ -0,0 +1,143 @@
1//! Pure text/history helpers for the client TUI.
2//!
3//! Nothing here touches the terminal, so it is unit-tested from `tests/`
4//! without a PTY.
5
6struct CommandHelp {
7 name: &'static str,
8 usage: &'static str,
9 description: &'static str,
10}
11
12const COMMANDS: &[CommandHelp] = &[
13 CommandHelp {
14 name: "connect",
15 usage: "connect <ip>:<port>",
16 description: "connect to the server",
17 },
18 CommandHelp {
19 name: "send",
20 usage: "send <message>",
21 description: "send a message to the server",
22 },
23 CommandHelp {
24 name: "disconnect",
25 usage: "disconnect",
26 description: "disconnect from the server",
27 },
28 CommandHelp {
29 name: "ping",
30 usage: "ping",
31 description: "ping the server",
32 },
33 CommandHelp {
34 name: "login",
35 usage: "login",
36 description: "login to the server",
37 },
38 CommandHelp {
39 name: "register",
40 usage: "register",
41 description: "register a new user",
42 },
43 CommandHelp {
44 name: "setcred",
45 usage: "setcred",
46 description: "set credentials for a host",
47 },
48 CommandHelp {
49 name: "logout",
50 usage: "logout",
51 description: "logout from the server",
52 },
53 CommandHelp {
54 name: "info",
55 usage: "info",
56 description: "show account and connection info",
57 },
58 CommandHelp {
59 name: "play",
60 usage: "play <game> [bet]",
61 description: "start a game (e.g. play slots 50)",
62 },
63 CommandHelp {
64 name: "games",
65 usage: "games",
66 description: "list available games",
67 },
68 CommandHelp {
69 name: "help",
70 usage: "help",
71 description: "show this message",
72 },
73 CommandHelp {
74 name: "forget-host",
75 usage: "forget-host [ip:port]",
76 description: "clear saved trust fingerprint and credentials",
77 },
78 CommandHelp {
79 name: "hosts",
80 usage: "hosts",
81 description: "list remembered hosts",
82 },
83 CommandHelp {
84 name: "quit",
85 usage: "quit",
86 description: "quit the program",
87 },
88];
89
90pub fn command_names() -> Vec<&'static str> {
91 COMMANDS.iter().map(|command| command.name).collect()
92}
93
94pub fn help_lines() -> Vec<String> {
95 let mut lines = vec!["Available commands:".to_string()];
96 for command in COMMANDS {
97 lines.push(format!(
98 " {:<28} - {}",
99 command.usage, command.description
100 ));
101 }
102 lines
103}
104
105/// Add a command to the history, skipping blanks and consecutive duplicates.
106pub fn record_history(history: &mut Vec<String>, line: &str) {
107 let line = line.trim();
108 if line.is_empty() {
109 return;
110 }
111 if history.last().is_some_and(|last| last == line) {
112 return;
113 }
114 history.push(line.to_string());
115}
116
117/// Parse the optional bet argument of `play <game> [bet]`.
118pub fn parse_bet_arg(raw: &str) -> Result<u64, String> {
119 let bet = raw
120 .trim()
121 .parse::<u64>()
122 .map_err(|_| format!("Invalid bet: {raw}"))?;
123 if bet < 10 {
124 return Err("Bet must be at least 10 PLN".to_string());
125 }
126 Ok(bet)
127}
128
129/// Lines to move the cursor up to reach the first line of a region that ends
130/// on the current line. `render()` has no trailing newline, so a 7-line board
131/// needs `MoveUp(6)`.
132pub fn lines_to_move_up(previous_lines: usize) -> u16 {
133 previous_lines
134 .saturating_sub(1)
135 .min(u16::MAX as usize) as u16
136}
137
138/// Column (0-based) to move to after the given prompt and input text.
139pub fn input_cursor_column(prompt_len: usize, input_len: usize) -> u16 {
140 prompt_len
141 .saturating_add(input_len)
142 .min(u16::MAX as usize) as u16
143}