#include #include #include // for setfill #include #include // for STDIN_FILENO #include // for tc(get/set)attr using namespace std; #include "include/config.hpp" #include "include/colors.hpp" 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; } void show_prompt(int line_number) { cout << BOLD << setw(4) << setfill(' ') << line_number << " " RESET; } string get_line_with_hist(vector history, int line_num, bool &received_eof) { 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 received_eof = true; if (input.size() > 0) cout << endl; return input; } 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"; } break; } case 'H': { //* Begin if (input_index > 0) { cout << "\033[" << input_index << "D"; // Go left input_index input_index = 0; } break; } case 'F': { //* End if (input_index < (int)input.size()) { cout << "\033[" << (input.size() - input_index) << "C"; // Go right input.size() - input_index input_index = input.size(); } break; } } } 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, bool &received_eof) { int line_num = input.size(); while (!received_eof) { line_num++; input.push_back(get_line_with_hist(input, line_num, received_eof)); int n = input.back().length(); if (n >= 2 && input.back()[n-1] == ';' && input.back()[n-2] == ';') { input.back().erase(n-1, 1); break; } } return input; }