static void text_draw( const SpaceText *st, const TextDrawContext *tdc, char *str, int cshift, int maxwidth, int x, int y, const char *format) { const bool use_syntax = (st->showsyntax && format); FlattenString fs; int columns, size, n, w = 0, padding, amount = 0; const char *in = NULL; for (n = flatten_string(st, &fs, str), str = fs.buf; n > 0; n--) { columns = BLI_str_utf8_char_width_safe(str); size = BLI_str_utf8_size_safe(str); if (!in) { if (w >= cshift) { padding = w - cshift; in = str; } else if (format) format++; } if (in) { if (maxwidth && w + columns > cshift + maxwidth) break; amount++; } w += columns; str += size; } if (!in) { flatten_string_free(&fs); return; /* String is shorter than shift or ends with a padding */ } x += tdc->cwidth * padding; if (use_syntax) { int a, str_shift = 0; char fmt_prev = 0xff; for (a = 0; a < amount; a++) { if (format[a] != fmt_prev) format_draw_color(fmt_prev = format[a]); x += text_font_draw_character_utf8(tdc, x, y, in + str_shift); str_shift += BLI_str_utf8_size_safe(in + str_shift); } } else { text_font_draw(tdc, x, y, in); } flatten_string_free(&fs); }
int flatten_string(const SpaceText *st, FlattenString *fs, const char *in) { int r, i, total = 0; memset(fs, 0, sizeof(FlattenString)); fs->buf = fs->fixedbuf; fs->accum = fs->fixedaccum; fs->len = sizeof(fs->fixedbuf); for (r = 0, i = 0; *in; r++) { if (*in == '\t') { i = st->tabnumber - (total % st->tabnumber); total += i; while (i--) flatten_string_append(fs, " ", r, 1); in++; } else { size_t len = BLI_str_utf8_size_safe(in); flatten_string_append(fs, in, r, len); in += len; total++; } } flatten_string_append(fs, "\0", r, 1); return total; }
static int console_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event) { // if (!RNA_struct_property_is_set(op->ptr, "text")) { /* always set from keymap XXX */ if (!RNA_string_length(op->ptr, "text")) { /* if alt/ctrl/super are pressed pass through except for utf8 character event * (when input method are used for utf8 inputs, the user may assign key event * including alt/ctrl/super like ctrl+m to commit utf8 string. in such case, * the modifiers in the utf8 character event make no sense.) */ if ((event->ctrl || event->oskey) && !event->utf8_buf[0]) { return OPERATOR_PASS_THROUGH; } else { char str[BLI_UTF8_MAX + 1]; size_t len; if (event->utf8_buf[0]) { len = BLI_str_utf8_size_safe(event->utf8_buf); memcpy(str, event->utf8_buf, len); } else { /* in theory, ghost can set value to extended ascii here */ len = BLI_str_utf8_from_unicode(event->ascii, str); } str[len] = '\0'; RNA_string_set(op->ptr, "text", str); } } return console_insert_exec(C, op); }
static int text_font_draw_character_utf8(const TextDrawContext *tdc, int x, int y, const char *c) { int columns; const size_t len = BLI_str_utf8_size_safe(c); BLF_position(tdc->font_id, x, y, 0); columns = BLF_draw_mono(tdc->font_id, c, len, tdc->cwidth); return tdc->cwidth * columns; }
static int text_font_draw_character_utf8(SpaceText *st, int x, int y, const char *c) { int columns; const size_t len = BLI_str_utf8_size_safe(c); BLF_position(mono, x, y, 0); columns = BLF_draw_mono(mono, c, len, st->cwidth); return st->cwidth * columns; }
int text_get_char_pos(SpaceText *st, const char *line, int cur) { int a = 0, i; for (i = 0; i < cur && line[i]; i += BLI_str_utf8_size_safe(line + i)) { if (line[i] == '\t') a += st->tabnumber - a % st->tabnumber; else a += BLI_str_utf8_char_width_safe(line + i); } return a; }
static const char *txt_utf8_forward_columns(const char *str, int columns, int *padding) { int col; const char *p = str; while (*p) { col = BLI_str_utf8_char_width(p); if (columns - col < 0) break; columns -= col; p += BLI_str_utf8_size_safe(p); if (columns == 0) break; } if (padding) *padding = *p ? columns : 0; return p; }
static void console_cursor_wrap_offset(const char *str, int width, int *row, int *column, const char *end) { int col; for (; *str; str += BLI_str_utf8_size_safe(str)) { col = BLI_str_utf8_char_width_safe(str); if (*column + col > width) { (*row)++; *column = 0; } if (end && str >= end) break; *column += col; } return; }
/** * Fill the string with formatting constant, * advancing \a str_p and \a fmt_p * * \param len length in bytes of \a fmt_p to fill. */ void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len) { const char *str = *str_p; char *fmt = *fmt_p; int i = 0; while (i < len) { const int size = BLI_str_utf8_size_safe(str); *fmt++ = type; str += size; i += 1; } str--; fmt--; BLI_assert(*str != '\0'); *str_p = str; *fmt_p = fmt; }
int text_get_visible_lines(SpaceText *st, ARegion *ar, const char *str) { int i, j, start, end, max, lines, chars; char ch; max = wrap_width(st, ar); lines = 1; start = 0; end = max; for (i = 0, j = 0; str[j]; j += BLI_str_utf8_size_safe(str + j)) { int columns = BLI_str_utf8_char_width_safe(str + j); /* = 1 for tab */ /* Mimic replacement of tabs */ ch = str[j]; if (ch == '\t') { chars = st->tabnumber - i % st->tabnumber; ch = ' '; } else { chars = 1; } while (chars--) { if (i + columns - start > max) { lines++; start = MIN2(end, i); end += max; } else if (ch == ' ' || ch == '-') { end = i + 1; } i += columns; } } return lines; }
/* warning: allocated memory for 'offsets' must be freed by caller */ static int console_wrap_offsets(const char *str, int len, int width, int *lines, int **offsets) { int i, end; /* column */ int j; /* mem */ *lines = 1; *offsets = MEM_callocN(sizeof(**offsets) * (len * BLI_UTF8_WIDTH_MAX / MAX2(1, width - (BLI_UTF8_WIDTH_MAX - 1)) + 1), "console_wrap_offsets"); (*offsets)[0] = 0; for (i = 0, end = width, j = 0; j < len && str[j]; j += BLI_str_utf8_size_safe(str + j)) { int columns = BLI_str_utf8_char_width_safe(str + j); if (i + columns > end) { (*offsets)[*lines] = j; (*lines)++; end = i + width; } i += columns; } return j; /* return actual length */ }
static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w, const char *format, int skip) { FlattenString fs; int basex, lines; int i, wrap, end, max, columns, padding; /* column */ int a, fstart, fpos; /* utf8 chars */ int mi, ma, mstart, mend; /* mem */ char fmt_prev = 0xff; flatten_string(st, &fs, str); str = fs.buf; max = w / st->cwidth; if (max < 8) max = 8; basex = x; lines = 1; fpos = fstart = 0; mstart = 0; mend = txt_utf8_forward_columns(str, max, &padding) - str; end = wrap = max - padding; for (i = 0, mi = 0; str[mi]; i += columns, mi += BLI_str_utf8_size_safe(str + mi)) { columns = BLI_str_utf8_char_width_safe(str + mi); if (i + columns > end) { /* skip hidden part of line */ if (skip) { skip--; fstart = fpos; mstart = mend; mend = txt_utf8_forward_columns(str + mend, max, &padding) - str; end = (wrap += max - padding); continue; } /* Draw the visible portion of text on the overshot line */ for (a = fstart, ma = mstart; ma < mend; a++, ma += BLI_str_utf8_size_safe(str + ma)) { if (st->showsyntax && format) { if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]); } x += text_font_draw_character_utf8(st, x, y, str + ma); fpos++; } y -= st->lheight_dpi + TXT_LINE_SPACING; x = basex; lines++; fstart = fpos; mstart = mend; mend = txt_utf8_forward_columns(str + mend, max, &padding) - str; end = (wrap += max - padding); if (y <= 0) break; } else if (str[mi] == ' ' || str[mi] == '-') { wrap = i + 1; mend = mi + 1; } } /* Draw the remaining text */ for (a = fstart, ma = mstart; str[ma] && y > 0; a++, ma += BLI_str_utf8_size_safe(str + ma)) { if (st->showsyntax && format) { if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]); } x += text_font_draw_character_utf8(st, x, y, str + ma); } flatten_string_free(&fs); return lines; }
static int text_draw_wrapped( const SpaceText *st, const TextDrawContext *tdc, const char *str, int x, int y, int w, const char *format, int skip) { const bool use_syntax = (st->showsyntax && format); FlattenString fs; int basex, lines; int i, wrap, end, max, columns, padding; /* column */ /* warning, only valid when 'use_syntax' is set */ int a, fstart, fpos; /* utf8 chars */ int mi, ma, mstart, mend; /* mem */ char fmt_prev = 0xff; /* don't draw lines below this */ const int clip_min_y = -(int)(st->lheight_dpi - 1); flatten_string(st, &fs, str); str = fs.buf; max = w / st->cwidth; if (max < 8) max = 8; basex = x; lines = 1; fpos = fstart = 0; mstart = 0; mend = txt_utf8_forward_columns(str, max, &padding) - str; end = wrap = max - padding; for (i = 0, mi = 0; str[mi]; i += columns, mi += BLI_str_utf8_size_safe(str + mi)) { columns = BLI_str_utf8_char_width_safe(str + mi); if (i + columns > end) { /* skip hidden part of line */ if (skip) { skip--; if (use_syntax) { /* currently fpos only used when formatting */ fpos += BLI_strnlen_utf8(str + mstart, mend - mstart); } fstart = fpos; mstart = mend; mend = txt_utf8_forward_columns(str + mend, max, &padding) - str; end = (wrap += max - padding); continue; } /* Draw the visible portion of text on the overshot line */ for (a = fstart, ma = mstart; ma < mend; a++, ma += BLI_str_utf8_size_safe(str + ma)) { if (use_syntax) { if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]); } x += text_font_draw_character_utf8(tdc, x, y, str + ma); fpos++; } y -= st->lheight_dpi + TXT_LINE_SPACING; x = basex; lines++; fstart = fpos; mstart = mend; mend = txt_utf8_forward_columns(str + mend, max, &padding) - str; end = (wrap += max - padding); if (y <= clip_min_y) break; } else if (str[mi] == ' ' || str[mi] == '-') { wrap = i + 1; mend = mi + 1; } } /* Draw the remaining text */ for (a = fstart, ma = mstart; str[ma] && y > clip_min_y; a++, ma += BLI_str_utf8_size_safe(str + ma)) { if (use_syntax) { if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]); } x += text_font_draw_character_utf8(tdc, x, y, str + ma); } flatten_string_free(&fs); return lines; }
/* cursin - mem, offc - view */ void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *offl, int *offc) { int i, j, start, end, chars, max, chop; char ch; *offl = *offc = 0; if (!st->text) return; if (!st->wordwrap) return; max = wrap_width(st, ar); start = 0; end = max; chop = 1; *offc = 0; cursin = txt_utf8_offset_to_column(linein->line, cursin); for (i = 0, j = 0; linein->line[j]; j += BLI_str_utf8_size_safe(linein->line + j)) { int columns = BLI_str_utf8_char_width_safe(linein->line + j); /* = 1 for tab */ /* Mimic replacement of tabs */ ch = linein->line[j]; if (ch == '\t') { chars = st->tabnumber - i % st->tabnumber; if (i < cursin) cursin += chars - 1; ch = ' '; } else chars = 1; while (chars--) { if (i + columns - start > max) { end = MIN2(end, i); if (chop && i >= cursin) { if (i == cursin) { (*offl)++; *offc -= end - start; } return; } (*offl)++; *offc -= end - start; start = end; end += max; chop = 1; } else if (ch == ' ' || ch == '-') { end = i + 1; chop = 0; if (i >= cursin) return; } i += columns; } } }
/* Sets (offl, offc) for transforming (line, curs) to its wrapped position */ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *offl, int *offc) { Text *text; TextLine *linep; int i, j, start, end, max, chop; char ch; *offl = *offc = 0; if (!st->text) return; if (!st->wordwrap) return; text = st->text; /* Move pointer to first visible line (top) */ linep = text->lines.first; i = st->top; while (i > 0 && linep) { int lines = text_get_visible_lines(st, ar, linep->line); /* Line before top */ if (linep == linein) { if (lines <= i) /* no visible part of line */ return; } if (i - lines < 0) { break; } else { linep = linep->next; (*offl) += lines - 1; i -= lines; } } max = wrap_width(st, ar); cursin = txt_utf8_offset_to_column(linein->line, cursin); while (linep) { start = 0; end = max; chop = 1; *offc = 0; for (i = 0, j = 0; linep->line[j]; j += BLI_str_utf8_size_safe(linep->line + j)) { int chars; int columns = BLI_str_utf8_char_width_safe(linep->line + j); /* = 1 for tab */ /* Mimic replacement of tabs */ ch = linep->line[j]; if (ch == '\t') { chars = st->tabnumber - i % st->tabnumber; if (linep == linein && i < cursin) cursin += chars - 1; ch = ' '; } else { chars = 1; } while (chars--) { if (i + columns - start > max) { end = MIN2(end, i); if (chop && linep == linein && i >= cursin) { if (i == cursin) { (*offl)++; *offc -= end - start; } return; } (*offl)++; *offc -= end - start; start = end; end += max; chop = 1; } else if (ch == ' ' || ch == '-') { end = i + 1; chop = 0; if (linep == linein && i >= cursin) return; } i += columns; } } if (linep == linein) break; linep = linep->next; } }
static void draw_brackets(SpaceText *st, ARegion *ar) { TextLine *startl, *endl, *linep; Text *text = st->text; int b, fc, find, stack, viewc, viewl, offl, offc, x, y; int startc, endc, c; char ch; // showsyntax must be on or else the format string will be null if (!text->curl || !st->showsyntax) return; startl = text->curl; startc = text->curc; b = text_check_bracket(startl->line[startc]); if (b == 0 && startc > 0) b = text_check_bracket(startl->line[--startc]); if (b == 0) return; linep = startl; c = startc; fc = txt_utf8_offset_to_index(linep->line, startc); endl = NULL; endc = -1; find = -b; stack = 0; /* Don't highlight backets if syntax HL is off or bracket in string or comment. */ if (!linep->format || linep->format[fc] == FMT_TYPE_STRING || linep->format[fc] == FMT_TYPE_COMMENT) return; if (b > 0) { /* opening bracket, search forward for close */ fc++; c += BLI_str_utf8_size_safe(linep->line + c); while (linep) { while (c < linep->len) { if (linep->format && linep->format[fc] != FMT_TYPE_STRING && linep->format[fc] != FMT_TYPE_COMMENT) { b = text_check_bracket(linep->line[c]); if (b == find) { if (stack == 0) { endl = linep; endc = c; break; } stack--; } else if (b == -find) { stack++; } } fc++; c += BLI_str_utf8_size_safe(linep->line + c); } if (endl) break; linep = linep->next; c = 0; fc = 0; } } else { /* closing bracket, search backward for open */ fc--; if (c > 0) c -= linep->line + c - BLI_str_prev_char_utf8(linep->line + c); while (linep) { while (fc >= 0) { if (linep->format && linep->format[fc] != FMT_TYPE_STRING && linep->format[fc] != FMT_TYPE_COMMENT) { b = text_check_bracket(linep->line[c]); if (b == find) { if (stack == 0) { endl = linep; endc = c; break; } stack--; } else if (b == -find) { stack++; } } fc--; if (c > 0) c -= linep->line + c - BLI_str_prev_char_utf8(linep->line + c); } if (endl) break; linep = linep->prev; if (linep) { if (linep->format) fc = strlen(linep->format) - 1; else fc = -1; if (linep->len) c = BLI_str_prev_char_utf8(linep->line + linep->len) - linep->line; else fc = -1; } } } if (!endl || endc == -1) return; UI_ThemeColor(TH_HILITE); x = st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET; y = ar->winy - st->lheight_dpi; /* draw opening bracket */ ch = startl->line[startc]; wrap_offset(st, ar, startl, startc, &offl, &offc); viewc = text_get_char_pos(st, startl->line, startc) - st->left + offc; if (viewc >= 0) { viewl = txt_get_span(text->lines.first, startl) - st->top + offl; text_font_draw_character(st, x + viewc * st->cwidth, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch); text_font_draw_character(st, x + viewc * st->cwidth + 1, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch); } /* draw closing bracket */ ch = endl->line[endc]; wrap_offset(st, ar, endl, endc, &offl, &offc); viewc = text_get_char_pos(st, endl->line, endc) - st->left + offc; if (viewc >= 0) { viewl = txt_get_span(text->lines.first, endl) - st->top + offl; text_font_draw_character(st, x + viewc * st->cwidth, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch); text_font_draw_character(st, x + viewc * st->cwidth + 1, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch); } }
static void txtfmt_lua_format_line(SpaceText *st, TextLine *line, const bool do_next) { FlattenString fs; const char *str; char *fmt; char cont_orig, cont, find, prev = ' '; int len, i; /* Get continuation from previous line */ if (line->prev && line->prev->format != NULL) { fmt = line->prev->format; cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */ BLI_assert((FMT_CONT_ALL & cont) == cont); } else { cont = FMT_CONT_NOP; } /* Get original continuation from this line */ if (line->format != NULL) { fmt = line->format; cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */ BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig); } else { cont_orig = 0xFF; } len = flatten_string(st, &fs, line->line); str = fs.buf; if (!text_check_format_len(line, len)) { flatten_string_free(&fs); return; } fmt = line->format; while (*str) { /* Handle escape sequences by skipping both \ and next char */ if (*str == '\\') { *fmt = prev; fmt++; str++; if (*str == '\0') break; *fmt = prev; fmt++; str += BLI_str_utf8_size_safe(str); continue; } /* Handle continuations */ else if (cont) { /* Multi-line comments */ if (cont & FMT_CONT_COMMENT_C) { if (*str == ']' && *(str + 1) == ']') { *fmt = FMT_TYPE_COMMENT; fmt++; str++; *fmt = FMT_TYPE_COMMENT; cont = FMT_CONT_NOP; } else { *fmt = FMT_TYPE_COMMENT; } /* Handle other comments */ } else { find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\''; if (*str == find) cont = 0; *fmt = FMT_TYPE_STRING; } str += BLI_str_utf8_size_safe(str) - 1; } /* Not in a string... */ else { /* Multi-line comments */ if (*str == '-' && *(str + 1) == '-' && *(str + 2) == '[' && *(str + 3) == '[') { cont = FMT_CONT_COMMENT_C; *fmt = FMT_TYPE_COMMENT; fmt++; str++; *fmt = FMT_TYPE_COMMENT; fmt++; str++; *fmt = FMT_TYPE_COMMENT; fmt++; str++; *fmt = FMT_TYPE_COMMENT; } /* Single line comment */ else if (*str == '-' && *(str + 1) == '-') { text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format)); } else if (*str == '"' || *str == '\'') { /* Strings */ find = *str; cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE; *fmt = FMT_TYPE_STRING; } /* Whitespace (all ws. has been converted to spaces) */ else if (*str == ' ') { *fmt = FMT_TYPE_WHITESPACE; } /* Numbers (digits not part of an identifier and periods followed by digits) */ else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) || (*str == '.' && text_check_digit(*(str + 1)))) { *fmt = FMT_TYPE_NUMERAL; } /* Booleans */ else if (prev != FMT_TYPE_DEFAULT && (i = txtfmt_lua_find_bool(str)) != -1) { if (i > 0) { text_format_fill_ascii(&str, &fmt, FMT_TYPE_NUMERAL, i); } else { str += BLI_str_utf8_size_safe(str) - 1; *fmt = FMT_TYPE_DEFAULT; } } /* Punctuation */ else if ((*str != '#') && text_check_delim(*str)) { *fmt = FMT_TYPE_SYMBOL; } /* Identifiers and other text (no previous ws. or delims. so text continues) */ else if (prev == FMT_TYPE_DEFAULT) { str += BLI_str_utf8_size_safe(str) - 1; *fmt = FMT_TYPE_DEFAULT; } /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */ else { /* Special vars(v) or built-in keywords(b) */ /* keep in sync with 'txtfmt_osl_format_identifier()' */ if ((i = txtfmt_lua_find_specialvar(str)) != -1) prev = FMT_TYPE_SPECIAL; else if ((i = txtfmt_lua_find_keyword(str)) != -1) prev = FMT_TYPE_KEYWORD; if (i > 0) { text_format_fill_ascii(&str, &fmt, prev, i); } else { str += BLI_str_utf8_size_safe(str) - 1; *fmt = FMT_TYPE_DEFAULT; } } } prev = *fmt; fmt++; str++; } /* Terminate and add continuation char */ *fmt = '\0'; fmt++; *fmt = cont; /* If continuation has changed and we're allowed, process the next line */ if (cont != cont_orig && do_next && line->next) { txtfmt_lua_format_line(st, line->next, do_next); } flatten_string_free(&fs); }