colors.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. #include "colors.h"
  2. #include <util/stream/output.h>
  3. #include <util/generic/singleton.h>
  4. #include <util/system/env.h>
  5. #if defined(_unix_)
  6. #include <unistd.h>
  7. #endif
  8. using namespace NColorizer;
  9. namespace {
  10. constexpr TStringBuf ToStringBufC(NColorizer::EAnsiCode x) {
  11. switch(x) {
  12. case RESET:
  13. return "\033[0m";
  14. case ST_LIGHT:
  15. return "\033[1m";
  16. case ST_DARK:
  17. return "\033[2m";
  18. case ST_NORMAL:
  19. return "\033[22m";
  20. case ITALIC_ON:
  21. return "\033[3m";
  22. case ITALIC_OFF:
  23. return "\033[23m";
  24. case UNDERLINE_ON:
  25. return "\033[4m";
  26. case UNDERLINE_OFF:
  27. return "\033[24m";
  28. case FG_DEFAULT:
  29. return "\033[39m";
  30. case FG_BLACK:
  31. return "\033[30m";
  32. case FG_RED:
  33. return "\033[31m";
  34. case FG_GREEN:
  35. return "\033[32m";
  36. case FG_YELLOW:
  37. return "\033[33m";
  38. case FG_BLUE:
  39. return "\033[34m";
  40. case FG_MAGENTA:
  41. return "\033[35m";
  42. case FG_CYAN:
  43. return "\033[36m";
  44. case FG_WHITE:
  45. return "\033[37m";
  46. case BG_DEFAULT:
  47. return "\033[49m";
  48. case BG_BLACK:
  49. return "\033[40m";
  50. case BG_RED:
  51. return "\033[41m";
  52. case BG_GREEN:
  53. return "\033[42m";
  54. case BG_YELLOW:
  55. return "\033[43m";
  56. case BG_BLUE:
  57. return "\033[44m";
  58. case BG_MAGENTA:
  59. return "\033[45m";
  60. case BG_CYAN:
  61. return "\033[46m";
  62. case BG_WHITE:
  63. return "\033[47m";
  64. // Note: the following codes are split into two escabe sequences because of how ya.make handles them.
  65. case DEFAULT:
  66. return "\033[0m\033[0;39m";
  67. case BLACK:
  68. return "\033[0m\033[0;30m";
  69. case RED:
  70. return "\033[0m\033[0;31m";
  71. case GREEN:
  72. return "\033[0m\033[0;32m";
  73. case YELLOW:
  74. return "\033[0m\033[0;33m";
  75. case BLUE:
  76. return "\033[0m\033[0;34m";
  77. case MAGENTA:
  78. return "\033[0m\033[0;35m";
  79. case CYAN:
  80. return "\033[0m\033[0;36m";
  81. case WHITE:
  82. return "\033[0m\033[0;37m";
  83. case LIGHT_DEFAULT:
  84. return "\033[0m\033[1;39m";
  85. case LIGHT_BLACK:
  86. return "\033[0m\033[1;30m";
  87. case LIGHT_RED:
  88. return "\033[0m\033[1;31m";
  89. case LIGHT_GREEN:
  90. return "\033[0m\033[1;32m";
  91. case LIGHT_YELLOW:
  92. return "\033[0m\033[1;33m";
  93. case LIGHT_BLUE:
  94. return "\033[0m\033[1;34m";
  95. case LIGHT_MAGENTA:
  96. return "\033[0m\033[1;35m";
  97. case LIGHT_CYAN:
  98. return "\033[0m\033[1;36m";
  99. case LIGHT_WHITE:
  100. return "\033[0m\033[1;37m";
  101. case DARK_DEFAULT:
  102. return "\033[0m\033[2;39m";
  103. case DARK_BLACK:
  104. return "\033[0m\033[2;30m";
  105. case DARK_RED:
  106. return "\033[0m\033[2;31m";
  107. case DARK_GREEN:
  108. return "\033[0m\033[2;32m";
  109. case DARK_YELLOW:
  110. return "\033[0m\033[2;33m";
  111. case DARK_BLUE:
  112. return "\033[0m\033[2;34m";
  113. case DARK_MAGENTA:
  114. return "\033[0m\033[2;35m";
  115. case DARK_CYAN:
  116. return "\033[0m\033[2;36m";
  117. case DARK_WHITE:
  118. return "\033[0m\033[2;37m";
  119. case INVALID:
  120. default:
  121. return "";
  122. }
  123. }
  124. }
  125. TStringBuf ToStringBuf(NColorizer::EAnsiCode x) {
  126. return ToStringBufC(x);
  127. }
  128. TString ToString(NColorizer::EAnsiCode x) {
  129. return TString(ToStringBufC(x));
  130. }
  131. template<>
  132. void Out<NColorizer::EAnsiCode>(IOutputStream& os, TTypeTraits<NColorizer::EAnsiCode>::TFuncParam x) {
  133. if (AutoColors(os).IsTTY()) {
  134. os << ToStringBufC(x);
  135. }
  136. }
  137. bool TColors::CalcIsTTY(FILE* file) {
  138. if (GetEnv("ENFORCE_TTY")) {
  139. return true;
  140. }
  141. #if defined(_unix_)
  142. return isatty(fileno(file));
  143. #else
  144. Y_UNUSED(file);
  145. return false;
  146. #endif
  147. }
  148. TColors::TColors(FILE* f)
  149. : IsTTY_(true)
  150. {
  151. SetIsTTY(CalcIsTTY(f));
  152. }
  153. TColors::TColors(bool ontty)
  154. : IsTTY_(true)
  155. {
  156. SetIsTTY(ontty);
  157. }
  158. TStringBuf TColors::Reset() const noexcept {
  159. return IsTTY() ? ToStringBufC(EAnsiCode::RESET) : ToStringBufC(EAnsiCode::INVALID);
  160. }
  161. TStringBuf TColors::StyleLight() const noexcept {
  162. return IsTTY() ? ToStringBufC(EAnsiCode::ST_LIGHT) : ToStringBufC(EAnsiCode::INVALID);
  163. }
  164. TStringBuf TColors::StyleDark() const noexcept {
  165. return IsTTY() ? ToStringBufC(EAnsiCode::ST_DARK) : ToStringBufC(EAnsiCode::INVALID);
  166. }
  167. TStringBuf TColors::StyleNormal() const noexcept {
  168. return IsTTY() ? ToStringBufC(EAnsiCode::ST_NORMAL) : ToStringBufC(EAnsiCode::INVALID);
  169. }
  170. TStringBuf TColors::ItalicOn() const noexcept {
  171. return IsTTY() ? ToStringBufC(EAnsiCode::ITALIC_ON) : ToStringBufC(EAnsiCode::INVALID);
  172. }
  173. TStringBuf TColors::ItalicOff() const noexcept {
  174. return IsTTY() ? ToStringBufC(EAnsiCode::ITALIC_OFF) : ToStringBufC(EAnsiCode::INVALID);
  175. }
  176. TStringBuf TColors::UnderlineOn() const noexcept {
  177. return IsTTY() ? ToStringBufC(EAnsiCode::UNDERLINE_ON) : ToStringBufC(EAnsiCode::INVALID);
  178. }
  179. TStringBuf TColors::UnderlineOff() const noexcept {
  180. return IsTTY() ? ToStringBufC(EAnsiCode::UNDERLINE_OFF) : ToStringBufC(EAnsiCode::INVALID);
  181. }
  182. TStringBuf TColors::ForeDefault() const noexcept {
  183. return IsTTY() ? ToStringBufC(EAnsiCode::FG_DEFAULT) : ToStringBufC(EAnsiCode::INVALID);
  184. }
  185. TStringBuf TColors::ForeBlack() const noexcept {
  186. return IsTTY() ? ToStringBufC(EAnsiCode::FG_BLACK) : ToStringBufC(EAnsiCode::INVALID);
  187. }
  188. TStringBuf TColors::ForeRed() const noexcept {
  189. return IsTTY() ? ToStringBufC(EAnsiCode::FG_RED) : ToStringBufC(EAnsiCode::INVALID);
  190. }
  191. TStringBuf TColors::ForeGreen() const noexcept {
  192. return IsTTY() ? ToStringBufC(EAnsiCode::FG_GREEN) : ToStringBufC(EAnsiCode::INVALID);
  193. }
  194. TStringBuf TColors::ForeYellow() const noexcept {
  195. return IsTTY() ? ToStringBufC(EAnsiCode::FG_YELLOW) : ToStringBufC(EAnsiCode::INVALID);
  196. }
  197. TStringBuf TColors::ForeBlue() const noexcept {
  198. return IsTTY() ? ToStringBufC(EAnsiCode::FG_BLUE) : ToStringBufC(EAnsiCode::INVALID);
  199. }
  200. TStringBuf TColors::ForeMagenta() const noexcept {
  201. return IsTTY() ? ToStringBufC(EAnsiCode::FG_MAGENTA) : ToStringBufC(EAnsiCode::INVALID);
  202. }
  203. TStringBuf TColors::ForeCyan() const noexcept {
  204. return IsTTY() ? ToStringBufC(EAnsiCode::FG_CYAN) : ToStringBufC(EAnsiCode::INVALID);
  205. }
  206. TStringBuf TColors::ForeWhite() const noexcept {
  207. return IsTTY() ? ToStringBufC(EAnsiCode::FG_WHITE) : ToStringBufC(EAnsiCode::INVALID);
  208. }
  209. TStringBuf TColors::BackDefault() const noexcept {
  210. return IsTTY() ? ToStringBufC(EAnsiCode::BG_DEFAULT) : ToStringBufC(EAnsiCode::INVALID);
  211. }
  212. TStringBuf TColors::BackBlack() const noexcept {
  213. return IsTTY() ? ToStringBufC(EAnsiCode::BG_BLACK) : ToStringBufC(EAnsiCode::INVALID);
  214. }
  215. TStringBuf TColors::BackRed() const noexcept {
  216. return IsTTY() ? ToStringBufC(EAnsiCode::BG_RED) : ToStringBufC(EAnsiCode::INVALID);
  217. }
  218. TStringBuf TColors::BackGreen() const noexcept {
  219. return IsTTY() ? ToStringBufC(EAnsiCode::BG_GREEN) : ToStringBufC(EAnsiCode::INVALID);
  220. }
  221. TStringBuf TColors::BackYellow() const noexcept {
  222. return IsTTY() ? ToStringBufC(EAnsiCode::BG_YELLOW) : ToStringBufC(EAnsiCode::INVALID);
  223. }
  224. TStringBuf TColors::BackBlue() const noexcept {
  225. return IsTTY() ? ToStringBufC(EAnsiCode::BG_BLUE) : ToStringBufC(EAnsiCode::INVALID);
  226. }
  227. TStringBuf TColors::BackMagenta() const noexcept {
  228. return IsTTY() ? ToStringBufC(EAnsiCode::BG_MAGENTA) : ToStringBufC(EAnsiCode::INVALID);
  229. }
  230. TStringBuf TColors::BackCyan() const noexcept {
  231. return IsTTY() ? ToStringBufC(EAnsiCode::BG_CYAN) : ToStringBufC(EAnsiCode::INVALID);
  232. }
  233. TStringBuf TColors::BackWhite() const noexcept {
  234. return IsTTY() ? ToStringBufC(EAnsiCode::BG_WHITE) : ToStringBufC(EAnsiCode::INVALID);
  235. }
  236. TStringBuf TColors::Default() const noexcept {
  237. return IsTTY() ? ToStringBufC(EAnsiCode::DEFAULT) : ToStringBufC(EAnsiCode::INVALID);
  238. }
  239. TStringBuf TColors::Black() const noexcept {
  240. return IsTTY() ? ToStringBufC(EAnsiCode::BLACK) : ToStringBufC(EAnsiCode::INVALID);
  241. }
  242. TStringBuf TColors::Red() const noexcept {
  243. return IsTTY() ? ToStringBufC(EAnsiCode::RED) : ToStringBufC(EAnsiCode::INVALID);
  244. }
  245. TStringBuf TColors::Green() const noexcept {
  246. return IsTTY() ? ToStringBufC(EAnsiCode::GREEN) : ToStringBufC(EAnsiCode::INVALID);
  247. }
  248. TStringBuf TColors::Yellow() const noexcept {
  249. return IsTTY() ? ToStringBufC(EAnsiCode::YELLOW) : ToStringBufC(EAnsiCode::INVALID);
  250. }
  251. TStringBuf TColors::Blue() const noexcept {
  252. return IsTTY() ? ToStringBufC(EAnsiCode::BLUE) : ToStringBufC(EAnsiCode::INVALID);
  253. }
  254. TStringBuf TColors::Magenta() const noexcept {
  255. return IsTTY() ? ToStringBufC(EAnsiCode::MAGENTA) : ToStringBufC(EAnsiCode::INVALID);
  256. }
  257. TStringBuf TColors::Cyan() const noexcept {
  258. return IsTTY() ? ToStringBufC(EAnsiCode::CYAN) : ToStringBufC(EAnsiCode::INVALID);
  259. }
  260. TStringBuf TColors::White() const noexcept {
  261. return IsTTY() ? ToStringBufC(EAnsiCode::WHITE) : ToStringBufC(EAnsiCode::INVALID);
  262. }
  263. TStringBuf TColors::LightDefault() const noexcept {
  264. return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_DEFAULT) : ToStringBufC(EAnsiCode::INVALID);
  265. }
  266. TStringBuf TColors::LightBlack() const noexcept {
  267. return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_BLACK) : ToStringBufC(EAnsiCode::INVALID);
  268. }
  269. TStringBuf TColors::LightRed() const noexcept {
  270. return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_RED) : ToStringBufC(EAnsiCode::INVALID);
  271. }
  272. TStringBuf TColors::LightGreen() const noexcept {
  273. return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_GREEN) : ToStringBufC(EAnsiCode::INVALID);
  274. }
  275. TStringBuf TColors::LightYellow() const noexcept {
  276. return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_YELLOW) : ToStringBufC(EAnsiCode::INVALID);
  277. }
  278. TStringBuf TColors::LightBlue() const noexcept {
  279. return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_BLUE) : ToStringBufC(EAnsiCode::INVALID);
  280. }
  281. TStringBuf TColors::LightMagenta() const noexcept {
  282. return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_MAGENTA) : ToStringBufC(EAnsiCode::INVALID);
  283. }
  284. TStringBuf TColors::LightCyan() const noexcept {
  285. return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_CYAN) : ToStringBufC(EAnsiCode::INVALID);
  286. }
  287. TStringBuf TColors::LightWhite() const noexcept {
  288. return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_WHITE) : ToStringBufC(EAnsiCode::INVALID);
  289. }
  290. TStringBuf TColors::DarkDefault() const noexcept {
  291. return IsTTY() ? ToStringBufC(EAnsiCode::DARK_DEFAULT) : ToStringBufC(EAnsiCode::INVALID);
  292. }
  293. TStringBuf TColors::DarkBlack() const noexcept {
  294. return IsTTY() ? ToStringBufC(EAnsiCode::DARK_BLACK) : ToStringBufC(EAnsiCode::INVALID);
  295. }
  296. TStringBuf TColors::DarkRed() const noexcept {
  297. return IsTTY() ? ToStringBufC(EAnsiCode::DARK_RED) : ToStringBufC(EAnsiCode::INVALID);
  298. }
  299. TStringBuf TColors::DarkGreen() const noexcept {
  300. return IsTTY() ? ToStringBufC(EAnsiCode::DARK_GREEN) : ToStringBufC(EAnsiCode::INVALID);
  301. }
  302. TStringBuf TColors::DarkYellow() const noexcept {
  303. return IsTTY() ? ToStringBufC(EAnsiCode::DARK_YELLOW) : ToStringBufC(EAnsiCode::INVALID);
  304. }
  305. TStringBuf TColors::DarkBlue() const noexcept {
  306. return IsTTY() ? ToStringBufC(EAnsiCode::DARK_BLUE) : ToStringBufC(EAnsiCode::INVALID);
  307. }
  308. TStringBuf TColors::DarkMagenta() const noexcept {
  309. return IsTTY() ? ToStringBufC(EAnsiCode::DARK_MAGENTA) : ToStringBufC(EAnsiCode::INVALID);
  310. }
  311. TStringBuf TColors::DarkCyan() const noexcept {
  312. return IsTTY() ? ToStringBufC(EAnsiCode::DARK_CYAN) : ToStringBufC(EAnsiCode::INVALID);
  313. }
  314. TStringBuf TColors::DarkWhite() const noexcept {
  315. return IsTTY() ? ToStringBufC(EAnsiCode::DARK_WHITE) : ToStringBufC(EAnsiCode::INVALID);
  316. }
  317. TStringBuf TColors::OldColor() const noexcept {
  318. return IsTTY() ? "\033[22;39m" : "";
  319. }
  320. TStringBuf TColors::BoldColor() const noexcept {
  321. return IsTTY() ? "\033[1m" : "";
  322. }
  323. TStringBuf TColors::BlackColor() const noexcept {
  324. return IsTTY() ? "\033[22;30m" : "";
  325. }
  326. TStringBuf TColors::BlueColor() const noexcept {
  327. return IsTTY() ? "\033[22;34m" : "";
  328. }
  329. TStringBuf TColors::GreenColor() const noexcept {
  330. return IsTTY() ? "\033[22;32m" : "";
  331. }
  332. TStringBuf TColors::CyanColor() const noexcept {
  333. return IsTTY() ? "\033[22;36m" : "";
  334. }
  335. TStringBuf TColors::RedColor() const noexcept {
  336. return IsTTY() ? "\033[22;31m" : "";
  337. }
  338. TStringBuf TColors::PurpleColor() const noexcept {
  339. return IsTTY() ? "\033[22;35m" : "";
  340. }
  341. TStringBuf TColors::BrownColor() const noexcept {
  342. return IsTTY() ? "\033[22;33m" : "";
  343. }
  344. TStringBuf TColors::LightGrayColor() const noexcept {
  345. return IsTTY() ? "\033[22;37m" : "";
  346. }
  347. TStringBuf TColors::DarkGrayColor() const noexcept {
  348. return IsTTY() ? "\033[1;30m" : "";
  349. }
  350. TStringBuf TColors::LightBlueColor() const noexcept {
  351. return IsTTY() ? "\033[1;34m" : "";
  352. }
  353. TStringBuf TColors::LightGreenColor() const noexcept {
  354. return IsTTY() ? "\033[1;32m" : "";
  355. }
  356. TStringBuf TColors::LightCyanColor() const noexcept {
  357. return IsTTY() ? "\033[1;36m" : "";
  358. }
  359. TStringBuf TColors::LightRedColor() const noexcept {
  360. return IsTTY() ? "\033[1;31m" : "";
  361. }
  362. TStringBuf TColors::LightPurpleColor() const noexcept {
  363. return IsTTY() ? "\033[1;35m" : "";
  364. }
  365. TStringBuf TColors::YellowColor() const noexcept {
  366. return IsTTY() ? "\033[1;33m" : "";
  367. }
  368. TStringBuf TColors::WhiteColor() const noexcept {
  369. return IsTTY() ? "\033[1;37m" : "";
  370. }
  371. namespace {
  372. class TStdErrColors: public TColors {
  373. public:
  374. TStdErrColors()
  375. : TColors(stderr)
  376. {
  377. }
  378. };
  379. class TStdOutColors: public TColors {
  380. public:
  381. TStdOutColors()
  382. : TColors(stdout)
  383. {
  384. }
  385. };
  386. class TDisabledColors: public TColors {
  387. public:
  388. TDisabledColors()
  389. : TColors(false)
  390. {
  391. }
  392. };
  393. } // anonymous namespace
  394. TColors& NColorizer::StdErr() {
  395. return *Singleton<TStdErrColors>();
  396. }
  397. TColors& NColorizer::StdOut() {
  398. return *Singleton<TStdOutColors>();
  399. }
  400. TColors& NColorizer::AutoColors(IOutputStream& os) {
  401. if (&os == &Cerr) {
  402. return StdErr();
  403. }
  404. if (&os == &Cout) {
  405. return StdOut();
  406. }
  407. return *Singleton<TDisabledColors>();
  408. }
  409. size_t NColorizer::TotalAnsiEscapeCodeLen(TStringBuf text) {
  410. enum {
  411. TEXT,
  412. BEFORE_CODE,
  413. IN_CODE,
  414. } state = TEXT;
  415. size_t totalLen = 0;
  416. size_t curLen = 0;
  417. for (auto it = text.begin(); it < text.end(); ++it) {
  418. switch (state) {
  419. case TEXT:
  420. if (*it == '\033') {
  421. state = BEFORE_CODE;
  422. curLen = 1;
  423. }
  424. break;
  425. case BEFORE_CODE:
  426. if (*it == '[') {
  427. state = IN_CODE;
  428. curLen++;
  429. } else {
  430. state = TEXT;
  431. }
  432. break;
  433. case IN_CODE:
  434. if (*it == ';' || isdigit(*it)) {
  435. curLen++;
  436. } else {
  437. if (*it == 'm') {
  438. totalLen += curLen + 1;
  439. }
  440. state = TEXT;
  441. }
  442. break;
  443. }
  444. }
  445. return totalLen;
  446. }