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)
64 else if(code >= 40 && code <= 47)
102 if(
m_buf.length() >= 16)
125 unsigned int col = 0;
126 std::vector<std::string> ret;
127 std::string currentLine;
129 auto setupLine = [&](){
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));
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(),
293 static_cast<SpecialKey>(
SK_F1 + i)
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),
std::string m_lineWrapOnStr
static int ansiColor(uint32_t rgb)
std::string safe_tigetstr(const char *key)
std::string standardColorCode()
Escape codes for standard colors.
SimpleColor
Simple colors.
bool getSize(int *columns, int *rows)
Get current window size.
void setForegroundColor(uint32_t color)
Set 24-bit foreground color.
void setSimpleBackground(SimpleColor color)
std::map< std::string, SpecialKey > m_specialKeys
void moveCursorToStartOfLine()
Move cursor to start of the line.
Color color(SimpleColor code)
void setBackgroundColor(uint32_t color)
Set 24-bit background color.
std::chrono::steady_clock::time_point m_escapeStartTime
void parseSetAttributes(const std::string &str)
std::string m_lineWrapOffStr
void apply()
Apply the current internal state (colors) on the terminal.
void setSimplePair(SimpleColor fg, SimpleColor bg)
std::string m_currentEscapeStr
std::vector< std::string > wrap(const std::string &str, unsigned int columns)
Apply line wrapping.
const std::string & backgroundCode() const
void setLineWrap(bool on)
void clearToEndOfLine()
Clear characters from cursor to end of line.
void setStandardColors()
Reset fg + bg to standard terminal colors.
void setCursorVisible()
restore cursor
void setSimpleForeground(SimpleColor color)
Encapsulates terminal control.
void moveCursorUp(int numLines)
Move cursor up by numLines.
bool has256Colors() const
void setWindowTitle(const std::string &title)
bool parse(char c)
parse single character c
void setCursorInvisible()
hide cursor
const std::string & foregroundCode() const
unsigned int m_currentEscapeAbortIdx
void clearWindowTitle(const std::string &backup)
bool m_currentEscapeAborted