#include "filecomplete.h" #include #include #ifdef _MSC_VER #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif #endif #include #include #include #define MAX_OF(x, y) (((x) > (y)) ? (x) : (y)) #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN64) #ifndef OS_WINDOWS #define OS_WINDOWS #include #include #include #endif #elif defined(__APPLE__) || defined(__unix__) || defined(__unix) || \ defined(unix) || defined(__linux__) #ifndef OS_UNIX #define OS_UNIX #include #include #include #endif #else #error Unknown environment! #endif #if defined(OS_WINDOWS) #define ENTER 13 #define BACKSPACE 8 #define LEFT 75 #define RIGHT 77 #define UP 72 #define DOWN 80 #define DEL 83 #define CTRL_C 3 #define SPECIAL_SEQ_1 0 #define SPECIAL_SEQ_2 224 #define COLOR_TYPE uint16_t #define DEFAULT_TITLE_COLOR 160 #define DEFAULT_PREDICT_COLOR 8 #define DEFAULT_MAIN_COLOR 7 #elif defined(OS_UNIX) #define ENTER 10 #define BACKSPACE 127 #define LEFT 68 #define RIGHT 67 #define UP 65 #define DOWN 66 #define DEL 51 #define DEL_AFTER 126 #define SPECIAL_SEQ_1 27 #define SPECIAL_SEQ_2 91 #define COLOR_TYPE char* #define DEFAULT_TITLE_COLOR "0;30;102" #define DEFAULT_PREDICT_COLOR "90" #define DEFAULT_MAIN_COLOR "0" #endif #define SPACE 32 #define TAB 9 static std::vector> g_buff{}; static std::vector g_wch{}; static size_t g_woffset{}; static size_t g_len{}; short terminal_width(); void clear_line(); void set_cursor_x(short x); short get_cursor_y(); char* readline(); void color_print(char* text, COLOR_TYPE color); void supply(std::vector& wch, char ch) { wch.push_back(ch); if (ch >= 0 && ch < 128) { return; } auto tch = _getch(); wch.push_back(tch); } short terminal_width() { #if defined(OS_WINDOWS) // Handle current terminal HANDLE h_console = GetStdHandle(STD_OUTPUT_HANDLE); if (h_console == NULL) { fprintf(stderr, "[ERROR] Couldn't handle terminal\n"); exit(1); } // Get current attributes CONSOLE_SCREEN_BUFFER_INFO console_info; if (GetConsoleScreenBufferInfo(h_console, &console_info) == 0) { fprintf(stderr, "[ERROR] Couldn't get terminal info\n"); exit(1); } // Return current width return console_info.dwSize.X; #elif defined(OS_UNIX) struct winsize t_size; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &t_size) == -1) { fprintf(stderr, "[ERROR] Couldn't get terminal info\n"); exit(1); } return (short)t_size.ws_col; #endif } void clear_line() { #if defined(OS_WINDOWS) // Get current terminal width short width = terminal_width(); if (width < 1) { fprintf(stderr, "[ERROR] Size of terminal is too small\n"); exit(1); } // Create long empty string char* empty = (char*)malloc(sizeof(char) * width); if (empty) { memset(empty, ' ', width); empty[width - 1] = '\0'; } // Clear line printf("\r%s\r", empty); // Free line free(empty); #elif defined(OS_UNIX) printf("\033[2K\r"); #endif } void set_cursor_x(short x) { #if defined(OS_WINDOWS) HANDLE h_console = GetStdHandle(STD_OUTPUT_HANDLE); if (h_console == NULL) { fprintf(stderr, "[ERROR] Couldn't handle terminal\n"); exit(1); } // Create position COORD xy; xy.X = x - 1; xy.Y = get_cursor_y(); // Set cursor position if (SetConsoleCursorPosition(h_console, xy) == 0) { fprintf(stderr, "[ERROR] Couldn't set terminal cursor position\n"); exit(1); } #elif defined(OS_UNIX) printf("\033[%d;%dH", get_cursor_y(), x); #endif } short get_cursor_y() { #if defined(OS_WINDOWS) HANDLE h_console = GetStdHandle(STD_OUTPUT_HANDLE); if (h_console == NULL) { fprintf(stderr, "[ERROR] Couldn't handle terminal\n"); exit(1); } // Get terminal info CONSOLE_SCREEN_BUFFER_INFO console_info; if (GetConsoleScreenBufferInfo(h_console, &console_info) == 0) { fprintf(stderr, "[ERROR] Couldn't get terminal Y position\n"); exit(1); } // Return Y position return console_info.dwCursorPosition.Y; #elif defined(OS_UNIX) struct termios old_attr, new_attr; char ch, buf[30] = {0}; int i = 0, pow = 1, y = 0; // Backup terminal attributes if (tcgetattr(STDIN_FILENO, &new_attr) == -1) { fprintf(stderr, "[ERROR] Couldn't get terminal attributes\n"); exit(1); } // Disable echo old_attr = new_attr; old_attr.c_lflag &= ~(ICANON | ECHO); if (tcsetattr(STDIN_FILENO, TCSANOW, &old_attr) == -1) { fprintf(stderr, "[ERROR] Couldn't set terminal attributes\n"); exit(1); } // Get info about cursor if (write(STDOUT_FILENO, "\033[6n", 4) != 4) { fprintf(stderr, "[ERROR] Couldn't get cursor information\n"); exit(1); } // Get ^[[{this};1R value for (ch = 0; ch != 'R'; i++) { if (read(STDIN_FILENO, &ch, 1) != 1) { fprintf(stderr, "[ERROR] Couldn't read cursor information"); exit(1); } buf[i] = ch; } i -= 2; while (buf[i] != ';') { i -= 1; } i -= 1; while (buf[i] != '[') { y = y + (buf[i] - '0') * pow; pow *= 10; i -= 1; } // Reset attributes if (tcsetattr(0, TCSANOW, &new_attr) == -1) { fprintf(stderr, "[ERROR] Couldn't reset terminal attributes\n"); exit(1); } return (short)y; #endif } char* readline() { short buff_cap = terminal_width(); char* buff = (char*)calloc((size_t)buff_cap, sizeof(char)); if (buff == NULL) { fprintf(stderr, "[ERROR] Couldn't allocate memory for buffer\n"); exit(1); } short buff_len = 0; // Cursor offset in buffer for moving int offset = 0; // Current hint number int hint_num = 0; while (1) { g_wch.clear(); clear_line(); // Print current buffer color_print(buff, DEFAULT_MAIN_COLOR); // Move cursor to buffer end // short x = (short)(buff_len + 1 - offset); // set_cursor_x(x); // Read character from console int ch = _getch(); switch (ch) { case ENTER: return nullptr; #if defined(OS_WINDWS) case CTRL_C: { exit(0); } #endif case BACKSPACE: { if (g_woffset > 0) { for (size_t i = g_woffset - 1; i < g_buff.size() - 1; ++i) { g_buff[i] = g_buff[i + 1]; } --g_woffset; --g_len; } break; } case TAB: { break; } #if defined(OS_WINDOWS) case SPECIAL_SEQ_1: case SPECIAL_SEQ_2: #elif defined(OS_UNIX) case SPECIAL_SEQ_1: #endif { #if defined(OS_UNIX) if (_getch() != SPECIAL_SEQ_2) { continue; } #endif switch (_getch()) { case LEFT: offset = offset < 1 ? 0 : (--offset); break; case RIGHT: offset = offset > g_buff.size() ? g_buff.size() : (++offset); break; case UP: break; case DOWN: break; case DEL: // Edit buffer like DELETE key #if defined(OS_UNIX) if (_getch() == DEL_AFTER) #endif { } break; default: break; } break; } default: { supply(g_wch, ch); g_buff.push_back(g_wch); ++g_woffset; ++g_len; break; } } } return buff; } void color_print(char* text, COLOR_TYPE color) { #if defined(OS_WINDOWS) HANDLE h_console = GetStdHandle(STD_OUTPUT_HANDLE); if (h_console == NULL) { fprintf(stderr, "[ERROR] Couldn't handle terminal\n"); exit(1); } CONSOLE_SCREEN_BUFFER_INFO console_info; COLOR_TYPE backup; // Save current attributes if (GetConsoleScreenBufferInfo(h_console, &console_info) == 0) { fprintf(stderr, "[ERROR] Couldn't get terminal info\n"); exit(1); } backup = console_info.wAttributes; // Print colored text if (SetConsoleTextAttribute(h_console, color) == 0) { fprintf(stderr, "[ERROR] Couldn't set terminal color\n"); exit(1); } std::string tbuf; for (size_t i = 0; i < g_buff.size() && i < g_len; ++i) { for (const auto& c : g_buff[i]) { tbuf.push_back(c); } } tbuf.push_back('\0'); printf("%s", tbuf.c_str()); // Restore original color if (SetConsoleTextAttribute(h_console, backup) == 0) { fprintf(stderr, "[ERROR] Couldn't reset terminal color\n"); exit(1); } #elif defined(OS_UNIX) // Set new terminal color printf("\033["); printf("%s", color); printf("m"); // Print colored text printf("%s", text); // Resets the text to default color printf("\033[0m"); #endif }