diff --git a/kitty/screen.c b/kitty/screen.c index b6c6b9429..02a324030 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -4785,7 +4785,24 @@ screen_draw_overlay_line(Screen *self) { self->modes.mIRM = false; Cursor *orig_cursor = self->cursor; self->cursor = &(self->overlay_line.original_line.cursor); - self->cursor->sgr.reverse ^= true; + // Mark the pre-edit text as distinct from committed text: italic, with a + // dashed underline in the highlight color. Underline rather than reverse + // video matches what other terminals do (VTE and foot both underline), and + // dashed avoids colliding with the styles applications already use: curly + // for spell checking and straight for hyperlinks. Saved and restored around + // the draw, like the modes above. + const bool orig_italic = self->cursor->sgr.italic; + const uint8_t orig_decoration = self->cursor->sgr.decoration; + const color_type orig_decoration_fg = self->cursor->sgr.decoration_fg; + self->cursor->sgr.italic = true; + self->cursor->sgr.decoration = 5; // dashed + self->cursor->sgr.decoration_fg = + ((colorprofile_to_color_with_fallback(self->color_profile, self->color_profile->overridden.highlight_bg, + self->color_profile->configured.highlight_bg, self->color_profile->overridden.default_fg, + self->color_profile->configured.default_fg) + & COL_MASK) + << 8) + | 2; self->cursor->x = xstart; self->cursor->y = self->overlay_line.ynum; self->overlay_line.xnum = 0; @@ -4837,7 +4854,9 @@ screen_draw_overlay_line(Screen *self) { self->overlay_line.xnum += len; } self->overlay_line.cursor_x = self->cursor->x; - self->cursor->sgr.reverse ^= true; + self->cursor->sgr.italic = orig_italic; + self->cursor->sgr.decoration = orig_decoration; + self->cursor->sgr.decoration_fg = orig_decoration_fg; self->cursor = orig_cursor; self->modes.mDECAWM = orig_line_wrap_mode; self->modes.mDECTCEM = orig_cursor_enable_mode; diff --git a/kitty_tests/screen.py b/kitty_tests/screen.py index 40f338d99..663b625aa 100644 --- a/kitty_tests/screen.py +++ b/kitty_tests/screen.py @@ -2119,6 +2119,29 @@ class TestScreen(BaseTest): s.reset() self.assertTrue(s.is_main_linebuf()) + def test_ime_preedit_styling(self): + # Pre-edit text is marked with italics and a dashed underline in the + # highlight color, rather than reverse video. + s = self.create_screen(cols=10, lines=3) + s.draw('xy') + before = s.line(0).cursor_from(0) + s.test_draw_overlay_line('ab', 0, 0) + line = s.line(0) + for x in (0, 1): + c = line.cursor_from(x) + self.assertTrue(c.italic, f'pre-edit cell {x} is not italic') + self.assertFalse(c.reverse, f'pre-edit cell {x} is in reverse video') + self.ae(c.decoration, 5, f'pre-edit cell {x} is not dashed-underlined') + # decoration_fg is packed as (rgb << 8) | type, type 2 being RGB + self.ae(c.decoration_fg & 0xff, 2) + self.ae(c.decoration_fg >> 8, 0xfffacd) # default selection_background + + # the styling is applied to the overlay's own cursor and must be + # restored, not leaked into the screen's cursor + self.assertFalse(s.cursor.italic) + self.ae(s.cursor.decoration, before.decoration) + self.ae(s.cursor.decoration_fg, before.decoration_fg) + def detect_url(self, scale=1): s = self.create_screen(cols=30 * scale)