diff options
Diffstat (limited to 'src/vterm/state.c')
-rw-r--r-- | src/vterm/state.c | 138 |
1 files changed, 36 insertions, 102 deletions
diff --git a/src/vterm/state.c b/src/vterm/state.c index e09b39436a..d546672e67 100644 --- a/src/vterm/state.c +++ b/src/vterm/state.c @@ -3,6 +3,9 @@ #include <stdio.h> #include <string.h> +#include "nvim/grid.h" +#include "nvim/mbyte.h" + #define strneq(a,b,n) (strncmp(a,b,n)==0) #if defined(DEBUG) && DEBUG > 1 @@ -11,10 +14,10 @@ /* Some convenient wrappers to make callback functions easier */ -static void putglyph(VTermState *state, const uint32_t chars[], int width, VTermPos pos) +static void putglyph(VTermState *state, const schar_T schar, int width, VTermPos pos) { VTermGlyphInfo info = { - .chars = chars, + .schar = schar, .width = width, .protected_cell = state->protected_cell, .dwl = state->lineinfo[pos.row].doublewidth, @@ -82,8 +85,7 @@ static VTermState *vterm_state_new(VTerm *vt) state->bold_is_highbright = 0; - state->combine_chars_size = 16; - state->combine_chars = vterm_allocator_malloc(state->vt, state->combine_chars_size * sizeof(state->combine_chars[0])); + state->combine_pos.row = -1; state->tabstops = vterm_allocator_malloc(state->vt, (state->cols + 7) / 8); @@ -105,7 +107,6 @@ INTERNAL void vterm_state_free(VTermState *state) vterm_allocator_free(state->vt, state->lineinfos[BUFIDX_PRIMARY]); if(state->lineinfos[BUFIDX_ALTSCREEN]) vterm_allocator_free(state->vt, state->lineinfos[BUFIDX_ALTSCREEN]); - vterm_allocator_free(state->vt, state->combine_chars); vterm_allocator_free(state->vt, state); } @@ -171,19 +172,6 @@ static void linefeed(VTermState *state) state->pos.row++; } -static void grow_combine_buffer(VTermState *state) -{ - size_t new_size = state->combine_chars_size * 2; - uint32_t *new_chars = vterm_allocator_malloc(state->vt, new_size * sizeof(new_chars[0])); - - memcpy(new_chars, state->combine_chars, state->combine_chars_size * sizeof(new_chars[0])); - - vterm_allocator_free(state->vt, state->combine_chars); - - state->combine_chars = new_chars; - state->combine_chars_size = new_size; -} - static void set_col_tabstop(VTermState *state, int col) { unsigned char mask = 1 << (col & 7); @@ -301,88 +289,35 @@ static int on_text(const char bytes[], size_t len, void *user) state->gsingle_set = 0; int i = 0; + GraphemeState grapheme_state = GRAPHEME_STATE_INIT; + size_t grapheme_len = 0; + bool recombine = false; + /* See if the cursor has moved since */ + if(state->pos.row == state->combine_pos.row && state->pos.col == state->combine_pos.col + state->combine_width) { /* This is a combining char. that needs to be merged with the previous * glyph output */ - if(vterm_unicode_is_combining(codepoints[i])) { - /* See if the cursor has moved since */ - if(state->pos.row == state->combine_pos.row && state->pos.col == state->combine_pos.col + state->combine_width) { -#ifdef DEBUG_GLYPH_COMBINE - int printpos; - printf("DEBUG: COMBINING SPLIT GLYPH of chars {"); - for(printpos = 0; state->combine_chars[printpos]; printpos++) - printf("U+%04x ", state->combine_chars[printpos]); - printf("} + {"); -#endif - + if(utf_iscomposing(state->grapheme_last, codepoints[i], &state->grapheme_state)) { /* Find where we need to append these combining chars */ - int saved_i = 0; - while(state->combine_chars[saved_i]) - saved_i++; - - /* Add extra ones */ - while(i < npoints && vterm_unicode_is_combining(codepoints[i])) { - if(saved_i >= state->combine_chars_size) - grow_combine_buffer(state); - state->combine_chars[saved_i++] = codepoints[i++]; - } - if(saved_i >= state->combine_chars_size) - grow_combine_buffer(state); - state->combine_chars[saved_i] = 0; - -#ifdef DEBUG_GLYPH_COMBINE - for(; state->combine_chars[printpos]; printpos++) - printf("U+%04x ", state->combine_chars[printpos]); - printf("}\n"); -#endif - - /* Now render it */ - putglyph(state, state->combine_chars, state->combine_width, state->combine_pos); - } - else { + grapheme_len = state->grapheme_len; + grapheme_state = state->grapheme_state; + state->pos.col = state->combine_pos.col; + recombine = true; + } else { DEBUG_LOG("libvterm: TODO: Skip over split char+combining\n"); } } - for(; i < npoints; i++) { + while(i < npoints) { // Try to find combining characters following this - int glyph_starts = i; - int glyph_ends; - for(glyph_ends = i + 1; - (glyph_ends < npoints) && (glyph_ends < glyph_starts + VTERM_MAX_CHARS_PER_CELL); - glyph_ends++) - if(!vterm_unicode_is_combining(codepoints[glyph_ends])) - break; - - int width = 0; - - uint32_t chars[VTERM_MAX_CHARS_PER_CELL + 1]; - - for( ; i < glyph_ends; i++) { - chars[i - glyph_starts] = codepoints[i]; - int this_width = vterm_unicode_width(codepoints[i]); -#ifdef DEBUG - if(this_width < 0) { - fprintf(stderr, "Text with negative-width codepoint U+%04x\n", codepoints[i]); - abort(); + do { + if (grapheme_len < sizeof(state->grapheme_buf) - 4) { + grapheme_len += utf_char2bytes(codepoints[i], state->grapheme_buf + grapheme_len); } -#endif - width += this_width; - } - - while(i < npoints && vterm_unicode_is_combining(codepoints[i])) i++; + } while(i < npoints && utf_iscomposing(codepoints[i-1], codepoints[i], &grapheme_state)); - chars[glyph_ends - glyph_starts] = 0; - i--; - -#ifdef DEBUG_GLYPH_COMBINE - int printpos; - printf("DEBUG: COMBINED GLYPH of %d chars {", glyph_ends - glyph_starts); - for(printpos = 0; printpos < glyph_ends - glyph_starts; printpos++) - printf("U+%04x ", chars[printpos]); - printf("}, onscreen width %d\n", width); -#endif + int width = utf_ptr2cells_len(state->grapheme_buf, grapheme_len); if(state->at_phantom || state->pos.col + width > THISROWWIDTH(state)) { linefeed(state); @@ -391,7 +326,7 @@ static int on_text(const char bytes[], size_t len, void *user) state->lineinfo[state->pos.row].continuation = 1; } - if(state->mode.insert) { + if(state->mode.insert && !recombine) { /* TODO: This will be a little inefficient for large bodies of text, as * it'll have to 'ICH' effectively before every glyph. We should scan * ahead and ICH as many times as required @@ -405,22 +340,20 @@ static int on_text(const char bytes[], size_t len, void *user) scroll(state, rect, 0, -1); } - putglyph(state, chars, width, state->pos); + schar_T sc = schar_from_buf(state->grapheme_buf, grapheme_len); + putglyph(state, sc, width, state->pos); - if(i == npoints - 1) { + if(i == npoints) { /* End of the buffer. Save the chars in case we have to combine with * more on the next call */ - int save_i; - for(save_i = 0; chars[save_i]; save_i++) { - if(save_i >= state->combine_chars_size) - grow_combine_buffer(state); - state->combine_chars[save_i] = chars[save_i]; - } - if(save_i >= state->combine_chars_size) - grow_combine_buffer(state); - state->combine_chars[save_i] = 0; + state->grapheme_len = grapheme_len; + state->grapheme_last = codepoints[i-1]; + state->grapheme_state = grapheme_state; state->combine_width = width; state->combine_pos = state->pos; + } else { + grapheme_len = 0; + recombine = false; } if(state->pos.col + width >= THISROWWIDTH(state)) { @@ -646,7 +579,7 @@ static int on_escape(const char *bytes, size_t len, void *user) case '8': // DECALN { VTermPos pos; - uint32_t E[] = { 'E', 0 }; + schar_T E = schar_from_ascii('E'); // E for(pos.row = 0; pos.row < state->rows; pos.row++) for(pos.col = 0; pos.col < ROWWIDTH(state, pos.row); pos.col++) putglyph(state, E, 1, pos); @@ -1234,8 +1167,9 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha count = CSI_ARG_COUNT(args[0]); col = state->pos.col + count; UBOUND(col, row_width); + schar_T sc = schar_from_buf(state->grapheme_buf, state->grapheme_len); while (state->pos.col < col) { - putglyph(state, state->combine_chars, state->combine_width, state->pos); + putglyph(state, sc, state->combine_width, state->pos); state->pos.col += state->combine_width; } if (state->pos.col + state->combine_width >= row_width) { |