1 #include <chrono>
2 #include <cstdlib>
3 #include <cstring>
4 #include <ctime>
5 #include <wctype.h>
6 
7 #include "util.hxx"
8 
9 namespace replxx {
10 
11 int mk_wcwidth( char32_t );
12 
13 /**
14  * Calculate a new screen position given a starting position, screen width and
15  * character count
16  * @param x             - initial x position (zero-based)
17  * @param y             - initial y position (zero-based)
18  * @param screenColumns - screen column count
19  * @param charCount     - character positions to advance
20  * @param xOut          - returned x position (zero-based)
21  * @param yOut          - returned y position (zero-based)
22  */
calculate_screen_position(int x,int y,int screenColumns,int charCount,int & xOut,int & yOut)23 void calculate_screen_position(
24 	int x, int y, int screenColumns,
25 	int charCount, int& xOut, int& yOut
26 ) {
27 	xOut = x;
28 	yOut = y;
29 	int charsRemaining = charCount;
30 	while ( charsRemaining > 0 ) {
31 		int charsThisRow = ( ( x + charsRemaining ) < screenColumns )
32 			? charsRemaining
33 			: screenColumns - x;
34 		xOut = x + charsThisRow;
35 		yOut = y;
36 		charsRemaining -= charsThisRow;
37 		x = 0;
38 		++ y;
39 	}
40 	if ( xOut == screenColumns ) {	// we have to special-case line wrap
41 		xOut = 0;
42 		++ yOut;
43 	}
44 }
45 
46 /**
47  * Calculate a column width using mk_wcswidth()
48  * @param buf32 - text to calculate
49  * @param len   - length of text to calculate
50  */
calculate_displayed_length(char32_t const * buf32_,int size_)51 int calculate_displayed_length( char32_t const* buf32_, int size_ ) {
52 	int len( 0 );
53 	for ( int i( 0 ); i < size_; ++ i ) {
54 		char32_t c( buf32_[i] );
55 		if ( c == '\033' ) {
56 			int escStart( i );
57 			++ i;
58 			if ( ( i < size_ ) && ( buf32_[i] != '[' ) ) {
59 				i = escStart;
60 				++ len;
61 				continue;
62 			}
63 			++ i;
64 			for ( ; i < size_; ++ i ) {
65 				c = buf32_[i];
66 				if ( ( c != ';' ) && ( ( c < '0' ) || ( c > '9' ) ) ) {
67 					break;
68 				}
69 			}
70 			if ( ( i < size_ ) && ( buf32_[i] == 'm' ) ) {
71 				continue;
72 			}
73 			i = escStart;
74 			len += 2;
75 		} else if ( is_control_code( c ) ) {
76 			len += 2;
77 		} else {
78 			int wcw( mk_wcwidth( c ) );
79 			if ( wcw < 0 ) {
80 				len = -1;
81 				break;
82 			}
83 			len += wcw;
84 		}
85 	}
86 	return ( len );
87 }
88 
ansi_color(Replxx::Color color_)89 char const* ansi_color( Replxx::Color color_ ) {
90 	static char const reset[] = "\033[0m";
91 	static char const black[] = "\033[0;22;30m";
92 	static char const red[] = "\033[0;22;31m";
93 	static char const green[] = "\033[0;22;32m";
94 	static char const brown[] = "\033[0;22;33m";
95 	static char const blue[] = "\033[0;22;34m";
96 	static char const magenta[] = "\033[0;22;35m";
97 	static char const cyan[] = "\033[0;22;36m";
98 	static char const lightgray[] = "\033[0;22;37m";
99 
100 #ifdef _WIN32
101 	static bool const has256colorDefault( true );
102 #else
103 	static bool const has256colorDefault( false );
104 #endif
105 	static char const* TERM( getenv( "TERM" ) );
106 	static bool const has256color( TERM ? ( strstr( TERM, "256" ) != nullptr ) : has256colorDefault );
107 	static char const* gray = has256color ? "\033[0;1;90m" : "\033[0;1;30m";
108 	static char const* brightred = has256color ? "\033[0;1;91m" : "\033[0;1;31m";
109 	static char const* brightgreen = has256color ? "\033[0;1;92m" : "\033[0;1;32m";
110 	static char const* yellow = has256color ? "\033[0;1;93m" : "\033[0;1;33m";
111 	static char const* brightblue = has256color ? "\033[0;1;94m" : "\033[0;1;34m";
112 	static char const* brightmagenta = has256color ? "\033[0;1;95m" : "\033[0;1;35m";
113 	static char const* brightcyan = has256color ? "\033[0;1;96m" : "\033[0;1;36m";
114 	static char const* white = has256color ? "\033[0;1;97m" : "\033[0;1;37m";
115 	static char const error[] = "\033[101;1;33m";
116 
117 	char const* code( reset );
118 	switch ( color_ ) {
119 		case Replxx::Color::BLACK:         code = black;         break;
120 		case Replxx::Color::RED:           code = red;           break;
121 		case Replxx::Color::GREEN:         code = green;         break;
122 		case Replxx::Color::BROWN:         code = brown;         break;
123 		case Replxx::Color::BLUE:          code = blue;          break;
124 		case Replxx::Color::MAGENTA:       code = magenta;       break;
125 		case Replxx::Color::CYAN:          code = cyan;          break;
126 		case Replxx::Color::LIGHTGRAY:     code = lightgray;     break;
127 		case Replxx::Color::GRAY:          code = gray;          break;
128 		case Replxx::Color::BRIGHTRED:     code = brightred;     break;
129 		case Replxx::Color::BRIGHTGREEN:   code = brightgreen;   break;
130 		case Replxx::Color::YELLOW:        code = yellow;        break;
131 		case Replxx::Color::BRIGHTBLUE:    code = brightblue;    break;
132 		case Replxx::Color::BRIGHTMAGENTA: code = brightmagenta; break;
133 		case Replxx::Color::BRIGHTCYAN:    code = brightcyan;    break;
134 		case Replxx::Color::WHITE:         code = white;         break;
135 		case Replxx::Color::ERROR:         code = error;         break;
136 		case Replxx::Color::DEFAULT:       code = reset;         break;
137 	}
138 	return ( code );
139 }
140 
now_ms_str(void)141 std::string now_ms_str( void ) {
142 	std::chrono::milliseconds ms( std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::system_clock::now().time_since_epoch() ) );
143 	time_t t( ms.count() / 1000 );
144 	tm broken;
145 #ifdef _WIN32
146 #define localtime_r( t, b ) localtime_s( ( b ), ( t ) )
147 #endif
148 	localtime_r( &t, &broken );
149 #undef localtime_r
150 	static int const BUFF_SIZE( 32 );
151 	char str[BUFF_SIZE];
152 	strftime( str, BUFF_SIZE, "%Y-%m-%d %H:%M:%S.", &broken );
153 	snprintf( str + sizeof ( "YYYY-mm-dd HH:MM:SS" ), 5, "%03d", static_cast<int>( ms.count() % 1000 ) );
154 	return ( str );
155 }
156 
157 }
158 
159