Simplify implementation of REP

Also make it align more with the standard by using the actual last drawn
graphics character rather than the character before the cursor
This commit is contained in:
Kovid Goyal 2021-01-03 04:38:02 +05:30
parent 8f58140419
commit b3ed4c3f40
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 22 additions and 20 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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)