aboutsummaryrefslogtreecommitdiff
path: root/src/vterm/state.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vterm/state.c')
-rw-r--r--src/vterm/state.c138
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) {