Files
CpCtrl/Noncanonical/Noncanonical.cpp
2025-06-13 17:35:27 +08:00

310 lines
8.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Noncanonical.h"
using namespace std;
// 全局终端设置
terminal_mode_t original_termios;
std::vector<std::string> cmdList{};
// 支持的命令列表
const vector<string> commands = {"setant", "seteph", "query","list", "exit", "help"};
void restore_terminal() {
#if defined(_WIN32)
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), original_termios);
#else
tcsetattr(STDIN_FILENO, TCSANOW, &original_termios);
#endif
}
void set_noncanonical_mode() {
#if defined(_WIN32)
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(hStdin, &original_termios);
DWORD new_mode = original_termios;
new_mode &= ~ENABLE_ECHO_INPUT; // 禁用回显
new_mode &= ~ENABLE_LINE_INPUT; // 禁用行缓冲
new_mode &= ~ENABLE_PROCESSED_INPUT; // 禁用Ctrl+C处理
SetConsoleMode(hStdin, new_mode);
#else
struct termios new_termios;
tcgetattr(STDIN_FILENO, &original_termios);
new_termios = original_termios;
new_termios.c_lflag &= ~(ICANON | ECHO | ISIG);
new_termios.c_cc[VMIN] = 1;
new_termios.c_cc[VTIME] = 0;
tcsetattr(STDIN_FILENO, TCSANOW, &new_termios);
#endif
atexit(restore_terminal);
}
string toLower(const string &str) {
string result;
for (char c : str) {
result += tolower(c);
}
return result;
}
string tabCompletion(const string &currentLine, size_t cursorPos) {
// 分割当前行
vector<string> tokens;
string token;
for (char c: currentLine) {
if (isspace(c)) {
if (!token.empty()) {
tokens.push_back(token);
token.clear();
}
}
else {
token += c;
}
}
if (!token.empty()) tokens.push_back(token);
// 如果没有token或当前token为空
if (tokens.empty() || token.empty()) return currentLine;
bool isFirstToken = (tokens.size() == 1);
string lastToken = tokens.back();
// 候选列表
vector<string> candidates;
// 第一个token匹配命令
if (isFirstToken) {
for (const string &cmd: commands) {
if (cmd.substr(0, lastToken.size()) == lastToken) {
candidates.push_back(cmd);
}
}
}
// // 第二个token匹配键
// else if (tokens.size() == 2) {
// for (const auto &kv: kvStore) {
// if (kv.first.substr(0, lastToken.size()) == lastToken) {
// candidates.push_back(kv.first);
// }
// }
// }
// 没有候选结果
if (candidates.empty()) {
// cout << "\n> " << currentLine << std::flush;
return currentLine;
}
// 唯一候选结果 - 直接补全
if (candidates.size() == 1) {
// 计算要删除的字符数
size_t charsToErase = lastToken.size();
// 创建新行
string newLine = currentLine.substr(0, currentLine.size() - charsToErase);
newLine += candidates[0];
if (isFirstToken) newLine += " ";
return newLine;
}
// 多个候选结果 - 打印选项
cout << "\nPossible completions:\n";
for (const auto &cand: candidates) {
cout << " " << cand << "\n";
}
cout << "> " << currentLine << std::flush;
return currentLine;
}
string readLine(const string &prompt) {
cout << prompt << flush;
string line;
static int historyIndex = -1; // 当前历史命令索引
static string tempLine = ""; // 临时保存当前编辑行
#if defined(_WIN32)
while (true) {
int ch = _getch(); // Windows专用字符读取
// 处理特殊键
if (ch == 0x00 || ch == 0xE0) {
int ext = _getch(); // 获取扩展按键
// 上方向键
if (ext == 72) {
if (!cmdList.empty()) {
// 保存当前编辑行
if (historyIndex == -1) tempLine = line;
// 更新历史索引
if (historyIndex < cmdList.size() - 1)
historyIndex++;
else if (historyIndex == -1)
historyIndex = 0;
//清除
cout << "\r" << prompt << string(line.size(), ' ') << flush;
// 更新当前行
line = cmdList[cmdList.size() - 1 - historyIndex];
//重绘
cout << "\r" << prompt << line << flush;
}
continue;
}
// 下方向键
else if (ext == 80) {
if (historyIndex != -1) {
//清除
cout << "\r" << prompt << string(line.size(), ' ') << flush;
if (historyIndex > 0) {
historyIndex--;
line = cmdList[cmdList.size() - 1 - historyIndex];
}
else {
historyIndex = -1;
line = tempLine;
}
//重绘
cout << "\r" << prompt << line << flush;
}
continue;
}
}
switch (ch) {
case '\r': // Enter键
cout << endl;
return line;
case '\t': // Tab键
line = tabCompletion(line, line.size());
cout << "\r" << prompt << string(line.size(), ' ') << flush;
cout << "\r" << prompt << line << flush;
break;
case 8: // Backspace键
if (!line.empty()) {
line.pop_back();
cout << "\b \b" << flush;
}
break;
case 3: // Ctrl+C
cout << endl;
exit(0);
break;
default: // 可打印字符
if (isprint(ch)) {
line += ch;
cout << static_cast<char>(ch) << flush;
}
}
}
#else
char ch;
while (read(STDIN_FILENO, &ch, 1) == 1) {
// 处理方向键序列 (ESC [ A 或 ESC [ B)
if (ch == 27) { // ESC
char seq[2];
if (read(STDIN_FILENO, seq, 2) == 2) {
// 上方向键
if (seq[0] == '[' && seq[1] == 'A') {
if (!cmdList.empty()) {
// 保存当前编辑行
if (historyIndex == -1) tempLine = line;
// 更新历史索引
if (historyIndex < cmdList.size() - 1)
historyIndex++;
else if (historyIndex == -1)
historyIndex = 0;
for (size_t i = 0; i < line.size(); i++) cout << "\b \b";
// 更新当前行
line = cmdList[cmdList.size() - 1 - historyIndex];
// 清除并重绘
cout << line << flush;
}
continue;
}
// 下方向键
else if (seq[0] == '[' && seq[1] == 'B') {
if (historyIndex != -1) {
for (size_t i = 0; i < line.size(); i++) cout << "\b \b";
if (historyIndex > 0) {
historyIndex--;
line = cmdList[cmdList .size() - 1 - historyIndex];
} else {
historyIndex = -1;
line = tempLine;
}
// 清除并重绘
cout << line << flush;
}
continue;
}
}
}
// Enter键 - 完成输入
if (ch == '\n') {
cout << endl;
return line;
}
// Tab键 - 触发补全
if (ch == '\t') {
string newLine = tabCompletion(line, line.size());
if (newLine != line) {
// 清除当前行
for (size_t i = 0; i < line.size(); i++) {
cout << "\b \b";
}
line = newLine;
cout << line << flush;
}
continue;
}
// Backspace键 - 删除字符(支持不同终端的两种编码)
if (ch == 127 || ch == 8) {
if (!line.empty()) {
line.pop_back();
// 清除字符:\b 移动光标,空格覆盖字符,再\b移动光标
cout << "\b \b" << flush;
}
continue;
}
// Ctrl+C - 退出程序
if (ch == 3) {
cout << endl;
exit(0);
}
// 其他可打印字符
if (isprint(ch)) {
line += ch;
cout << ch << flush;
}
}
#endif
return line;
}