mirror of
https://github.com/aristocratos/btop.git
synced 2024-05-18 19:33:03 +12:00
File reorganization
This commit is contained in:
parent
55e2a3f02b
commit
3b3a93935d
2
Makefile
2
Makefile
|
@ -2,7 +2,7 @@ PREFIX ?= /usr/local
|
|||
DOCDIR ?= $(PREFIX)/share/btop/doc
|
||||
CXX = g++
|
||||
CXXFLAGS = -std=c++20 -pthread
|
||||
INCLUDES = -I./Include
|
||||
INCLUDES = -I./src
|
||||
|
||||
btop: btop.cpp
|
||||
@mkdir -p bin
|
||||
|
|
163
btop.cpp
163
btop.cpp
|
@ -16,12 +16,9 @@ indent = tab
|
|||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
@ -29,16 +26,15 @@ tab-size = 4
|
|||
#include <thread>
|
||||
#include <future>
|
||||
#include <atomic>
|
||||
#include <string_view>
|
||||
#include <chrono>
|
||||
#include <ranges>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <btop_globs.h>
|
||||
#include <btop_tools.h>
|
||||
#include <btop_config.h>
|
||||
#include <btop_input.h>
|
||||
#include <btop_theme.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#define SYSTEM "linux"
|
||||
|
@ -100,141 +96,10 @@ void argumentParser(int argc, char **argv){
|
|||
}
|
||||
}
|
||||
|
||||
//* Functions and variables for handling keyboard and mouse input
|
||||
class C_Key {
|
||||
const map<string, string> KEY_ESCAPES = {
|
||||
{"\033", "escape"},
|
||||
{"\n", "enter"},
|
||||
{" ", "space"},
|
||||
{"\x7f", "backspace"},
|
||||
{"\x08", "backspace"},
|
||||
{"[A", "up"},
|
||||
{"OA", "up"},
|
||||
{"[B", "down"},
|
||||
{"OB", "down"},
|
||||
{"[D", "left"},
|
||||
{"OD", "left"},
|
||||
{"[C", "right"},
|
||||
{"OC", "right"},
|
||||
{"[2~", "insert"},
|
||||
{"[3~", "delete"},
|
||||
{"[H", "home"},
|
||||
{"[F", "end"},
|
||||
{"[5~", "page_up"},
|
||||
{"[6~", "page_down"},
|
||||
{"\t", "tab"},
|
||||
{"[Z", "shift_tab"},
|
||||
{"OP", "f1"},
|
||||
{"OQ", "f2"},
|
||||
{"OR", "f3"},
|
||||
{"OS", "f4"},
|
||||
{"[15~", "f5"},
|
||||
{"[17~", "f6"},
|
||||
{"[18~", "f7"},
|
||||
{"[19~", "f8"},
|
||||
{"[20~", "f9"},
|
||||
{"[21~", "f10"},
|
||||
{"[23~", "f11"},
|
||||
{"[24~", "f12"}
|
||||
};
|
||||
|
||||
bool wait(int timeout=0){
|
||||
struct pollfd pls[1];
|
||||
pls[ 0 ].fd = STDIN_FILENO;
|
||||
pls[ 0 ].events = POLLIN | POLLPRI;
|
||||
return poll(pls, 1, timeout) > 0;
|
||||
}
|
||||
|
||||
string get(){
|
||||
string key = "";
|
||||
while (wait() && key.size() < 100) key += cin.get();
|
||||
if (key != ""){
|
||||
if (key.starts_with(Fx::e)) key.erase(0, 1);
|
||||
if (KEY_ESCAPES.count(key)) key = KEY_ESCAPES.at(key);
|
||||
else if (ulen(key) > 1) key = "";
|
||||
}
|
||||
return key;
|
||||
}
|
||||
public:
|
||||
string last = "";
|
||||
|
||||
//* Wait <timeout> ms for input on stdin and return true if available
|
||||
//* 0 to just check for input
|
||||
//* -1 for infinite wait
|
||||
bool operator()(int timeout){
|
||||
if (wait(timeout)) {
|
||||
last = get();
|
||||
return true;
|
||||
} else {
|
||||
last = "";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//* Return last entered key
|
||||
string operator()(){
|
||||
return last;
|
||||
}
|
||||
};
|
||||
|
||||
class C_Theme {
|
||||
map<string, string> c;
|
||||
map<string, vector<string>> g;
|
||||
C_Config conf;
|
||||
|
||||
map<string,string> generate(map<string, string>& source){
|
||||
map<string, string> out;
|
||||
vector<string> t_rgb;
|
||||
string depth;
|
||||
for (auto& item : Global::Default_theme) {
|
||||
depth = (item.first.ends_with("bg")) ? "bg" : "fg";
|
||||
if (source.count(item.first)) {
|
||||
if (source.at(item.first)[0] == '#') out[item.first] = hex_to_color(source.at(item.first), !State::truecolor, depth);
|
||||
else {
|
||||
t_rgb = ssplit(source.at(item.first), " ");
|
||||
out[item.first] = dec_to_color(stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2]), !State::truecolor, depth);
|
||||
}
|
||||
}
|
||||
else out[item.first] = "";
|
||||
if (out[item.first] == "") out[item.first] = hex_to_color(item.second, !State::truecolor, depth);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
//* Change to theme using <source> map
|
||||
void change(map<string, string> source){
|
||||
c = generate(source);
|
||||
State::fg = c.at("main_fg");
|
||||
State::bg = c.at("main_bg");
|
||||
Fx::reset = Fx::reset_base + State::fg + State::bg;
|
||||
}
|
||||
|
||||
//* Generate theme from <source> map, default to DEFAULT_THEME on missing or malformatted values
|
||||
C_Theme(map<string, string> source){
|
||||
change(source);
|
||||
}
|
||||
|
||||
//* Return escape code for color <name>
|
||||
auto operator()(string name){
|
||||
return c.at(name);
|
||||
}
|
||||
|
||||
//* Return vector of escape codes for color gradient <name>
|
||||
auto gradient(string name){
|
||||
return g.at(name);
|
||||
}
|
||||
|
||||
//* Return map of decimal int's (r, g, b) for color <name>
|
||||
auto rgb(string name){
|
||||
return c_to_rgb(c.at(name));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct C_Banner {
|
||||
class C_Banner {
|
||||
string banner_str;
|
||||
|
||||
public:
|
||||
int width;
|
||||
|
||||
C_Banner(){
|
||||
|
@ -274,7 +139,6 @@ struct C_Banner {
|
|||
};
|
||||
|
||||
|
||||
|
||||
//? --------------------------------------------- Main starts here! ---------------------------------------------------
|
||||
int main(int argc, char **argv){
|
||||
int debug = 0;
|
||||
|
@ -293,11 +157,10 @@ int main(int argc, char **argv){
|
|||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
C_Config Config;
|
||||
C_Theme Theme(Global::Default_theme);
|
||||
C_Banner Banner;
|
||||
C_Key Key;
|
||||
C_Input Input;
|
||||
|
||||
cout << Theme("main_bg") << Term.clear << flush;
|
||||
// bool thread_test = false;
|
||||
|
@ -453,17 +316,17 @@ int main(int argc, char **argv){
|
|||
wt--;
|
||||
cout << Mv::to(Term.height - 1, 26) << "(" << wtm << ":" << wts << ") " << flush;
|
||||
//chr = Key(1000);
|
||||
if (Key(1000)) {
|
||||
cout << Mv::to(Term.height - 2, 1) << "Last key: LEN=" << Key().size() << " ULEN=" << ulen(Key()) << " KEY=\"" << Key() << "\" CODE=" << (int)Key().at(0) << " " << flush;
|
||||
full += Key();
|
||||
if (Input(1000)) {
|
||||
cout << Mv::to(Term.height - 2, 1) << "Last key: LEN=" << Input().size() << " ULEN=" << ulen(Input()) << " KEY=\"" << Input() << "\" CODE=" << (int)Input().at(0) << " " << flush;
|
||||
full += Input();
|
||||
cout << Mv::to(Term.height - 5, 1) << full << flush;
|
||||
if (Key() == "q") qp = true;
|
||||
if (Input() == "q") qp = true;
|
||||
wt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (debug == 1) Key(-1);
|
||||
if (debug == 1) Input(-1);
|
||||
Term.restore();
|
||||
if (debug < 2) cout << Term.normal_screen << Term.show_cursor << flush;
|
||||
return 0;
|
||||
|
|
|
@ -19,16 +19,16 @@ tab-size = 4
|
|||
#ifndef _btop_config_included_
|
||||
#define _btop_config_included_
|
||||
|
||||
|
||||
#include <btop_tools.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
using std::string;
|
||||
using std::to_string;
|
||||
using std::vector;
|
||||
using std::map;
|
||||
#include <btop_tools.h>
|
||||
|
||||
using std::string, std::to_string, std::vector, std::map;
|
||||
|
||||
|
||||
//? Classes, functions and variables for reading and writing the btop config file
|
||||
|
||||
#define Bool bool()
|
||||
#define Int int()
|
|
@ -109,6 +109,6 @@ namespace Global {
|
|||
} }
|
||||
} }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
119
src/btop_input.h
Normal file
119
src/btop_input.h
Normal file
|
@ -0,0 +1,119 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#ifndef _btop_input_included_
|
||||
#define _btop_input_included_
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
|
||||
#include <btop_globs.h>
|
||||
#include <btop_tools.h>
|
||||
|
||||
using std::string, std::map, std::cin;
|
||||
|
||||
|
||||
//* Class for handling keyboard and mouse input
|
||||
class C_Input {
|
||||
|
||||
string last = "";
|
||||
|
||||
//* Map for translating key codes to readable values
|
||||
const map<string, string> Key_escapes = {
|
||||
{"\033", "escape"},
|
||||
{"\n", "enter"},
|
||||
{" ", "space"},
|
||||
{"\x7f", "backspace"},
|
||||
{"\x08", "backspace"},
|
||||
{"[A", "up"},
|
||||
{"OA", "up"},
|
||||
{"[B", "down"},
|
||||
{"OB", "down"},
|
||||
{"[D", "left"},
|
||||
{"OD", "left"},
|
||||
{"[C", "right"},
|
||||
{"OC", "right"},
|
||||
{"[2~", "insert"},
|
||||
{"[3~", "delete"},
|
||||
{"[H", "home"},
|
||||
{"[F", "end"},
|
||||
{"[5~", "page_up"},
|
||||
{"[6~", "page_down"},
|
||||
{"\t", "tab"},
|
||||
{"[Z", "shift_tab"},
|
||||
{"OP", "f1"},
|
||||
{"OQ", "f2"},
|
||||
{"OR", "f3"},
|
||||
{"OS", "f4"},
|
||||
{"[15~", "f5"},
|
||||
{"[17~", "f6"},
|
||||
{"[18~", "f7"},
|
||||
{"[19~", "f8"},
|
||||
{"[20~", "f9"},
|
||||
{"[21~", "f10"},
|
||||
{"[23~", "f11"},
|
||||
{"[24~", "f12"}
|
||||
};
|
||||
|
||||
bool wait(int timeout=0){
|
||||
if (timeout == 0) return cin.rdbuf()->in_avail() > 0;
|
||||
auto timer = 0;
|
||||
while (timeout == -1 || timer * 10 <= timeout) {
|
||||
if (cin.rdbuf()->in_avail() > 0) return true;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
if (timeout >= 0) ++timer;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
string get(){
|
||||
string key = "";
|
||||
while (cin.rdbuf()->in_avail() > 0 && key.size() < 100) key += cin.get();
|
||||
if (key != ""){
|
||||
if (key.substr(0,2) == Fx::e) key.erase(0, 1);
|
||||
if (Key_escapes.contains(key)) key = Key_escapes.at(key);
|
||||
else if (ulen(key) > 1) key = "";
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
//* Wait <timeout> ms for input on stdin and return true if available
|
||||
//* 0 to just check for input
|
||||
//* -1 for infinite wait
|
||||
bool operator()(int timeout){
|
||||
if (wait(timeout)) {
|
||||
last = get();
|
||||
return last != "";
|
||||
} else {
|
||||
last = "";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//* Return last entered key
|
||||
string operator()(){
|
||||
return last;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
169
src/btop_theme.h
Normal file
169
src/btop_theme.h
Normal file
|
@ -0,0 +1,169 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#ifndef _btop_theme_included_
|
||||
#define _btop_theme_included_
|
||||
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <btop_globs.h>
|
||||
#include <btop_tools.h>
|
||||
#include <btop_config.h>
|
||||
|
||||
using std::string, std::to_string, std::round, std::vector, std::map;
|
||||
|
||||
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
|
||||
|
||||
//* Convert 24-bit colors to 256 colors using 6x6x6 color cube
|
||||
int truecolor_to_256(unsigned r, unsigned g, unsigned b){
|
||||
if (r / 11 == g / 11 && g / 11 == b / 11) {
|
||||
return 232 + r / 11;
|
||||
} else {
|
||||
return round((float)(r / 51)) * 36 + round((float)(g / 51)) * 6 + round((float)(b / 51)) + 16;
|
||||
}
|
||||
}
|
||||
|
||||
//* Generate escape sequence for 24-bit or 256 color and return as a string
|
||||
//* Args hexa: ["#000000"-"#ffffff"] for color, ["#00"-"#ff"] for greyscale
|
||||
//* t_to_256: [true|false] convert 24bit value to 256 color value
|
||||
//* depth: ["fg"|"bg"] for either a foreground color or a background color
|
||||
string hex_to_color(string hexa, bool t_to_256=false, string depth="fg"){
|
||||
if (hexa.size() > 1){
|
||||
hexa.erase(0, 1);
|
||||
for (auto& c : hexa) if (!isxdigit(c)) return "";
|
||||
depth = (depth == "fg") ? "38" : "48";
|
||||
string pre = Fx::e + depth + ";";
|
||||
pre += (t_to_256) ? "5;" : "2;";
|
||||
|
||||
if (hexa.size() == 2){
|
||||
unsigned h_int = stoi(hexa, 0, 16);
|
||||
if (t_to_256){
|
||||
return pre + to_string(truecolor_to_256(h_int, h_int, h_int)) + "m";
|
||||
} else {
|
||||
string h_str = to_string(h_int);
|
||||
return pre + h_str + ";" + h_str + ";" + h_str + "m";
|
||||
}
|
||||
}
|
||||
else if (hexa.size() == 6){
|
||||
if (t_to_256){
|
||||
return pre + to_string(truecolor_to_256(
|
||||
stoi(hexa.substr(0, 2), 0, 16),
|
||||
stoi(hexa.substr(2, 2), 0, 16),
|
||||
stoi(hexa.substr(4, 2), 0, 16))) + "m";
|
||||
} else {
|
||||
return pre +
|
||||
to_string(stoi(hexa.substr(0, 2), 0, 16)) + ";" +
|
||||
to_string(stoi(hexa.substr(2, 2), 0, 16)) + ";" +
|
||||
to_string(stoi(hexa.substr(4, 2), 0, 16)) + "m";
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//* Generate escape sequence for 24-bit or 256 color and return as a string
|
||||
//* Args r: [0-255], g: [0-255], b: [0-255]
|
||||
//* t_to_256: [true|false] convert 24bit value to 256 color value
|
||||
//* depth: ["fg"|"bg"] for either a foreground color or a background color
|
||||
string dec_to_color(unsigned r, unsigned g, unsigned b, bool t_to_256=false, string depth="fg"){
|
||||
depth = (depth == "fg") ? "38" : "48";
|
||||
string pre = Fx::e + depth + ";";
|
||||
pre += (t_to_256) ? "5;" : "2;";
|
||||
r = (r > 255) ? 255 : r;
|
||||
g = (g > 255) ? 255 : g;
|
||||
b = (b > 255) ? 255 : b;
|
||||
if (t_to_256) return pre + to_string(truecolor_to_256(r, g, b)) + "m";
|
||||
else return pre + to_string(r) + ";" + to_string(g) + ";" + to_string(b) + "m";
|
||||
}
|
||||
|
||||
//* Return a map of "r", "g", "b", 0-255 values for a 24-bit color escape string
|
||||
map<string, int> c_to_rgb(string c_string){
|
||||
map<string, int> rgb = {{"r", 0}, {"g", 0}, {"b", 0}};
|
||||
if (c_string.size() >= 14){
|
||||
c_string.erase(0, 7);
|
||||
auto c_split = ssplit(c_string, ";");
|
||||
if (c_split.size() == 3){
|
||||
rgb["r"] = stoi(c_split[0]);
|
||||
rgb["g"] = stoi(c_split[1]);
|
||||
rgb["b"] = stoi(c_split[2].erase(c_split[2].size()));
|
||||
}
|
||||
}
|
||||
return rgb;
|
||||
}
|
||||
|
||||
//? --------------------------------------------------- CLASSES -----------------------------------------------------
|
||||
|
||||
class C_Theme {
|
||||
map<string, string> c;
|
||||
map<string, vector<string>> g;
|
||||
|
||||
map<string,string> generate(map<string, string>& source){
|
||||
map<string, string> out;
|
||||
vector<string> t_rgb;
|
||||
string depth;
|
||||
for (auto& item : Global::Default_theme) {
|
||||
depth = (item.first.ends_with("bg")) ? "bg" : "fg";
|
||||
if (source.contains(item.first)) {
|
||||
if (source.at(item.first)[0] == '#') out[item.first] = hex_to_color(source.at(item.first), !State::truecolor, depth);
|
||||
else {
|
||||
t_rgb = ssplit(source.at(item.first), " ");
|
||||
out[item.first] = dec_to_color(stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2]), !State::truecolor, depth);
|
||||
}
|
||||
}
|
||||
else out[item.first] = "";
|
||||
if (out[item.first] == "") out[item.first] = hex_to_color(item.second, !State::truecolor, depth);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
//* Change to theme <source>
|
||||
void change(map<string, string> source){
|
||||
c = generate(source);
|
||||
State::fg = c.at("main_fg");
|
||||
State::bg = c.at("main_bg");
|
||||
Fx::reset = Fx::reset_base + State::fg + State::bg;
|
||||
}
|
||||
|
||||
//* Generate theme from <source> map, default to DEFAULT_THEME on missing or malformatted values
|
||||
C_Theme(map<string, string> source){
|
||||
change(source);
|
||||
}
|
||||
|
||||
//* Return escape code for color <name>
|
||||
auto operator()(string name){
|
||||
return c.at(name);
|
||||
}
|
||||
|
||||
//* Return vector of escape codes for color gradient <name>
|
||||
auto gradient(string name){
|
||||
return g.at(name);
|
||||
}
|
||||
|
||||
//* Return map of decimal int's (r, g, b) for color <name>
|
||||
auto rgb(string name){
|
||||
return c_to_rgb(c.at(name));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -19,17 +19,17 @@ tab-size = 4
|
|||
#ifndef _btop_tools_included_
|
||||
#define _btop_tools_included_
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <btop_globs.h>
|
||||
|
||||
using std::string, std::to_string, std::round, std::vector, std::map, std::cin;
|
||||
|
||||
//? ------------------------------------------------- NAMESPACES ------------------------------------------------------
|
||||
|
@ -86,6 +86,65 @@ namespace Mv {
|
|||
const string restore = Fx::e + "u";
|
||||
};
|
||||
|
||||
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
|
||||
|
||||
//* Return number of UTF8 characters in a string
|
||||
inline size_t ulen(const string& str){
|
||||
size_t len = 0;
|
||||
for (char c : str) if ((c & 0xC0) != 0x80) ++len;
|
||||
return len;
|
||||
}
|
||||
|
||||
//* Return current time since epoch in milliseconds
|
||||
uint64_t time_ms(){
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
//* Check if a string is a valid bool value
|
||||
bool isbool(string str){
|
||||
return (str == "true") || (str == "false") || (str == "True") || (str == "False");
|
||||
}
|
||||
|
||||
//* Check if a string is a valid integer value
|
||||
bool isint(string str){
|
||||
return all_of(str.begin(), str.end(), ::isdigit);
|
||||
}
|
||||
|
||||
//* Left-trim <t_str> from <str> and return string
|
||||
string ltrim(string str, string t_str = " "){
|
||||
while (str.starts_with(t_str)) str.erase(0, t_str.size());
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Right-trim <t_str> from <str> and return string
|
||||
string rtrim(string str, string t_str = " "){
|
||||
while (str.ends_with(t_str)) str.resize(str.size() - t_str.size());
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Left-right-trim <t_str> from <str> and return string
|
||||
string trim(string str, string t_str = " "){
|
||||
return ltrim(rtrim(str, t_str), t_str);
|
||||
}
|
||||
|
||||
//* Split <string> at <delim> <times> (0 for unlimited) times and return vector
|
||||
vector<string> ssplit(string str, string delim = " ", int times = 0){
|
||||
vector<string> out;
|
||||
if (str != "" && delim != ""){
|
||||
size_t pos = 0;
|
||||
int x = 0;
|
||||
string tmp;
|
||||
while ((pos = str.find(delim)) != string::npos){
|
||||
tmp = str.substr(0, pos);
|
||||
if (tmp != delim && tmp != "") out.push_back(tmp);
|
||||
str.erase(0, pos + delim.size());
|
||||
if (times > 0 && ++x >= times) break;
|
||||
}
|
||||
}
|
||||
out.push_back(str);
|
||||
return out;
|
||||
}
|
||||
|
||||
//? --------------------------------------------------- CLASSES -----------------------------------------------------
|
||||
|
||||
//* Collection of escape codes and functions for terminal manipulation
|
||||
|
@ -185,143 +244,6 @@ public:
|
|||
refresh();
|
||||
resized = false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
|
||||
|
||||
//* Return number of UTF8 characters in a string
|
||||
inline size_t ulen(const string& str){
|
||||
size_t len = 0;
|
||||
for (char c : str) if ((c & 0xC0) != 0x80) ++len;
|
||||
return len;
|
||||
}
|
||||
|
||||
//* Return current time since epoch in milliseconds
|
||||
uint64_t time_ms(){
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
//* Check if a string is a valid bool value
|
||||
bool isbool(string str){
|
||||
return (str == "true") | (str == "false") | (str == "True") | (str == "False");
|
||||
}
|
||||
|
||||
//* Check if a string is a valid integer value
|
||||
bool isint(string str){
|
||||
return all_of(str.begin(), str.end(), ::isdigit);
|
||||
}
|
||||
|
||||
//* Convert 24-bit colors to 256 colors using 6x6x6 color cube
|
||||
int truecolor_to_256(unsigned r, unsigned g, unsigned b){
|
||||
if (r / 11 == g / 11 && g / 11 == b / 11) {
|
||||
return 232 + r / 11;
|
||||
} else {
|
||||
return round((float)(r / 51)) * 36 + round((float)(g / 51)) * 6 + round((float)(b / 51)) + 16;
|
||||
}
|
||||
}
|
||||
|
||||
//* Generate escape sequence for 24-bit or 256 color and return as a string
|
||||
//* Args hexa: ["#000000"-"#ffffff"] for color, ["#00"-"#ff"] for greyscale
|
||||
//* t_to_256: [true|false] convert 24bit value to 256 color value
|
||||
//* depth: ["fg"|"bg"] for either a foreground color or a background color
|
||||
string hex_to_color(string hexa, bool t_to_256=false, string depth="fg"){
|
||||
if (hexa.size() > 1){
|
||||
hexa.erase(0, 1);
|
||||
for (auto& c : hexa) if (!isxdigit(c)) return "";
|
||||
depth = (depth == "fg") ? "38" : "48";
|
||||
string pre = Fx::e + depth + ";";
|
||||
pre += (t_to_256) ? "5;" : "2;";
|
||||
|
||||
if (hexa.size() == 2){
|
||||
unsigned h_int = stoi(hexa, 0, 16);
|
||||
if (t_to_256){
|
||||
return pre + to_string(truecolor_to_256(h_int, h_int, h_int)) + "m";
|
||||
} else {
|
||||
string h_str = to_string(h_int);
|
||||
return pre + h_str + ";" + h_str + ";" + h_str + "m";
|
||||
}
|
||||
}
|
||||
else if (hexa.size() == 6){
|
||||
if (t_to_256){
|
||||
return pre + to_string(truecolor_to_256(
|
||||
stoi(hexa.substr(0, 2), 0, 16),
|
||||
stoi(hexa.substr(2, 2), 0, 16),
|
||||
stoi(hexa.substr(4, 2), 0, 16))) + "m";
|
||||
} else {
|
||||
return pre +
|
||||
to_string(stoi(hexa.substr(0, 2), 0, 16)) + ";" +
|
||||
to_string(stoi(hexa.substr(2, 2), 0, 16)) + ";" +
|
||||
to_string(stoi(hexa.substr(4, 2), 0, 16)) + "m";
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//* Generate escape sequence for 24-bit or 256 color and return as a string
|
||||
//* Args r: [0-255], g: [0-255], b: [0-255]
|
||||
//* t_to_256: [true|false] convert 24bit value to 256 color value
|
||||
//* depth: ["fg"|"bg"] for either a foreground color or a background color
|
||||
string dec_to_color(unsigned r, unsigned g, unsigned b, bool t_to_256=false, string depth="fg"){
|
||||
depth = (depth == "fg") ? "38" : "48";
|
||||
string pre = Fx::e + depth + ";";
|
||||
pre += (t_to_256) ? "5;" : "2;";
|
||||
r = (r > 255) ? 255 : r;
|
||||
g = (g > 255) ? 255 : g;
|
||||
b = (b > 255) ? 255 : b;
|
||||
if (t_to_256) return pre + to_string(truecolor_to_256(r, g, b)) + "m";
|
||||
else return pre + to_string(r) + ";" + to_string(g) + ";" + to_string(b) + "m";
|
||||
}
|
||||
|
||||
//* Left-trim <t_str> from <str> and return string
|
||||
string ltrim(string str, string t_str = " "){
|
||||
while (str.starts_with(t_str)) str.erase(0, t_str.size());
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Right-trim <t_str> from <str> and return string
|
||||
string rtrim(string str, string t_str = " "){
|
||||
while (str.ends_with(t_str)) str.resize(str.size() - t_str.size());
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Left-right-trim <t_str> from <str> and return string
|
||||
string trim(string str, string t_str = " "){
|
||||
return ltrim(rtrim(str, t_str), t_str);
|
||||
}
|
||||
|
||||
//* Split <string> at <delim> <times> (0 for unlimited) times and return vector
|
||||
vector<string> ssplit(string str, string delim = " ", int times = 0){
|
||||
vector<string> out;
|
||||
if (str != "" && delim != ""){
|
||||
size_t pos = 0;
|
||||
int x = 0;
|
||||
string tmp;
|
||||
while ((pos = str.find(delim)) != string::npos){
|
||||
tmp = str.substr(0, pos);
|
||||
if (tmp != delim && tmp != "") out.push_back(tmp);
|
||||
str.erase(0, pos + delim.size());
|
||||
if (times > 0 && ++x >= times) break;
|
||||
}
|
||||
}
|
||||
out.push_back(str);
|
||||
return out;
|
||||
}
|
||||
|
||||
//* Return a map of "r", "g", "b", 0-255 values for a 24-bit color escape string
|
||||
map<string, int> c_to_rgb(string c_string){
|
||||
map<string, int> rgb = {{"r", 0}, {"g", 0}, {"b", 0}};
|
||||
if (c_string.size() >= 14){
|
||||
c_string.erase(0, 7);
|
||||
auto c_split = ssplit(c_string, ";");
|
||||
if (c_split.size() == 3){
|
||||
rgb["r"] = stoi(c_split[0]);
|
||||
rgb["g"] = stoi(c_split[1]);
|
||||
rgb["b"] = stoi(c_split[2].erase(c_split[2].size()));
|
||||
}
|
||||
}
|
||||
return rgb;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue