mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-06-27 19:31:46 +00:00
Fix drawing multiple chars where the second or later char is on a multicell
This commit is contained in:
parent
4a0086b241
commit
06c428ba7b
2 changed files with 71 additions and 46 deletions
100
kitty/screen.c
100
kitty/screen.c
|
|
@ -941,7 +941,7 @@ screen_on_input(Screen *self) {
|
|||
|
||||
static bool
|
||||
ts_cursor_on_multicell(Screen *self, text_loop_state *s) {
|
||||
return s->cp[self->cursor->x].is_multicell;
|
||||
return self->cursor->x < self->columns && s->cp[self->cursor->x].is_multicell;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -983,56 +983,62 @@ map_char(Screen *self, const uint32_t ch) {
|
|||
return UNLIKELY(self->charset.current && ch < 256) ? self->charset.current[ch] : ch;
|
||||
}
|
||||
|
||||
static void
|
||||
draw_control_char(Screen *self, text_loop_state *s, uint32_t ch) {
|
||||
switch (ch) {
|
||||
case BEL:
|
||||
screen_bell(self); break;
|
||||
case BS:
|
||||
screen_backspace(self); break;
|
||||
case HT:
|
||||
if (UNLIKELY(self->cursor->x >= self->columns)) {
|
||||
if (self->modes.mDECAWM) {
|
||||
// xterm discards the TAB in this case so match its behavior
|
||||
continue_to_next_line(self);
|
||||
init_text_loop_line(self, s);
|
||||
} else if (self->columns > 0){
|
||||
self->cursor->x = self->columns - 1;
|
||||
if (ts_cursor_on_multicell(self, s)) {
|
||||
if (s->cp[self->cursor->x].y) move_cursor_past_multicell(self, 1);
|
||||
else replace_multicell_char_under_cursor_with_spaces(self);
|
||||
}
|
||||
screen_tab(self);
|
||||
}
|
||||
} else screen_tab(self);
|
||||
break;
|
||||
case SI:
|
||||
screen_change_charset(self, 0); break;
|
||||
case SO:
|
||||
screen_change_charset(self, 1); break;
|
||||
case LF:
|
||||
case VT:
|
||||
case FF:
|
||||
screen_linefeed(self); init_text_loop_line(self, s); break;
|
||||
case CR:
|
||||
screen_carriage_return(self); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
draw_text_loop(Screen *self, const uint32_t *chars, size_t num_chars, text_loop_state *s) {
|
||||
init_text_loop_line(self, s);
|
||||
const uint32_t first_char = map_char(self, chars[0]);
|
||||
if (ts_cursor_on_multicell(self, s) && ' ' <= first_char && first_char != DEL) {
|
||||
if (s->cp[self->cursor->x].y) {
|
||||
move_cursor_past_multicell(self, 1);
|
||||
} else {
|
||||
if (!is_combining_char(first_char)) nuke_multicell_char_at(self, self->cursor->x, self->cursor->y, s->cp[self->cursor->x].x != 0);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < num_chars; i++) {
|
||||
uint32_t ch = map_char(self, chars[i]);
|
||||
if (ch < ' ') {
|
||||
switch (ch) {
|
||||
case BEL:
|
||||
screen_bell(self); break;
|
||||
case BS:
|
||||
screen_backspace(self); break;
|
||||
case HT:
|
||||
if (UNLIKELY(self->cursor->x >= self->columns)) {
|
||||
if (self->modes.mDECAWM) {
|
||||
// xterm discards the TAB in this case so match its behavior
|
||||
continue_to_next_line(self);
|
||||
init_text_loop_line(self, s);
|
||||
} else if (self->columns > 0){
|
||||
self->cursor->x = self->columns - 1;
|
||||
if (ts_cursor_on_multicell(self, s)) {
|
||||
if (s->cp[self->cursor->x].y) move_cursor_past_multicell(self, 1);
|
||||
else replace_multicell_char_under_cursor_with_spaces(self);
|
||||
}
|
||||
screen_tab(self);
|
||||
}
|
||||
} else screen_tab(self);
|
||||
break;
|
||||
case SI:
|
||||
screen_change_charset(self, 0); break;
|
||||
case SO:
|
||||
screen_change_charset(self, 1); break;
|
||||
case LF:
|
||||
case VT:
|
||||
case FF:
|
||||
screen_linefeed(self); init_text_loop_line(self, s); break;
|
||||
case CR:
|
||||
screen_carriage_return(self); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
draw_control_char(self, s, ch);
|
||||
continue;
|
||||
}
|
||||
if (ts_cursor_on_multicell(self, s)) {
|
||||
if (s->cp[self->cursor->x].y) {
|
||||
move_cursor_past_multicell(self, 1);
|
||||
init_text_loop_line(self, s);
|
||||
} else {
|
||||
if (!is_combining_char(ch)) nuke_multicell_char_at(self, self->cursor->x, self->cursor->y, s->cp[self->cursor->x].x != 0);
|
||||
}
|
||||
}
|
||||
|
||||
int char_width = 1;
|
||||
if (ch > DEL) { // not printable ASCII
|
||||
if (is_ignored_char(ch)) continue;
|
||||
|
|
@ -1055,9 +1061,11 @@ draw_text_loop(Screen *self, const uint32_t *chars, size_t num_chars, text_loop_
|
|||
if (self->modes.mDECAWM) {
|
||||
continue_to_next_line(self);
|
||||
init_text_loop_line(self, s);
|
||||
} else {
|
||||
self->cursor->x = self->columns - char_width;
|
||||
if (ts_cursor_on_multicell(self, s)) replace_multicell_char_under_cursor_with_spaces(self);
|
||||
} else self->cursor->x = self->columns - char_width;
|
||||
CPUCell *c = &s->cp[self->cursor->x];
|
||||
if (c->is_multicell) {
|
||||
if (c->y) { move_cursor_past_multicell(self, char_width); init_text_loop_line(self, s); }
|
||||
nuke_multicell_char_at(self, self->cursor->x, self->cursor->y, c->x > 0);
|
||||
}
|
||||
}
|
||||
if (self->modes.mIRM) insert_characters(self, self->cursor->x, char_width, self->cursor->y, true);
|
||||
|
|
|
|||
|
|
@ -107,8 +107,24 @@ def test_multicell(self: TestMulticell) -> None:
|
|||
for x in range(0, 4):
|
||||
ac(x, 1, is_multicell=True, width=2, scale=2, subscale_n=3, x=x, y=1, text='', natural_width=False)
|
||||
|
||||
# Test wrapping
|
||||
s.reset()
|
||||
multicell(s, 'a', scale=2)
|
||||
s.draw('x' * s.columns)
|
||||
ac(s.cursor.x-1, s.cursor.y, is_multicell=False, text='x')
|
||||
ac(0, 0, is_multicell=True, text='a')
|
||||
ac(0, 1, is_multicell=True, text='', y=1)
|
||||
|
||||
# Test draw with cursor in a multicell
|
||||
s.reset()
|
||||
multicell(s, '12', scale=2)
|
||||
s.draw('\rx')
|
||||
ac(0, 0, is_multicell=False, text='x')
|
||||
ac(1, 0, is_multicell=False, text='')
|
||||
ac(0, 1, is_multicell=False, text='')
|
||||
ac(1, 1, is_multicell=False, text='')
|
||||
ac(2, 0, is_multicell=True, text='2')
|
||||
s.reset()
|
||||
s.draw('莊')
|
||||
s.cursor.x -= 1
|
||||
s.draw('a'), ac(0, 0, is_multicell=False), ac(1, 0, is_multicell=False)
|
||||
|
|
@ -140,6 +156,7 @@ def test_multicell(self: TestMulticell) -> None:
|
|||
multicell(s, 'a', scale=2)
|
||||
s.cursor.x += 1
|
||||
multicell(s, 'b', scale=2)
|
||||
assert_cursor_at(5, 0)
|
||||
s.draw('\u2716\ufe0f')
|
||||
assert_cursor_at(2, 2)
|
||||
s.reset()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue