748 lines
18 KiB
C++
748 lines
18 KiB
C++
#include "filecomplete.h"
|
|
#include <cstring>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#ifdef USE_BOOST_FILESYSTEM
|
|
#include <boost/filesystem.hpp>
|
|
namespace fs = boost::filesystem;
|
|
#else
|
|
#include <filesystem>
|
|
namespace fs = std::filesystem;
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
#ifndef _CRT_SECURE_NO_WARNINGS
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#endif
|
|
#endif
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
#define MAX_OF(x, y) (((x) > (y)) ? (x) : (y))
|
|
|
|
#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN64)
|
|
#ifndef OS_WINDOWS
|
|
#define OS_WINDOWS
|
|
|
|
#include <conio.h>
|
|
#include <stdint.h>
|
|
#include <windows.h>
|
|
#endif
|
|
#elif defined(__APPLE__) || defined(__unix__) || defined(__unix) || defined(unix) || defined(__linux__)
|
|
#ifndef OS_UNIX
|
|
#define OS_UNIX
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
#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)
|
|
#ifdef IOS_ISH
|
|
#define ENTER 13
|
|
#else
|
|
#define ENTER 10
|
|
#endif
|
|
#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
|
|
|
|
constexpr int buf_size = 1024 * 100;
|
|
static std::vector<std::vector<char>> buf{};
|
|
static std::vector<char> word{};
|
|
static size_t wo{};
|
|
static size_t len{};
|
|
static char* main_buf{};
|
|
|
|
void trans2buf(char* buffer);
|
|
void clear_line();
|
|
void set_cursor_x(short x);
|
|
short get_cursor_y();
|
|
char* fc_readline();
|
|
void color_print(const char* text, const COLOR_TYPE color);
|
|
|
|
static std::vector<std::string> cur_work_content;
|
|
static std::vector<char> deadline_vch;
|
|
static std::string str_predict;
|
|
static std::map<std::string, std::vector<std::string>> path_cache;
|
|
static std::vector<std::string> history;
|
|
static size_t his_pos{};
|
|
|
|
void append_his(const std::string& his)
|
|
{
|
|
history.push_back(his);
|
|
his_pos = history.size();
|
|
}
|
|
|
|
std::string up_his()
|
|
{
|
|
if (history.size() < 1) {
|
|
return "";
|
|
}
|
|
|
|
if (his_pos >= 1) {
|
|
--his_pos;
|
|
return history[his_pos];
|
|
} else {
|
|
return history[0];
|
|
}
|
|
}
|
|
|
|
std::string next_his()
|
|
{
|
|
if (history.size() < 1) {
|
|
return "";
|
|
}
|
|
|
|
if (his_pos < (history.size() - 1)) {
|
|
++his_pos;
|
|
return history[his_pos];
|
|
} else {
|
|
his_pos = history.size();
|
|
return "";
|
|
}
|
|
}
|
|
|
|
void flush_content(const std::string& search_dir, std::vector<std::string>& out)
|
|
{
|
|
out.clear();
|
|
fs::path work_path(search_dir);
|
|
try {
|
|
if (!fs::exists(work_path)) {
|
|
return;
|
|
}
|
|
} catch (const std::exception& e) {
|
|
return;
|
|
}
|
|
if (path_cache.count(search_dir)) {
|
|
out = path_cache[search_dir];
|
|
} else {
|
|
for (const auto& entry : fs::directory_iterator(work_path)) {
|
|
out.push_back(entry.path().lexically_normal().string());
|
|
}
|
|
path_cache[search_dir] = out;
|
|
}
|
|
}
|
|
|
|
std::string file_predict(const char* data)
|
|
{
|
|
std::string result;
|
|
std::string cur(data);
|
|
|
|
std::string not_key(" ");
|
|
std::string search_key;
|
|
for (const auto& item : deadline_vch) {
|
|
not_key.push_back(item);
|
|
}
|
|
auto fk = cur.find_last_of(not_key);
|
|
if (fk != std::string::npos) {
|
|
search_key = cur.substr(fk + 1, cur.size() - fk);
|
|
} else {
|
|
search_key = cur;
|
|
}
|
|
if (search_key.find("/") == std::string::npos && search_key.find("\\") == std::string::npos) {
|
|
for (const auto& item : cur_work_content) {
|
|
if (item != search_key && item.find(search_key) == 0) {
|
|
return item.substr(search_key.size(), item.size() - search_key.size());
|
|
}
|
|
}
|
|
}
|
|
std::string bk_search_path = search_key.substr(0, search_key.find_last_of("\\/") + 1);
|
|
std::vector<std::string> sr;
|
|
flush_content(bk_search_path, sr);
|
|
for (const auto& item : sr) {
|
|
if (item != search_key && item.find(search_key) == 0) {
|
|
return item.substr(search_key.size(), item.size() - search_key.size());
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#if defined(OS_UNIX)
|
|
int _getch()
|
|
{
|
|
int character;
|
|
struct termios old_attr, new_attr;
|
|
|
|
// Backup terminal attributes
|
|
if (tcgetattr(STDIN_FILENO, &old_attr) == -1) {
|
|
fprintf(stderr, "[ERROR] Couldn't get terminal attributes\n");
|
|
exit(1);
|
|
}
|
|
|
|
// Disable echo
|
|
new_attr = old_attr;
|
|
new_attr.c_lflag &= ~(ICANON | ECHO);
|
|
if (tcsetattr(STDIN_FILENO, TCSANOW, &new_attr) == -1) {
|
|
fprintf(stderr, "[ERROR] Couldn't set terminal attributes\n");
|
|
exit(1);
|
|
}
|
|
|
|
// Get input character
|
|
character = getchar();
|
|
|
|
// Restore terminal attributes
|
|
if (tcsetattr(STDIN_FILENO, TCSANOW, &old_attr) == -1) {
|
|
fprintf(stderr, "[ERROR] Couldn't reset terminal attributes\n");
|
|
exit(1);
|
|
}
|
|
|
|
return character;
|
|
}
|
|
#endif
|
|
|
|
std::pair<short, short> get_wh()
|
|
{
|
|
#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;
|
|
if (GetConsoleScreenBufferInfo(h_console, &console_info) == 0) {
|
|
fprintf(stderr, "[ERROR] Couldn't get terminal info\n");
|
|
exit(1);
|
|
}
|
|
int cw = console_info.srWindow.Right - console_info.srWindow.Left + 1;
|
|
int ch = console_info.srWindow.Bottom - console_info.srWindow.Top + 1;
|
|
auto w = static_cast<short>(cw);
|
|
auto h = static_cast<short>(ch);
|
|
return std::make_pair(w, h);
|
|
#elif defined(OS_UNIX)
|
|
return std::make_pair(12, 12);
|
|
#endif
|
|
}
|
|
|
|
size_t get_u8_len(unsigned char ch)
|
|
{
|
|
if (ch <= 0x7F) {
|
|
return 1;
|
|
} else if ((ch & 0xE0) == 0xC0) {
|
|
return 2;
|
|
} else if ((ch & 0xF0) == 0xE0) {
|
|
return 3;
|
|
} else if ((ch & 0xF8) == 0xF0) {
|
|
return 4;
|
|
} else if ((ch & 0xFC) == 0xF8) {
|
|
return 5;
|
|
} else if ((ch & 0xFE) == 0xFC) {
|
|
return 6;
|
|
} else {
|
|
printf("invalid u8 first ch.");
|
|
exit(1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
std::vector<std::vector<char>> str_to_vec(const std::string& source)
|
|
{
|
|
std::vector<std::vector<char>> result;
|
|
for (size_t i = 0; i < source.size();) {
|
|
std::vector<char> b;
|
|
char curch = source[i];
|
|
b.push_back(curch);
|
|
if (curch >= 0) {
|
|
result.push_back(b);
|
|
++i;
|
|
} else {
|
|
#if defined(BINARY_GBK)
|
|
size_t length = 2;
|
|
#else
|
|
size_t length = get_u8_len(curch);
|
|
#endif
|
|
for (size_t z = 1; z < length; ++z) {
|
|
if ((i + z) < source.size()) {
|
|
b.push_back(source[i + z]);
|
|
}
|
|
}
|
|
result.push_back(b);
|
|
i += length;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void supply(std::vector<char>& wch, char ch)
|
|
{
|
|
#if defined(BINARY_GBK)
|
|
wch.push_back(ch);
|
|
if (ch >= 0 && ch < 128) {
|
|
return;
|
|
}
|
|
auto tch = _getch();
|
|
wch.push_back(tch);
|
|
#else
|
|
wch.push_back(ch);
|
|
int length = get_u8_len(static_cast<unsigned char>(ch));
|
|
if (length == 0) {
|
|
printf("Invalid Charactor!\n");
|
|
exit(1);
|
|
}
|
|
for (int i = 1; i < length; ++i) {
|
|
auto tch = _getch();
|
|
wch.push_back(tch);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void clear_line()
|
|
{
|
|
#if defined(OS_WINDOWS)
|
|
// Get current terminal width
|
|
short width = get_wh().first;
|
|
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';
|
|
}
|
|
|
|
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
CONSOLE_CURSOR_INFO cursorInfo;
|
|
GetConsoleCursorInfo(hConsole, &cursorInfo);
|
|
cursorInfo.bVisible = FALSE;
|
|
SetConsoleCursorInfo(hConsole, &cursorInfo);
|
|
|
|
// 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);
|
|
}
|
|
|
|
auto wh = get_wh();
|
|
// Create position
|
|
COORD xy;
|
|
xy.Y = get_cursor_y();
|
|
short px = x % wh.first - 1;
|
|
xy.X = px < 0 ? 0 : px;
|
|
|
|
// Set cursor position
|
|
if (SetConsoleCursorPosition(h_console, xy) == 0) {
|
|
auto code = GetLastError();
|
|
fprintf(stderr, "[ERROR] Couldn't set terminal cursor position, err=%lu\n", code);
|
|
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
|
|
}
|
|
|
|
void fc_append(char deadline_ch)
|
|
{
|
|
deadline_vch.push_back(deadline_ch);
|
|
}
|
|
|
|
char* fc_readline()
|
|
{
|
|
main_buf = (char*)malloc(sizeof(char) * buf_size);
|
|
std::memset(main_buf, 0x0, buf_size);
|
|
if (main_buf == NULL) {
|
|
fprintf(stderr, "[ERROR] Couldn't allocate memory for buffer\n");
|
|
exit(1);
|
|
}
|
|
|
|
char* tmp_buf = (char*)malloc(sizeof(char) * buf_size);
|
|
std::memset(tmp_buf, 0x0, buf_size);
|
|
std::shared_ptr<int> deleter(new int(), [tmp_buf](int* p) {
|
|
delete p;
|
|
free(tmp_buf);
|
|
});
|
|
|
|
flush_content(".", cur_work_content);
|
|
auto add_newer = [&](const std::vector<char>& wch) {
|
|
if (wo < buf.size()) {
|
|
if (len >= buf.size()) {
|
|
buf.resize(buf.size() * 2);
|
|
}
|
|
if (len > 0) {
|
|
for (size_t i = len - 1; i >= wo; --i) {
|
|
buf[i + 1] = buf[i];
|
|
}
|
|
}
|
|
buf[wo] = wch;
|
|
} else {
|
|
buf.push_back(wch);
|
|
}
|
|
++wo;
|
|
++len;
|
|
};
|
|
|
|
bool need_predic = true;
|
|
std::chrono::time_point<std::chrono::high_resolution_clock> p1, p2;
|
|
p1 = std::chrono::high_resolution_clock::now();
|
|
|
|
#if defined(OS_WINDOWS)
|
|
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
CONSOLE_CURSOR_INFO cursorInfo;
|
|
GetConsoleCursorInfo(hConsole, &cursorInfo);
|
|
cursorInfo.bVisible = TRUE;
|
|
SetConsoleCursorInfo(hConsole, &cursorInfo);
|
|
#endif
|
|
|
|
while (1) {
|
|
word.clear();
|
|
clear_line();
|
|
// Print current buffer
|
|
color_print(nullptr, DEFAULT_MAIN_COLOR);
|
|
if (!str_predict.empty()) {
|
|
color_print(str_predict.data(), DEFAULT_PREDICT_COLOR);
|
|
}
|
|
// Move cursor
|
|
size_t cur_pos{};
|
|
#if defined(BINARY_GBK)
|
|
for (size_t i = 0; i < buf.size() && i < wo; ++i) {
|
|
cur_pos += buf[i].size();
|
|
}
|
|
#else
|
|
for (size_t i = 0; i < buf.size() && i < wo; ++i) {
|
|
if (buf[i].size() > 1) {
|
|
cur_pos += 2;
|
|
} else {
|
|
cur_pos += 1;
|
|
}
|
|
}
|
|
#endif
|
|
set_cursor_x(cur_pos + 1);
|
|
need_predic = true;
|
|
|
|
// Read character from console
|
|
int ch = _getch();
|
|
|
|
p2 = p1;
|
|
p1 = std::chrono::high_resolution_clock::now();
|
|
|
|
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(p1 - p2).count();
|
|
if (duration <= 10) {
|
|
need_predic = false;
|
|
}
|
|
|
|
switch (ch) {
|
|
case ENTER:
|
|
#if defined(OS_WINDOWS)
|
|
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
CONSOLE_CURSOR_INFO cursorInfo;
|
|
GetConsoleCursorInfo(hConsole, &cursorInfo);
|
|
cursorInfo.bVisible = FALSE;
|
|
SetConsoleCursorInfo(hConsole, &cursorInfo);
|
|
#endif
|
|
append_his(main_buf);
|
|
return main_buf;
|
|
#if defined(OS_WINDOWS)
|
|
case CTRL_C: {
|
|
free(main_buf);
|
|
return nullptr;
|
|
}
|
|
#endif
|
|
case BACKSPACE: {
|
|
if (wo > 0) {
|
|
for (size_t i = wo - 1; i < buf.size() - 1; ++i) {
|
|
buf[i] = buf[i + 1];
|
|
}
|
|
--wo;
|
|
--len;
|
|
}
|
|
break;
|
|
}
|
|
case TAB: {
|
|
// 在这里补全
|
|
if (!str_predict.empty()) {
|
|
auto temp = str_to_vec(str_predict);
|
|
str_predict.clear();
|
|
for (const auto& item : temp) {
|
|
add_newer(item);
|
|
}
|
|
continue;
|
|
}
|
|
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:
|
|
if (wo > 0) {
|
|
--wo;
|
|
}
|
|
break;
|
|
case RIGHT:
|
|
if (wo < len) {
|
|
++wo;
|
|
}
|
|
break;
|
|
case UP: {
|
|
auto up_str = up_his();
|
|
buf.clear();
|
|
auto t = str_to_vec(up_str);
|
|
if (t.size() > 0) {
|
|
buf.insert(buf.end(), t.begin(), t.end());
|
|
}
|
|
len = buf.size();
|
|
wo = len;
|
|
break;
|
|
}
|
|
|
|
case DOWN: {
|
|
auto next_str = next_his();
|
|
buf.clear();
|
|
auto t = str_to_vec(next_str);
|
|
if (t.size() > 0) {
|
|
buf.insert(buf.end(), t.begin(), t.end());
|
|
}
|
|
len = buf.size();
|
|
wo = len;
|
|
break;
|
|
}
|
|
case DEL:
|
|
// Edit buffer like DELETE key
|
|
#if defined(OS_UNIX)
|
|
if (_getch() == DEL_AFTER)
|
|
#endif
|
|
{
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
supply(word, ch);
|
|
add_newer(word);
|
|
break;
|
|
}
|
|
}
|
|
// 补正
|
|
trans2buf(tmp_buf);
|
|
if (need_predic) {
|
|
str_predict = file_predict(tmp_buf);
|
|
} else if (!str_predict.empty()) {
|
|
str_predict.clear();
|
|
}
|
|
p1 = std::chrono::high_resolution_clock::now();
|
|
}
|
|
return main_buf;
|
|
}
|
|
|
|
void fc_free(char* str)
|
|
{
|
|
buf.clear();
|
|
wo = 0;
|
|
len = 0;
|
|
free(str);
|
|
}
|
|
|
|
void trans2buf(char* buffer)
|
|
{
|
|
int j = 0;
|
|
for (size_t i = 0; i < buf.size() && i < len; ++i) {
|
|
for (const auto& c : buf[i]) {
|
|
buffer[j++] = c;
|
|
}
|
|
}
|
|
buffer[j++] = '\0';
|
|
}
|
|
|
|
void color_print(const char* text, const 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);
|
|
}
|
|
|
|
auto wh = get_wh();
|
|
backup = console_info.wAttributes;
|
|
|
|
// Print colored text
|
|
if (SetConsoleTextAttribute(h_console, color) == 0) {
|
|
fprintf(stderr, "[ERROR] Couldn't set terminal color\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (!text) {
|
|
trans2buf(main_buf);
|
|
printf("%s", main_buf);
|
|
} else {
|
|
printf("%s", text);
|
|
}
|
|
|
|
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
CONSOLE_CURSOR_INFO cursorInfo;
|
|
GetConsoleCursorInfo(hConsole, &cursorInfo);
|
|
cursorInfo.bVisible = TRUE;
|
|
SetConsoleCursorInfo(hConsole, &cursorInfo);
|
|
|
|
// 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");
|
|
|
|
if (!text) {
|
|
trans2buf(main_buf);
|
|
printf("%s", main_buf);
|
|
} else {
|
|
printf("%s", text);
|
|
}
|
|
// Resets the text to default color
|
|
printf("\033[0m");
|
|
#if defined(MFLUSH_STDOUT)
|
|
fflush(stdout);
|
|
#endif
|
|
#endif
|
|
}
|