Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/extern/isocline/src/attr.c
2727 views
1
/* ----------------------------------------------------------------------------
2
Copyright (c) 2021, Daan Leijen
3
This is free software; you can redistribute it and/or modify it
4
under the terms of the MIT License. A copy of the license can be
5
found in the "LICENSE" file at the root of this distribution.
6
-----------------------------------------------------------------------------*/
7
#include <string.h>
8
9
#include "common.h"
10
#include "stringbuf.h" // str_next_ofs
11
#include "attr.h"
12
#include "term.h" // color_from_ansi256
13
14
//-------------------------------------------------------------
15
// Attributes
16
//-------------------------------------------------------------
17
18
ic_private attr_t attr_none(void) {
19
attr_t attr;
20
attr.value = 0;
21
return attr;
22
}
23
24
ic_private attr_t attr_default(void) {
25
attr_t attr = attr_none();
26
attr.x.color = IC_ANSI_DEFAULT;
27
attr.x.bgcolor = IC_ANSI_DEFAULT;
28
attr.x.bold = IC_OFF;
29
attr.x.underline = IC_OFF;
30
attr.x.reverse = IC_OFF;
31
attr.x.italic = IC_OFF;
32
return attr;
33
}
34
35
ic_private bool attr_is_none(attr_t attr) {
36
return (attr.value == 0);
37
}
38
39
ic_private bool attr_is_eq(attr_t attr1, attr_t attr2) {
40
return (attr1.value == attr2.value);
41
}
42
43
ic_private attr_t attr_from_color( ic_color_t color ) {
44
attr_t attr = attr_none();
45
attr.x.color = color;
46
return attr;
47
}
48
49
50
ic_private attr_t attr_update_with( attr_t oldattr, attr_t newattr ) {
51
attr_t attr = oldattr;
52
if (newattr.x.color != IC_COLOR_NONE) { attr.x.color = newattr.x.color; }
53
if (newattr.x.bgcolor != IC_COLOR_NONE) { attr.x.bgcolor = newattr.x.bgcolor; }
54
if (newattr.x.bold != IC_NONE) { attr.x.bold = newattr.x.bold; }
55
if (newattr.x.italic != IC_NONE) { attr.x.italic = newattr.x.italic; }
56
if (newattr.x.reverse != IC_NONE) { attr.x.reverse = newattr.x.reverse; }
57
if (newattr.x.underline != IC_NONE) { attr.x.underline = newattr.x.underline; }
58
return attr;
59
}
60
61
static bool sgr_is_digit(char c) {
62
return (c >= '0' && c <= '9');
63
}
64
65
static bool sgr_is_sep( char c ) {
66
return (c==';' || c==':');
67
}
68
69
static bool sgr_next_par(const char* s, ssize_t* pi, ssize_t* par) {
70
const ssize_t i = *pi;
71
ssize_t n = 0;
72
while( sgr_is_digit(s[i+n])) {
73
n++;
74
}
75
if (n==0) {
76
*par = 0;
77
return true;
78
}
79
else {
80
*pi = i+n;
81
return ic_atoz(s+i, par);
82
}
83
}
84
85
static bool sgr_next_par3(const char* s, ssize_t* pi, ssize_t* p1, ssize_t* p2, ssize_t* p3) {
86
bool ok = false;
87
ssize_t i = *pi;
88
if (sgr_next_par(s,&i,p1) && sgr_is_sep(s[i])) {
89
i++;
90
if (sgr_next_par(s,&i,p2) && sgr_is_sep(s[i])) {
91
i++;
92
if (sgr_next_par(s,&i,p3)) {
93
ok = true;
94
};
95
}
96
}
97
*pi = i;
98
return ok;
99
}
100
101
ic_private attr_t attr_from_sgr( const char* s, ssize_t len) {
102
attr_t attr = attr_none();
103
for( ssize_t i = 0; i < len && s[i] != 0; i++) {
104
ssize_t cmd = 0;
105
if (!sgr_next_par(s,&i,&cmd)) continue;
106
switch(cmd) {
107
case 0: attr = attr_default(); break;
108
case 1: attr.x.bold = IC_ON; break;
109
case 3: attr.x.italic = IC_ON; break;
110
case 4: attr.x.underline = IC_ON; break;
111
case 7: attr.x.reverse = IC_ON; break;
112
case 22: attr.x.bold = IC_OFF; break;
113
case 23: attr.x.italic = IC_OFF; break;
114
case 24: attr.x.underline = IC_OFF; break;
115
case 27: attr.x.reverse = IC_OFF; break;
116
case 39: attr.x.color = IC_ANSI_DEFAULT; break;
117
case 49: attr.x.bgcolor = IC_ANSI_DEFAULT; break;
118
default: {
119
if (cmd >= 30 && cmd <= 37) {
120
attr.x.color = IC_ANSI_BLACK + (unsigned)(cmd - 30);
121
}
122
else if (cmd >= 40 && cmd <= 47) {
123
attr.x.bgcolor = IC_ANSI_BLACK + (unsigned)(cmd - 40);
124
}
125
else if (cmd >= 90 && cmd <= 97) {
126
attr.x.color = IC_ANSI_DARKGRAY + (unsigned)(cmd - 90);
127
}
128
else if (cmd >= 100 && cmd <= 107) {
129
attr.x.bgcolor = IC_ANSI_DARKGRAY + (unsigned)(cmd - 100);
130
}
131
else if ((cmd == 38 || cmd == 48) && sgr_is_sep(s[i])) {
132
// non-associative SGR :-(
133
ssize_t par = 0;
134
i++;
135
if (sgr_next_par(s, &i, &par)) {
136
if (par==5 && sgr_is_sep(s[i])) {
137
// ansi 256 index
138
i++;
139
if (sgr_next_par(s, &i, &par) && par >= 0 && par <= 0xFF) {
140
ic_color_t color = color_from_ansi256(par);
141
if (cmd==38) { attr.x.color = color; }
142
else { attr.x.bgcolor = color; }
143
}
144
}
145
else if (par == 2 && sgr_is_sep(s[i])) {
146
// rgb value
147
i++;
148
ssize_t r,g,b;
149
if (sgr_next_par3(s, &i, &r,&g,&b)) {
150
ic_color_t color = ic_rgbx(r,g,b);
151
if (cmd==38) { attr.x.color = color; }
152
else { attr.x.bgcolor = color; }
153
}
154
}
155
}
156
}
157
else {
158
debug_msg("attr: unknow ANSI SGR code: %zd\n", cmd );
159
}
160
}
161
}
162
}
163
return attr;
164
}
165
166
ic_private attr_t attr_from_esc_sgr( const char* s, ssize_t len) {
167
if (len <= 2 || s[0] != '\x1B' || s[1] != '[' || s[len-1] != 'm') return attr_none();
168
return attr_from_sgr(s+2, len-2);
169
}
170
171
172
//-------------------------------------------------------------
173
// Attribute buffer
174
//-------------------------------------------------------------
175
struct attrbuf_s {
176
attr_t* attrs;
177
ssize_t capacity;
178
ssize_t count;
179
alloc_t* mem;
180
};
181
182
static bool attrbuf_ensure_capacity( attrbuf_t* ab, ssize_t needed ) {
183
if (needed <= ab->capacity) return true;
184
ssize_t newcap = (ab->capacity <= 0 ? 240 : (ab->capacity > 1000 ? ab->capacity + 1000 : 2*ab->capacity));
185
if (needed > newcap) { newcap = needed; }
186
attr_t* newattrs = mem_realloc_tp( ab->mem, attr_t, ab->attrs, newcap );
187
if (newattrs == NULL) return false;
188
ab->attrs = newattrs;
189
ab->capacity = newcap;
190
assert(needed <= ab->capacity);
191
return true;
192
}
193
194
static bool attrbuf_ensure_extra( attrbuf_t* ab, ssize_t extra ) {
195
const ssize_t needed = ab->count + extra;
196
return attrbuf_ensure_capacity( ab, needed );
197
}
198
199
200
ic_private attrbuf_t* attrbuf_new( alloc_t* mem ) {
201
attrbuf_t* ab = mem_zalloc_tp(mem,attrbuf_t);
202
if (ab == NULL) return NULL;
203
ab->mem = mem;
204
attrbuf_ensure_extra(ab,1);
205
return ab;
206
}
207
208
ic_private void attrbuf_free( attrbuf_t* ab ) {
209
if (ab==NULL) return;
210
mem_free(ab->mem, ab->attrs);
211
mem_free(ab->mem, ab);
212
}
213
214
ic_private void attrbuf_clear(attrbuf_t* ab) {
215
if (ab == NULL) return;
216
ab->count = 0;
217
}
218
219
ic_private ssize_t attrbuf_len( attrbuf_t* ab ) {
220
return (ab==NULL ? 0 : ab->count);
221
}
222
223
ic_private const attr_t* attrbuf_attrs( attrbuf_t* ab, ssize_t expected_len ) {
224
assert(expected_len <= ab->count );
225
// expand if needed
226
if (ab->count < expected_len) {
227
if (!attrbuf_ensure_capacity(ab,expected_len)) return NULL;
228
for(ssize_t i = ab->count; i < expected_len; i++) {
229
ab->attrs[i] = attr_none();
230
}
231
ab->count = expected_len;
232
}
233
return ab->attrs;
234
}
235
236
237
238
static void attrbuf_update_set_at( attrbuf_t* ab, ssize_t pos, ssize_t count, attr_t attr, bool update ) {
239
const ssize_t end = pos + count;
240
if (!attrbuf_ensure_capacity(ab, end)) return;
241
ssize_t i;
242
// initialize if end is beyond the count (todo: avoid duplicate init and set if update==false?)
243
if (ab->count < end) {
244
for(i = ab->count; i < end; i++) {
245
ab->attrs[i] = attr_none();
246
}
247
ab->count = end;
248
}
249
// fill pos to end with attr
250
for(i = pos; i < end; i++) {
251
ab->attrs[i] = (update ? attr_update_with(ab->attrs[i],attr) : attr);
252
}
253
}
254
255
ic_private void attrbuf_set_at( attrbuf_t* ab, ssize_t pos, ssize_t count, attr_t attr ) {
256
attrbuf_update_set_at(ab, pos, count, attr, false);
257
}
258
259
ic_private void attrbuf_update_at( attrbuf_t* ab, ssize_t pos, ssize_t count, attr_t attr ) {
260
attrbuf_update_set_at(ab, pos, count, attr, true);
261
}
262
263
ic_private void attrbuf_insert_at( attrbuf_t* ab, ssize_t pos, ssize_t count, attr_t attr ) {
264
if (pos < 0 || pos > ab->count || count <= 0) return;
265
if (!attrbuf_ensure_extra(ab,count)) return;
266
ic_memmove( ab->attrs + pos + count, ab->attrs + pos, (ab->count - pos)*ssizeof(attr_t) );
267
ab->count += count;
268
attrbuf_set_at( ab, pos, count, attr );
269
}
270
271
272
// note: must allow ab == NULL!
273
ic_private ssize_t attrbuf_append_n( stringbuf_t* sb, attrbuf_t* ab, const char* s, ssize_t len, attr_t attr ) {
274
if (s == NULL || len == 0) return sbuf_len(sb);
275
if (ab != NULL) {
276
if (!attrbuf_ensure_extra(ab,len)) return sbuf_len(sb);
277
attrbuf_set_at(ab, ab->count, len, attr);
278
}
279
return sbuf_append_n(sb,s,len);
280
}
281
282
ic_private attr_t attrbuf_attr_at( attrbuf_t* ab, ssize_t pos ) {
283
if (ab==NULL || pos < 0 || pos > ab->count) return attr_none();
284
return ab->attrs[pos];
285
}
286
287
ic_private void attrbuf_delete_at( attrbuf_t* ab, ssize_t pos, ssize_t count ) {
288
if (ab==NULL || pos < 0 || pos > ab->count) return;
289
if (pos + count > ab->count) { count = ab->count - pos; }
290
if (count == 0) return;
291
assert(pos + count <= ab->count);
292
ic_memmove( ab->attrs + pos, ab->attrs + pos + count, ab->count - (pos + count) );
293
ab->count -= count;
294
}
295
296