diff --git a/kitty/parser.c b/kitty/parser.c index d95b2201f..c8476f250 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -192,7 +192,7 @@ handle_normal_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_ break; // no-op default: REPORT_DRAW(ch); - screen_draw(screen, ch); + screen_draw(screen, ch, true); break; } #undef CALL_SCREEN_HANDLER diff --git a/kitty/screen.c b/kitty/screen.c index 97ef0bc07..19ae7eba3 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -149,6 +149,7 @@ void screen_reset(Screen *self) { if (self->linebuf == self->alt_linebuf) screen_toggle_screen_buffer(self, true, true); if (self->overlay_line.is_active) deactivate_overlay_line(self); + self->last_graphic_char = 0; self->main_savepoint.is_valid = false; self->alt_savepoint.is_valid = false; linebuf_clear(self->linebuf, BLANK_CHAR); @@ -503,7 +504,7 @@ draw_combining_char(Screen *self, char_type ch) { } void -screen_draw(Screen *self, uint32_t och) { +screen_draw(Screen *self, uint32_t och, bool from_input_stream) { if (is_ignored_char(och)) return; if (!self->has_activity_since_last_focus && !self->has_focus) { self->has_activity_since_last_focus = true; @@ -523,6 +524,7 @@ screen_draw(Screen *self, uint32_t och) { if (char_width == 0) return; char_width = 1; } + if (from_input_stream) self->last_graphic_char = ch; if (UNLIKELY(self->columns - self->cursor->x < (unsigned int)char_width)) { if (self->modes.mDECAWM) { screen_carriage_return(self); @@ -568,7 +570,7 @@ screen_draw_overlay_text(Screen *self, const char *utf8_text) { switch(decode_utf8(&state, &codepoint, *(utf8_text++))) { case UTF8_ACCEPT: before = self->cursor->x; - screen_draw(self, codepoint); + screen_draw(self, codepoint, false); self->overlay_line.xnum += self->cursor->x - before; break; case UTF8_REJECT: @@ -1328,22 +1330,10 @@ screen_insert_characters(Screen *self, unsigned int count) { void screen_repeat_character(Screen *self, unsigned int count) { - const unsigned int top = 0, bottom = self->lines ? self->lines - 1 : 0; - unsigned int x = self->cursor->x; - if (count == 0) count = 1; - if (x > self->columns) return; - if (x > 0) { - linebuf_init_line(self->linebuf, self->cursor->y); - } else { - if (self->cursor->y > 0) { - linebuf_init_line(self->linebuf, self->cursor->y - 1); - x = self->columns; - } else return; - } - char_type ch = line_get_char(self->linebuf->line, x-1); - if (top <= self->cursor->y && self->cursor->y <= bottom && !is_ignored_char(ch)) { + if (self->last_graphic_char) { + if (count == 0) count = 1; unsigned int num = MIN(count, CSI_REP_MAX_REPETITIONS); - while (num-- > 0) screen_draw(self, ch); + while (num-- > 0) screen_draw(self, self->last_graphic_char, false); } } @@ -2142,7 +2132,7 @@ draw(Screen *self, PyObject *src) { int kind = PyUnicode_KIND(src); void *buf = PyUnicode_DATA(src); Py_ssize_t sz = PyUnicode_GET_LENGTH(src); - for (Py_ssize_t i = 0; i < sz; i++) screen_draw(self, PyUnicode_READ(kind, buf, i)); + for (Py_ssize_t i = 0; i < sz; i++) screen_draw(self, PyUnicode_READ(kind, buf, i), true); Py_RETURN_NONE; } diff --git a/kitty/screen.h b/kitty/screen.h index 3d426907a..e18bc148c 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -128,6 +128,7 @@ typedef struct { hyperlink_id_type active_hyperlink_id; HYPERLINK_POOL_HANDLE hyperlink_pool; ANSIBuf as_ansi_buf; + char_type last_graphic_char; } Screen; @@ -143,7 +144,7 @@ void screen_cursor_position(Screen*, unsigned int, unsigned int); void screen_cursor_back(Screen *self, unsigned int count/*=1*/, int move_direction/*=-1*/); void screen_erase_in_line(Screen *, unsigned int, bool); void screen_erase_in_display(Screen *, unsigned int, bool); -void screen_draw(Screen *screen, uint32_t codepoint); +void screen_draw(Screen *screen, uint32_t codepoint, bool); void screen_ensure_bounds(Screen *self, bool use_margins, bool cursor_was_within_margins); void screen_toggle_screen_buffer(Screen *self, bool, bool); void screen_normal_keypad_mode(Screen *self); diff --git a/kitty_tests/screen.py b/kitty_tests/screen.py index 59ce4d0b5..d9f3385db 100644 --- a/kitty_tests/screen.py +++ b/kitty_tests/screen.py @@ -93,6 +93,17 @@ def test_draw_char(self): self.ae(str(s.line(4)), 'a\u0306b1\u030623') self.ae((s.cursor.x, s.cursor.y), (2, 4)) + def test_rep(self): + s = self.create_screen() + s.draw('a') + parse_bytes(s, b'\x1b[b') + self.ae(str(s.line(0)), 'aa') + parse_bytes(s, b'\x1b[3b') + self.ae(str(s.line(0)), 'a'*5) + s.draw(' ') + parse_bytes(s, b'\x1b[3b') + self.ae(str(s.line(1)), ' '*4) + def test_emoji_skin_tone_modifiers(self): s = self.create_screen() q = chr(0x1f469) + chr(0x1f3fd)