83
78
static int text_font_draw_character(SpaceText *st, int x, int y, char c)
89
80
BLF_position(mono, x, y, 0);
90
BLF_draw(mono, str, 1);
81
BLF_draw(mono, &c, 1);
95
86
static int text_font_draw_character_utf8(SpaceText *st, int x, int y, const char *c)
97
char str[BLI_UTF8_MAX + 1];
98
size_t len = BLI_str_utf8_size(c);
88
const size_t len = BLI_str_utf8_size_safe(c);
102
89
BLF_position(mono, x, y, 0);
103
BLF_draw(mono, str, len);
90
BLF_draw(mono, c, len);
105
91
return st->cwidth;
108
/****************** flatten string **********************/
110
static void flatten_string_append(FlattenString *fs, const char *c, int accum, int len)
114
if (fs->pos + len > fs->len) {
115
char *nbuf; int *naccum;
118
nbuf = MEM_callocN(sizeof(*fs->buf) * fs->len, "fs->buf");
119
naccum = MEM_callocN(sizeof(*fs->accum) * fs->len, "fs->accum");
121
memcpy(nbuf, fs->buf, fs->pos * sizeof(*fs->buf));
122
memcpy(naccum, fs->accum, fs->pos * sizeof(*fs->accum));
124
if (fs->buf != fs->fixedbuf) {
126
MEM_freeN(fs->accum);
133
for (i = 0; i < len; i++)
135
fs->buf[fs->pos + i] = c[i];
136
fs->accum[fs->pos + i] = accum;
142
int flatten_string(SpaceText *st, FlattenString *fs, const char *in)
146
memset(fs, 0, sizeof(FlattenString));
147
fs->buf = fs->fixedbuf;
148
fs->accum = fs->fixedaccum;
149
fs->len = sizeof(fs->fixedbuf);
151
for (r = 0, i = 0; *in; r++) {
153
i = st->tabnumber - (total % st->tabnumber);
157
flatten_string_append(fs, " ", r, 1);
162
size_t len = BLI_str_utf8_size(in);
163
flatten_string_append(fs, in, r, len);
169
flatten_string_append(fs, "\0", r, 1);
174
void flatten_string_free(FlattenString *fs)
176
if (fs->buf != fs->fixedbuf)
178
if (fs->accum != fs->fixedaccum)
179
MEM_freeN(fs->accum);
182
/* Checks the specified source string for a Python built-in function name. This
183
* name must start at the beginning of the source string and must be followed by
184
* a non-identifier (see text_check_identifier(char)) or null character.
186
* If a built-in function is found, the length of the matching name is returned.
187
* Otherwise, -1 is returned.
190
* http://docs.python.org/py3k/reference/lexical_analysis.html#keywords
193
static int find_builtinfunc(char *string)
196
const char *builtinfuncs[] = {
197
/* "False", "None", "True", */ /* see find_bool() */
198
"and", "as", "assert", "break",
199
"class", "continue", "def", "del", "elif", "else", "except",
200
"finally", "for", "from", "global", "if", "import", "in",
201
"is", "lambda", "nonlocal", "not", "or", "pass", "raise",
202
"return", "try", "while", "with", "yield",
205
for (a = 0; a < sizeof(builtinfuncs) / sizeof(builtinfuncs[0]); a++) {
208
/* If we hit the end of a keyword... (eg. "def") */
209
if (builtinfuncs[a][i] == '\0') {
210
/* If we still have identifier chars in the source (eg. "definate") */
211
if (text_check_identifier(string[i]))
212
i = -1; /* No match */
213
break; /* Next keyword if no match, otherwise we're done */
215
/* If chars mismatch, move on to next keyword */
217
else if (string[i] != builtinfuncs[a][i]) {
219
break; /* Break inner loop, start next keyword */
223
if (i > 0) break; /* If we have a match, we're done */
228
/* Checks the specified source string for a Python special name. This name must
229
* start at the beginning of the source string and must be followed by a non-
230
* identifier (see text_check_identifier(char)) or null character.
232
* If a special name is found, the length of the matching name is returned.
233
* Otherwise, -1 is returned. */
235
static int find_specialvar(char *string)
238
/* Check for "def" */
239
if (string[0] == 'd' && string[1] == 'e' && string[2] == 'f')
241
/* Check for "class" */
242
else if (string[0] == 'c' && string[1] == 'l' && string[2] == 'a' && string[3] == 's' && string[4] == 's')
244
/* If next source char is an identifier (eg. 'i' in "definate") no match */
245
if (i == 0 || text_check_identifier(string[i]))
250
static int find_decorator(char *string)
252
if (string[0] == '@') {
254
while (text_check_identifier(string[i])) {
262
static int find_bool(char *string)
265
/* Check for "False" */
266
if (string[0] == 'F' && string[1] == 'a' && string[2] == 'l' && string[3] == 's' && string[4] == 'e')
268
/* Check for "True" */
269
else if (string[0] == 'T' && string[1] == 'r' && string[2] == 'u' && string[3] == 'e')
271
/* Check for "None" */
272
else if (string[0] == 'N' && string[1] == 'o' && string[2] == 'n' && string[3] == 'e')
274
/* If next source char is an identifier (eg. 'i' in "definate") no match */
275
if (i == 0 || text_check_identifier(string[i]))
280
/* Ensures the format string for the given line is long enough, reallocating
281
* as needed. Allocation is done here, alone, to ensure consistency. */
282
static int text_check_format_len(TextLine *line, unsigned int len)
285
if (strlen(line->format) < len) {
286
MEM_freeN(line->format);
287
line->format = MEM_mallocN(len + 2, "SyntaxFormat");
288
if (!line->format) return 0;
292
line->format = MEM_mallocN(len + 2, "SyntaxFormat");
293
if (!line->format) return 0;
299
/* Formats the specified line. If do_next is set, the process will move on to
300
* the succeeding line if it is affected (eg. multiline strings). Format strings
301
* may contain any of the following characters:
304
* '!' Punctuation and other symbols
307
* 'v' Special variables (class, def)
308
* 'b' Built-in names (print, for, etc.)
309
* 'q' Other text (identifiers, etc.)
310
* It is terminated with a null-terminator '\0' followed by a continuation
311
* flag indicating whether the line is part of a multi-line string. */
313
static void txt_format_line(SpaceText *st, TextLine *line, int do_next)
316
char *str, *fmt, orig, cont, find, prev = ' ';
319
/* Get continuation from previous line */
320
if (line->prev && line->prev->format != NULL) {
321
fmt = line->prev->format;
322
cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
326
/* Get original continuation from this line */
327
if (line->format != NULL) {
329
orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
333
len = flatten_string(st, &fs, line->line);
335
if (!text_check_format_len(line, len)) {
336
flatten_string_free(&fs);
342
/* Handle escape sequences by skipping both \ and next char */
344
*fmt = prev; fmt++; str++;
345
if (*str == '\0') break;
346
*fmt = prev; fmt++; str += BLI_str_utf8_size(str);
349
/* Handle continuations */
351
/* Triple strings ("""...""" or '''...''') */
352
if (cont & TXT_TRISTR) {
353
find = (cont & TXT_DBLQUOTSTR) ? '"' : '\'';
354
if (*str == find && *(str + 1) == find && *(str + 2) == find) {
355
*fmt = 'l'; fmt++; str++;
356
*fmt = 'l'; fmt++; str++;
359
/* Handle other strings */
362
find = (cont & TXT_DBLQUOTSTR) ? '"' : '\'';
363
if (*str == find) cont = 0;
367
str += BLI_str_utf8_size(str) - 1;
369
/* Not in a string... */
371
/* Deal with comments first */
372
if (prev == '#' || *str == '#') {
374
str += BLI_str_utf8_size(str) - 1;
376
else if (*str == '"' || *str == '\'') {
379
cont = (*str == '"') ? TXT_DBLQUOTSTR : TXT_SNGQUOTSTR;
380
if (*(str + 1) == find && *(str + 2) == find) {
381
*fmt = 'l'; fmt++; str++;
382
*fmt = 'l'; fmt++; str++;
387
/* Whitespace (all ws. has been converted to spaces) */
388
else if (*str == ' ')
390
/* Numbers (digits not part of an identifier and periods followed by digits) */
391
else if ((prev != 'q' && text_check_digit(*str)) || (*str == '.' && text_check_digit(*(str + 1))))
394
else if (prev != 'q' && (i = find_bool(str)) != -1)
397
*fmt = 'n'; fmt++; str++;
403
str += BLI_str_utf8_size(str) - 1;
407
else if (text_check_delim(*str))
409
/* Identifiers and other text (no previous ws. or delims. so text continues) */
410
else if (prev == 'q') {
411
str += BLI_str_utf8_size(str) - 1;
414
/* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
416
/* Special vars(v) or built-in keywords(b) */
417
if ((i = find_specialvar(str)) != -1)
419
else if ((i = find_builtinfunc(str)) != -1)
421
else if ((i = find_decorator(str)) != -1)
422
prev = 'v'; /* could have a new color for this */
425
*fmt = prev; fmt++; str++;
431
str += BLI_str_utf8_size(str) - 1;
441
/* Terminate and add continuation char */
445
/* If continuation has changed and we're allowed, process the next line */
446
if (cont != orig && do_next && line->next) {
447
txt_format_line(st, line->next, do_next);
450
flatten_string_free(&fs);
454
95
/* Formats every line of the current text */
455
96
static void txt_format_text(SpaceText *st)
1242
862
glDisable(GL_BLEND);
1245
/************************** draw markers **************************/
1247
static void draw_markers(SpaceText *st, ARegion *ar)
1249
Text *text = st->text;
1250
TextMarker *marker, *next;
1251
TextLine *top, *line;
1252
int offl, offc, i, x1, x2, y1, y2, x, y;
1255
/* Move pointer to first visible line (top) */
1256
top = first_visible_line(st, ar, NULL);
1257
topi = BLI_findindex(&text->lines, top);
1259
topy = txt_get_span(text->lines.first, top);
1261
for (marker = text->markers.first; marker; marker = next) {
1262
next = marker->next;
1264
/* invisible line (before top) */
1265
if (marker->lineno < topi) continue;
1267
line = BLI_findlink(&text->lines, marker->lineno);
1269
/* Remove broken markers */
1270
if (marker->end > line->len || marker->start > marker->end) {
1271
BLI_freelinkN(&text->markers, marker);
1275
wrap_offset(st, ar, line, marker->start, &offl, &offc);
1276
y1 = txt_get_span(top, line) - st->top + offl + topy;
1277
x1 = text_get_char_pos(st, line->line, marker->start) - st->left + offc;
1279
wrap_offset(st, ar, line, marker->end, &offl, &offc);
1280
y2 = txt_get_span(top, line) - st->top + offl + topy;
1281
x2 = text_get_char_pos(st, line->line, marker->end) - st->left + offc;
1283
/* invisible part of line (before top, after last visible line) */
1284
if (y2 < 0 || y1 > st->top + st->viewlines) continue;
1286
glColor3ubv(marker->color);
1287
x = st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET;
1291
y -= y1 * st->lheight;
1292
glBegin(GL_LINE_LOOP);
1293
glVertex2i(x + x2 * st->cwidth + 1, y);
1294
glVertex2i(x + x1 * st->cwidth - 2, y);
1295
glVertex2i(x + x1 * st->cwidth - 2, y - st->lheight);
1296
glVertex2i(x + x2 * st->cwidth + 1, y - st->lheight);
1300
y -= y1 * st->lheight;
1301
glBegin(GL_LINE_STRIP);
1302
glVertex2i(ar->winx, y);
1303
glVertex2i(x + x1 * st->cwidth - 2, y);
1304
glVertex2i(x + x1 * st->cwidth - 2, y - st->lheight);
1305
glVertex2i(ar->winx, y - st->lheight);
1309
for (i = y1 + 1; i < y2; i++) {
1312
glVertex2i(ar->winx, y);
1313
glVertex2i(x, y - st->lheight);
1314
glVertex2i(ar->winx, y - st->lheight);
1319
glBegin(GL_LINE_STRIP);
1321
glVertex2i(x + x2 * st->cwidth + 1, y);
1322
glVertex2i(x + x2 * st->cwidth + 1, y - st->lheight);
1323
glVertex2i(x, y - st->lheight);
1329
865
/*********************** draw documentation *******************************/
1331
867
static void draw_documentation(SpaceText *st, ARegion *ar)