diff --git a/src/input.cpp b/src/input.cpp index ed5eb7a..45f0df8 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -1,33 +1,134 @@ #include #include +#include // for setfill #include +#include // for STDIN_FILENO +#include // for tc(get/set)attr using namespace std; #include "include/config.h" #include "include/colors.h" +char silent_get_char() { // Get char without echoing it + struct termios oldt, newt; + char ch; + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + ch = getchar(); + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + return ch; +} -vector get_input(vector input) { - string buffer; - int line_num = input.size(); - while (1) { - line_num++; - printf(BOLD "%4d " RESET , line_num); - if (!getline(cin, buffer)) { - cout << "\rReceived EOF" << endl; +void show_prompt(int line_number) { + cout << BOLD << setw(4) << setfill(' ') << line_number << " " RESET; +} + + +string get_line_with_hist(vector history, int line_num) { + show_prompt(line_num); + + string input; + int history_index = history.size(); + int input_index = 0; + char ch = 0; + + while (ch != '\n') { + ch = silent_get_char(); + + if (ch == 4 || ch == EOF) { // 4 is End Of Transmission which can also be received + cout << "\rReceived EOF\033[K" << endl; exit(0); } - int n = buffer.length(); - if (n >= 2 && buffer[n-1] == ';' && buffer[n-2] == ';') { - input.push_back(buffer); - buffer[n-1] = '\0'; + if (ch == 27) { // Special sequences + silent_get_char(); + ch = silent_get_char(); + + switch (ch) { + case 'A': { //* Up arrow + if (history_index > 0) { + history_index--; + cout << "\r\033[K"; // Clear the end of the line + show_prompt(line_num); + + cout << history[history_index]; + input = history[history_index]; + input_index = input.size(); + } + break; + } case 'B': { //* Down arrow + if (history_index < (int)history.size() - 1) { + history_index++; + cout << "\r\033[K"; // Clear the end of the line + show_prompt(line_num); + + cout << history[history_index]; + input = history[history_index]; + input_index = input.size(); + } + break; + } case 'D': { //* Left arrow + if (input_index > 0) { + input_index--; + cout << "\033[1D"; // Go left 1 + } + break; + } case 'C': { //* Right arrow + if (input_index < (int)input.size()) { + input_index++; + cout << "\033[1C"; // Go right 1 + } + break; + } case '3': { //* Suppr + silent_get_char(); // Remove last printed char + if (input_index < (int)input.length()) { + input.erase(input_index, 1); + cout << "\033[K" << input.substr(input_index); + + if (input_index < (int)input.size()) + cout << "\033[" << input.size() - input_index << "D"; + } + } + } + } else if (ch == '\b' || ch == 127) { //* Backspace + if (input_index > 0) { + input.erase(input_index-1, 1); + input_index--; + + cout << "\033[1D\033[K"; // Go left 1, clear the end of the line + cout << input.substr(input_index); // Print the input after the deleted character + if (input_index < (int)input.size()) + cout << "\033[" << input.size() - input_index << "D"; // Place the cursor back in the right position + } + } else if (ch != '\n') { + input.insert(input_index, 1, ch); + cout << input.substr(input_index); + input_index++; + if (input_index < (int)input.size()) + cout << "\033[" << input.size() - input_index << "D"; // Place the cursor back in the right position + } + } + cout << endl; + + return input; +} + + +vector get_input(vector input) { + int line_num = input.size(); + while (1) { + line_num++; + input.push_back(get_line_with_hist(input, line_num)); + + int n = input.back().length(); + if (n >= 2 && input.back()[n-1] == ';' && input.back()[n-2] == ';') { + input.back().erase(n-1, 1); break; } - - input.push_back(buffer); } return input;