19 #include <sys/ioctl.h>
20 #include <sys/types.h>
22 #include <boost/lexical_cast.hpp>
23 #include <boost/regex.hpp>
24 #include <boost/tokenizer.hpp>
26 #include <fmt/format.h>
38 using Tokenizer = boost::tokenizer<boost::char_separator<char>>;
40 boost::char_separator<char> sep(
";");
41 Tokenizer tok(str, sep);
43 for(Tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
46 auto endptr =
const_cast<char*
>(it->c_str());
47 int code = strtoul(it->c_str(), &endptr, 10);
49 if(errno != 0 || *endptr != 0)
62 else if(code >= 30 && code <= 37)
63 m_fgColor = m_term->color(
static_cast<SimpleColor>(code - 30));
64 else if(code >= 40 && code <= 47)
65 m_bgColor = m_term->color(
static_cast<SimpleColor>(code - 40));
91 m_state = STATE_ESCAPE;
96 parseSetAttributes(m_buf);
97 m_state = STATE_ESCAPE;
102 if(m_buf.length() >= 16)
103 m_state = STATE_ESCAPE;
125 unsigned int col = 0;
126 std::vector<std::string> ret;
127 std::string currentLine;
129 auto setupLine = [&](){
130 currentLine = m_term->standardColorCode();
131 currentLine += m_fgColor.foregroundCode();
132 currentLine += m_bgColor.backgroundCode();
139 if(c ==
'\r' || c ==
'\n')
145 currentLine.push_back(c);
149 ret.push_back(std::move(currentLine));
156 ret.push_back(std::move(currentLine));
166 m_term->setStandardColors();
167 m_fgColor.foreground();
168 m_bgColor.background();
173 const char* ret = tigetstr(key);
174 if(!ret || ret ==
reinterpret_cast<const char*
>(-1))
186 char* overrideMode = getenv(
"ROSMON_COLOR_MODE");
187 const char* termOverride =
nullptr;
190 if(strcasecmp(overrideMode,
"truecolor") == 0)
192 termOverride =
"xterm-256color";
196 else if(strcasecmp(overrideMode,
"256colors") == 0)
198 termOverride =
"xterm-256color";
202 else if(strcasecmp(overrideMode,
"ansi") == 0)
209 fmt::print(stderr,
"Warning: Unknown ROSMON_COLOR_MODE value: '{}'\n", overrideMode);
215 if(getenv(
"KONSOLE_DBUS_SESSION"))
220 termOverride =
"xterm-256color";
225 char* vte_version = getenv(
"VTE_VERSION");
226 if(vte_version && boost::lexical_cast<unsigned int>(vte_version) >= 3600)
228 termOverride =
"xterm-256color";
235 if(setupterm(termOverride, STDOUT_FILENO, &ret) != OK)
237 fmt::print(
"Could not setup the terminal. Disabling all colors...\n");
246 int num_colors = tigetnum(
"colors");
252 fmt::print(
"Your terminal does not support ANSI background!\n");
256 fmt::print(
"Your terminal does not support ANSI foreground!\n");
267 const char* TERM = getenv(
"TERM");
268 const bool isScreen = TERM && strncmp(TERM,
"screen", strlen(
"screen")) == 0;
278 auto registerKey = [&](
const char* name,
SpecialKey key,
const std::string& fallback =
""){
279 char* code = tigetstr(name);
282 if(code && code !=
reinterpret_cast<char*
>(-1))
284 else if(!fallback.empty())
289 for(
int i = 0; i < 12; ++i)
292 fmt::format(
"kf{}", i+1).c_str(),
301 registerKey(key_up,
SK_Up,
"\033[A");
302 registerKey(key_down,
SK_Down,
"\033[B");
303 registerKey(key_right,
SK_Right,
"\033[C");
304 registerKey(key_left,
SK_Left,
"\033[D");
317 putp(tigetstr(
"civis"));
325 putp(tigetstr(
"cnorm"));
330 int r = (rgb & 0xFF);
331 int g = (rgb >> 8) & 0xFF;
332 int b = (rgb >> 16) & 0xFF;
338 return 16 + 36 * r + 6 * g +
b;
349 snprintf(buf,
sizeof(buf),
"\033[48;2;%d;%d;%dm",
color & 0xFF, (
color >> 8) & 0xFF, (
color >> 16) & 0xFF);
367 snprintf(buf,
sizeof(buf),
"\033[38;2;%d;%d;%dm",
color & 0xFF, (
color >> 8) & 0xFF, (
color >> 16) & 0xFF);
381 if(tcgetattr(STDIN_FILENO, &ios) == 0)
386 ios.c_lflag |= ICANON;
390 ios.c_lflag &= ~ECHO;
391 ios.c_lflag &= ~ICANON;
394 tcsetattr(STDIN_FILENO, TCSANOW, &ios);
464 putp(tparm(
m_upStr.c_str(), numLines));
483 if(ioctl(STDIN_FILENO, TIOCGWINSZ, &w) == 0)
485 *outColumns = w.ws_col;
498 snprintf(buf,
sizeof(buf),
"\033]30;%s\007", title.c_str());
502 snprintf(buf,
sizeof(buf),
"\033k%s\033\\", title.c_str());
508 fputs(
"\033]30;%d : %n\007", stdout);
511 fmt::print(
"\033k{}\033\\", backup);
532 auto now = std::chrono::steady_clock::now();
560 if(read(STDIN_FILENO, &c, 1) != 1)
574 std::size_t matches = 0;
576 bool completeMatch =
false;
586 lastMatch = pair.second;
590 completeMatch =
true;
601 else if(completeMatch)
627 return color(fallback);
633 fmt::format(
"\033[38;2;{};{};{}m", rgb & 0xFF, (rgb >> 8) & 0xFF, (rgb >> 16) & 0xFF),
634 fmt::format(
"\033[48;2;{};{};{}m", rgb & 0xFF, (rgb >> 8) & 0xFF, (rgb >> 16) & 0xFF),