diff --git a/kitty/history.c b/kitty/history.c index b382de965..94ea67df2 100644 --- a/kitty/history.c +++ b/kitty/history.c @@ -203,16 +203,24 @@ pagerhist_write_bytes(PagerHistoryBuf *ph, const uint8_t *buf, size_t sz) { return true; } -static inline void +static inline bool pagerhist_ensure_start_is_valid_utf8(PagerHistoryBuf *ph) { uint32_t state = UTF8_ACCEPT, codep; - while (ph->length) { - decode_utf8(&state, &codep, ph->buffer[ph->start]); + size_t pos = ph->start, count = 0; + size_t last_reject_at = 0; + while (count < ph->length) { + decode_utf8(&state, &codep, ph->buffer[pos]); + count++; if (state == UTF8_ACCEPT) break; - if (state == UTF8_REJECT) state = UTF8_ACCEPT; - ph->start = ph->start == ph->buffer_size - 1 ? 0 : ph->start + 1; - ph->length--; + if (state == UTF8_REJECT) { state = UTF8_ACCEPT; last_reject_at = count; } + pos = pos == ph->buffer_size - 1 ? 0: pos + 1; } + if (last_reject_at) { + ph->start = (ph->start + last_reject_at) % ph->buffer_size; + ph->length -= last_reject_at; + return true; + } + return false; } static inline bool diff --git a/kitty_tests/screen.py b/kitty_tests/screen.py index 315b04f2e..bf022ae2c 100644 --- a/kitty_tests/screen.py +++ b/kitty_tests/screen.py @@ -477,6 +477,9 @@ class TestScreen(BaseTest): def line(i): q.append('\x1b[m' + f'{i}' * s.columns + '\r') + def w(x): + s.historybuf.pagerhist_write(x) + def test(): expected = ''.join(q) maxlen = hsz @@ -497,6 +500,21 @@ class TestScreen(BaseTest): s.draw('8' * s.columns), line(4), test() s.draw('9' * s.columns), line(5), test() + s = self.create_screen(options={'scrollback_pager_history_size': 2048}) + text = '\x1b[msoft\r\x1b[mbreak\nnext😼cat' + w(text) + self.ae(contents(), text + '\n') + s.historybuf.pagerhist_rewrap(2) + self.ae(contents(), '\x1b[mso\rft\x1b[m\rbr\rea\rk\nne\rxt\r😼\rca\rt\n') + + s = self.create_screen(options={'scrollback_pager_history_size': 8}) + w('😼') + self.ae(contents(), '😼\n') + w('abcd') + self.ae(contents(), '😼abcd\n') + w('e') + self.ae(contents(), 'abcde\n') + def test_user_marking(self): def cells(*a, y=0, mark=3):