-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathterminal_input.hpp
More file actions
160 lines (135 loc) · 4.21 KB
/
Copy pathterminal_input.hpp
File metadata and controls
160 lines (135 loc) · 4.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#pragma once
#include <string>
#include <vector>
#include <iostream>
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#include <io.h>
#else
#include <unistd.h>
#include <termios.h>
#endif
namespace acecode {
// Read a line from stdin with prompt and default value.
// Shows "[default]" in prompt. Returns default on empty input.
inline std::string read_line(const std::string& prompt, const std::string& default_value = "") {
if (default_value.empty()) {
std::cout << prompt << ": ";
} else {
std::cout << prompt << " [" << default_value << "]: ";
}
std::cout << std::flush;
std::string input;
std::getline(std::cin, input);
if (input.empty()) {
return default_value;
}
return input;
}
// Read a password (no echo). Shows masked hint of existing value.
// On non-TTY, falls back to normal input with warning.
inline std::string read_password(const std::string& prompt, const std::string& existing = "") {
// Build display hint for existing value
std::string hint;
if (!existing.empty()) {
if (existing.size() > 4) {
hint = "****" + existing.substr(existing.size() - 4);
} else {
hint = "****";
}
}
if (hint.empty()) {
std::cout << prompt << ": ";
} else {
std::cout << prompt << " [" << hint << "]: ";
}
std::cout << std::flush;
#ifdef _WIN32
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
bool is_tty = (_isatty(_fileno(stdin)) != 0);
DWORD old_mode = 0;
if (is_tty) {
GetConsoleMode(hStdin, &old_mode);
SetConsoleMode(hStdin, old_mode & ~ENABLE_ECHO_INPUT);
} else {
std::cerr << "Warning: input may be visible" << std::endl;
}
std::string input;
std::getline(std::cin, input);
if (is_tty) {
SetConsoleMode(hStdin, old_mode);
std::cout << std::endl; // newline after hidden input
}
#else
bool is_tty = (isatty(fileno(stdin)) != 0);
struct termios old_term, new_term;
if (is_tty) {
tcgetattr(fileno(stdin), &old_term);
new_term = old_term;
new_term.c_lflag &= ~ECHO;
tcsetattr(fileno(stdin), TCSANOW, &new_term);
} else {
std::cerr << "Warning: input may be visible" << std::endl;
}
std::string input;
std::getline(std::cin, input);
if (is_tty) {
tcsetattr(fileno(stdin), TCSANOW, &old_term);
std::cout << std::endl;
}
#endif
if (input.empty()) {
return existing;
}
return input;
}
// Display numbered menu and read user choice.
// Returns 0-based index. default_index is 0-based (-1 = no default).
inline int read_choice(const std::string& prompt,
const std::vector<std::string>& options,
int default_index = -1) {
std::cout << prompt << std::endl;
for (size_t i = 0; i < options.size(); ++i) {
std::cout << " " << (i + 1) << ") " << options[i];
if (static_cast<int>(i) == default_index) {
std::cout << " (default)";
}
std::cout << std::endl;
}
while (true) {
if (default_index >= 0) {
std::cout << "Choose [" << (default_index + 1) << "]: ";
} else {
std::cout << "Choose: ";
}
std::cout << std::flush;
std::string input;
std::getline(std::cin, input);
if (input.empty() && default_index >= 0) {
return default_index;
}
try {
int choice = std::stoi(input);
if (choice >= 1 && choice <= static_cast<int>(options.size())) {
return choice - 1;
}
} catch (...) {}
std::cout << "Invalid choice. Please enter a number between 1 and "
<< options.size() << "." << std::endl;
}
}
// Simple yes/no prompt. Returns true for yes.
inline bool read_confirm(const std::string& prompt, bool default_yes = true) {
std::string suffix = default_yes ? " [Y/n]: " : " [y/N]: ";
std::cout << prompt << suffix << std::flush;
std::string input;
std::getline(std::cin, input);
if (input.empty()) {
return default_yes;
}
return (input[0] == 'y' || input[0] == 'Y');
}
} // namespace acecode