static void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Integer endcol, Integer clearcol, Integer clearattr, const schar_T *chunk, const sattr_T *attrs) { UIData *data = ui->data; if (ui->ui_ext[kUINewgrid]) { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(grid)); ADD(args, INTEGER_OBJ(row)); ADD(args, INTEGER_OBJ(startcol)); Array cells = ARRAY_DICT_INIT; int repeat = 0; size_t ncells = (size_t)(endcol-startcol); int last_hl = -1; for (size_t i = 0; i < ncells; i++) { repeat++; if (i == ncells-1 || attrs[i] != attrs[i+1] || STRCMP(chunk[i], chunk[i+1])) { Array cell = ARRAY_DICT_INIT; ADD(cell, STRING_OBJ(cstr_to_string((const char *)chunk[i]))); if (attrs[i] != last_hl || repeat > 1) { ADD(cell, INTEGER_OBJ(attrs[i])); last_hl = attrs[i]; } if (repeat > 1) { ADD(cell, INTEGER_OBJ(repeat)); } ADD(cells, ARRAY_OBJ(cell)); repeat = 0; } } if (endcol < clearcol) { Array cell = ARRAY_DICT_INIT; ADD(cell, STRING_OBJ(cstr_to_string(" "))); ADD(cell, INTEGER_OBJ(clearattr)); ADD(cell, INTEGER_OBJ(clearcol-endcol)); ADD(cells, ARRAY_OBJ(cell)); } ADD(args, ARRAY_OBJ(cells)); push_call(ui, "grid_line", args); } else { for (int i = 0; i < endcol-startcol; i++) { remote_ui_cursor_goto(ui, row, startcol+i); remote_ui_highlight_set(ui, attrs[i]); remote_ui_put(ui, (const char *)chunk[i]); if (utf_ambiguous_width(utf_ptr2char(chunk[i]))) { data->client_col = -1; // force cursor update } } if (endcol < clearcol) { remote_ui_cursor_goto(ui, row, endcol); remote_ui_highlight_set(ui, (int)clearattr); // legacy eol_clear was only ever used with cleared attributes // so be on the safe side if (clearattr == 0 && clearcol == Columns) { Array args = ARRAY_DICT_INIT; push_call(ui, "eol_clear", args); } else { for (Integer c = endcol; c < clearcol; c++) { remote_ui_put(ui, " "); } } } } }
/// Convert the string "str[orglen]" to do ignore-case comparing. Uses the /// current locale. /// /// When "buf" is NULL returns an allocated string (NULL for out-of-memory). /// Otherwise puts the result in "buf[buflen]". /// /// @param str /// @param orglen /// @param buf /// @param buflen /// /// @return converted string. char_u* str_foldcase(char_u *str, int orglen, char_u *buf, int buflen) { garray_T ga; int i; int len = orglen; #define GA_CHAR(i) ((char_u *)ga.ga_data)[i] #define GA_PTR(i) ((char_u *)ga.ga_data + i) #define STR_CHAR(i) (buf == NULL ? GA_CHAR(i) : buf[i]) #define STR_PTR(i) (buf == NULL ? GA_PTR(i) : buf + i) // Copy "str" into "buf" or allocated memory, unmodified. if (buf == NULL) { ga_init(&ga, 1, 10); ga_grow(&ga, len + 1); memmove(ga.ga_data, str, (size_t)len); ga.ga_len = len; } else { if (len >= buflen) { // Ugly! len = buflen - 1; } memmove(buf, str, (size_t)len); } if (buf == NULL) { GA_CHAR(len) = NUL; } else { buf[len] = NUL; } // Make each character lower case. i = 0; while (STR_CHAR(i) != NUL) { if (enc_utf8 || (has_mbyte && (MB_BYTE2LEN(STR_CHAR(i)) > 1))) { if (enc_utf8) { int c = utf_ptr2char(STR_PTR(i)); int olen = utf_ptr2len(STR_PTR(i)); int lc = utf_tolower(c); // Only replace the character when it is not an invalid // sequence (ASCII character or more than one byte) and // utf_tolower() doesn't return the original character. if (((c < 0x80) || (olen > 1)) && (c != lc)) { int nlen = utf_char2len(lc); // If the byte length changes need to shift the following // characters forward or backward. if (olen != nlen) { if (nlen > olen) { if (buf == NULL) { ga_grow(&ga, nlen - olen + 1); } else { if (len + nlen - olen >= buflen) { // out of memory, keep old char lc = c; nlen = olen; } } } if (olen != nlen) { if (buf == NULL) { STRMOVE(GA_PTR(i) + nlen, GA_PTR(i) + olen); ga.ga_len += nlen - olen; } else { STRMOVE(buf + i + nlen, buf + i + olen); len += nlen - olen; } } } (void)utf_char2bytes(lc, STR_PTR(i)); } } // skip to next multi-byte char i += (*mb_ptr2len)(STR_PTR(i)); } else { if (buf == NULL) { GA_CHAR(i) = TOLOWER_LOC(GA_CHAR(i)); } else { buf[i] = TOLOWER_LOC(buf[i]); } ++i; } } if (buf == NULL) { return (char_u *)ga.ga_data; } return buf; }
static void write_string(garray_T *gap, char_u *str) { char_u *res = str; char_u numbuf[NUMBUFLEN]; if (res == NULL) ga_concat(gap, (char_u *)"null"); else { #if defined(FEAT_MBYTE) && defined(USE_ICONV) vimconv_T conv; char_u *converted = NULL; if (!enc_utf8) { /* Convert the text from 'encoding' to utf-8, the JSON string is * always utf-8. */ conv.vc_type = CONV_NONE; convert_setup(&conv, p_enc, (char_u*)"utf-8"); if (conv.vc_type != CONV_NONE) converted = res = string_convert(&conv, res, NULL); convert_setup(&conv, NULL, NULL); } #endif ga_append(gap, '"'); while (*res != NUL) { int c; #ifdef FEAT_MBYTE /* always use utf-8 encoding, ignore 'encoding' */ c = utf_ptr2char(res); #else c = *res; #endif switch (c) { case 0x08: ga_append(gap, '\\'); ga_append(gap, 'b'); break; case 0x09: ga_append(gap, '\\'); ga_append(gap, 't'); break; case 0x0a: ga_append(gap, '\\'); ga_append(gap, 'n'); break; case 0x0c: ga_append(gap, '\\'); ga_append(gap, 'f'); break; case 0x0d: ga_append(gap, '\\'); ga_append(gap, 'r'); break; case 0x22: /* " */ case 0x5c: /* \ */ ga_append(gap, '\\'); ga_append(gap, c); break; default: if (c >= 0x20) { #ifdef FEAT_MBYTE numbuf[utf_char2bytes(c, numbuf)] = NUL; #else numbuf[0] = c; numbuf[1] = NUL; #endif ga_concat(gap, numbuf); } else { vim_snprintf((char *)numbuf, NUMBUFLEN, "\\u%04lx", (long)c); ga_concat(gap, numbuf); } } #ifdef FEAT_MBYTE res += utf_ptr2len(res); #else ++res; #endif } ga_append(gap, '"'); #if defined(FEAT_MBYTE) && defined(USE_ICONV) vim_free(converted); #endif } }
/* * Convert the string "str[orglen]" to do ignore-case comparing. Uses the * current locale. * When "buf" is NULL returns an allocated string (NULL for out-of-memory). * Otherwise puts the result in "buf[buflen]". */ char_u * str_foldcase( char_u *str, int orglen, char_u *buf, int buflen) { garray_T ga; int i; int len = orglen; #define GA_CHAR(i) ((char_u *)ga.ga_data)[i] #define GA_PTR(i) ((char_u *)ga.ga_data + i) #define STR_CHAR(i) (buf == NULL ? GA_CHAR(i) : buf[i]) #define STR_PTR(i) (buf == NULL ? GA_PTR(i) : buf + i) /* Copy "str" into "buf" or allocated memory, unmodified. */ if (buf == NULL) { ga_init2(&ga, 1, 10); if (ga_grow(&ga, len + 1) == FAIL) return NULL; mch_memmove(ga.ga_data, str, (size_t)len); ga.ga_len = len; } else { if (len >= buflen) /* Ugly! */ len = buflen - 1; mch_memmove(buf, str, (size_t)len); } if (buf == NULL) GA_CHAR(len) = NUL; else buf[len] = NUL; /* Make each character lower case. */ i = 0; while (STR_CHAR(i) != NUL) { #ifdef FEAT_MBYTE if (enc_utf8 || (has_mbyte && MB_BYTE2LEN(STR_CHAR(i)) > 1)) { if (enc_utf8) { int c = utf_ptr2char(STR_PTR(i)); int olen = utf_ptr2len(STR_PTR(i)); int lc = utf_tolower(c); /* Only replace the character when it is not an invalid * sequence (ASCII character or more than one byte) and * utf_tolower() doesn't return the original character. */ if ((c < 0x80 || olen > 1) && c != lc) { int nlen = utf_char2len(lc); /* If the byte length changes need to shift the following * characters forward or backward. */ if (olen != nlen) { if (nlen > olen) { if (buf == NULL ? ga_grow(&ga, nlen - olen + 1) == FAIL : len + nlen - olen >= buflen) { /* out of memory, keep old char */ lc = c; nlen = olen; } } if (olen != nlen) { if (buf == NULL) { STRMOVE(GA_PTR(i) + nlen, GA_PTR(i) + olen); ga.ga_len += nlen - olen; } else { STRMOVE(buf + i + nlen, buf + i + olen); len += nlen - olen; } } } (void)utf_char2bytes(lc, STR_PTR(i)); } } /* skip to next multi-byte char */ i += (*mb_ptr2len)(STR_PTR(i)); } else #endif { if (buf == NULL) GA_CHAR(i) = TOLOWER_LOC(GA_CHAR(i)); else buf[i] = TOLOWER_LOC(buf[i]); ++i; } } if (buf == NULL) return (char_u *)ga.ga_data; return buf; }