148 lines
5.0 KiB
C++
148 lines
5.0 KiB
C++
#include <string>
|
|
#include <vector>
|
|
#include <iomanip> // for setfill
|
|
#include <iostream>
|
|
#include <unistd.h> // for STDIN_FILENO
|
|
#include <termios.h> // 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;
|
|
}
|
|
|
|
|
|
void show_prompt(int line_number) {
|
|
cout << BOLD << setw(4) << setfill(' ') << line_number << " " RESET;
|
|
}
|
|
|
|
|
|
string get_line_with_hist(vector<string> 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);
|
|
}
|
|
|
|
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<string> get_input(vector<string> 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;
|
|
}
|
|
}
|
|
|
|
return input;
|
|
} |