summaryrefslogtreecommitdiffstats
path: root/contrib/replxx/src/util.cxx
blob: 719d7073d8f8dab64074e16a0a1590efe93a4d87 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <chrono>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <wctype.h>

#include "util.hxx"

namespace replxx {

int mk_wcwidth( char32_t );

/**
 * Calculate a new screen position given a starting position, screen width and
 * character count
 * @param x             - initial x position (zero-based)
 * @param y             - initial y position (zero-based)
 * @param screenColumns - screen column count
 * @param charCount     - character positions to advance
 * @param xOut          - returned x position (zero-based)
 * @param yOut          - returned y position (zero-based)
 */
void calculate_screen_position(
	int x, int y, int screenColumns,
	int charCount, int& xOut, int& yOut
) {
	xOut = x;
	yOut = y;
	int charsRemaining = charCount;
	while ( charsRemaining > 0 ) {
		int charsThisRow = ( ( x + charsRemaining ) < screenColumns )
			? charsRemaining
			: screenColumns - x;
		xOut = x + charsThisRow;
		yOut = y;
		charsRemaining -= charsThisRow;
		x = 0;
		++ y;
	}
	if ( xOut == screenColumns ) {	// we have to special-case line wrap
		xOut = 0;
		++ yOut;
	}
}

/**
 * Calculate a column width using mk_wcswidth()
 * @param buf32 - text to calculate
 * @param len   - length of text to calculate
 */
int calculate_displayed_length( char32_t const* buf32_, int size_ ) {
	int len( 0 );
	for ( int i( 0 ); i < size_; ++ i ) {
		char32_t c( buf32_[i] );
		if ( c == '\033' ) {
			int escStart( i );
			++ i;
			if ( ( i < size_ ) && ( buf32_[i] != '[' ) ) {
				i = escStart;
				++ len;
				continue;
			}
			++ i;
			for ( ; i < size_; ++ i ) {
				c = buf32_[i];
				if ( ( c != ';' ) && ( ( c < '0' ) || ( c > '9' ) ) ) {
					break;
				}
			}
			if ( ( i < size_ ) && ( buf32_[i] == 'm' ) ) {
				continue;
			}
			i = escStart;
			len += 2;
		} else if ( is_control_code( c ) ) {
			len += 2;
		} else {
			int wcw( mk_wcwidth( c ) );
			if ( wcw < 0 ) {
				len = -1;
				break;
			}
			len += wcw;
		}
	}
	return ( len );
}

char const* ansi_color( Replxx::Color color_ ) {
	static char const reset[] = "\033[0m";
	static char const black[] = "\033[0;22;30m";
	static char const red[] = "\033[0;22;31m";
	static char const green[] = "\033[0;22;32m";
	static char const brown[] = "\033[0;22;33m";
	static char const blue[] = "\033[0;22;34m";
	static char const magenta[] = "\033[0;22;35m";
	static char const cyan[] = "\033[0;22;36m";
	static char const lightgray[] = "\033[0;22;37m";

#ifdef _WIN32
	static bool const has256colorDefault( true );
#else
	static bool const has256colorDefault( false );
#endif
	static char const* TERM( getenv( "TERM" ) );
	static bool const has256color( TERM ? ( strstr( TERM, "256" ) != nullptr ) : has256colorDefault );
	static char const* gray = has256color ? "\033[0;1;90m" : "\033[0;1;30m";
	static char const* brightred = has256color ? "\033[0;1;91m" : "\033[0;1;31m";
	static char const* brightgreen = has256color ? "\033[0;1;92m" : "\033[0;1;32m";
	static char const* yellow = has256color ? "\033[0;1;93m" : "\033[0;1;33m";
	static char const* brightblue = has256color ? "\033[0;1;94m" : "\033[0;1;34m";
	static char const* brightmagenta = has256color ? "\033[0;1;95m" : "\033[0;1;35m";
	static char const* brightcyan = has256color ? "\033[0;1;96m" : "\033[0;1;36m";
	static char const* white = has256color ? "\033[0;1;97m" : "\033[0;1;37m";
	static char const error[] = "\033[101;1;33m";

	char const* code( reset );
	switch ( color_ ) {
		case Replxx::Color::BLACK:         code = black;         break;
		case Replxx::Color::RED:           code = red;           break;
		case Replxx::Color::GREEN:         code = green;         break;
		case Replxx::Color::BROWN:         code = brown;         break;
		case Replxx::Color::BLUE:          code = blue;          break;
		case Replxx::Color::MAGENTA:       code = magenta;       break;
		case Replxx::Color::CYAN:          code = cyan;          break;
		case Replxx::Color::LIGHTGRAY:     code = lightgray;     break;
		case Replxx::Color::GRAY:          code = gray;          break;
		case Replxx::Color::BRIGHTRED:     code = brightred;     break;
		case Replxx::Color::BRIGHTGREEN:   code = brightgreen;   break;
		case Replxx::Color::YELLOW:        code = yellow;        break;
		case Replxx::Color::BRIGHTBLUE:    code = brightblue;    break;
		case Replxx::Color::BRIGHTMAGENTA: code = brightmagenta; break;
		case Replxx::Color::BRIGHTCYAN:    code = brightcyan;    break;
		case Replxx::Color::WHITE:         code = white;         break;
		case Replxx::Color::ERROR:         code = error;         break;
		case Replxx::Color::DEFAULT:       code = reset;         break;
	}
	return ( code );
}

std::string now_ms_str( void ) {
	std::chrono::milliseconds ms( std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::system_clock::now().time_since_epoch() ) );
	time_t t( ms.count() / 1000 );
	tm broken;
#ifdef _WIN32
#define localtime_r( t, b ) localtime_s( ( b ), ( t ) )
#endif
	localtime_r( &t, &broken );
#undef localtime_r
	static int const BUFF_SIZE( 32 );
	char str[BUFF_SIZE];
	strftime( str, BUFF_SIZE, "%Y-%m-%d %H:%M:%S.", &broken );
	snprintf( str + sizeof ( "YYYY-mm-dd HH:MM:SS" ), 5, "%03d", static_cast<int>( ms.count() % 1000 ) );
	return ( str );
}

}