From 823db08712b92d66dd67e2b70557329a2b7cf37c Mon Sep 17 00:00:00 2001 From: pagedown Date: Sat, 4 Mar 2023 16:11:29 +0800 Subject: [PATCH] IME: Right align overlay when typing at the edge of the screen When the cursor is at the right edge of the screen, push the overlay to the left to display the pre-edit text just entered. --- docs/changelog.rst | 2 +- kitty/screen.c | 33 ++++++++++++++++++++++++++++++--- kitty/screen.h | 2 +- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index bbfe554be..795029a9c 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -50,7 +50,7 @@ Detailed list of changes - When changing the cursor color via escape codes or remote control to a fixed color, do not reset cursor_text_color (:iss:`5994`) -- Input Method Extensions: Fix incorrect rendering of IME in-progress and committed text in some situations (:pull:`6049`) +- Input Method Extensions: Fix incorrect rendering of IME in-progress and committed text in some situations (:pull:`6049`, :pull:`6087`) - Linux: Reduce minimum required OpenGL version from 3.3 to 3.1 + extensions (:iss:`2790`) diff --git a/kitty/screen.c b/kitty/screen.c index d27277040..f9853240a 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -2898,6 +2898,7 @@ screen_update_overlay_text(Screen *self, const char *utf8_text) { self->overlay_line.is_dirty = true; self->overlay_line.xstart = self->cursor->x; self->overlay_line.xnum = !text_len ? 0 : PyLong_AsLong(text_len); + self->overlay_line.text_len = self->overlay_line.xnum; self->overlay_line.cursor_x = MIN(self->overlay_line.xstart + self->overlay_line.xnum, self->columns); self->overlay_line.ynum = self->cursor->y; cursor_copy_to(self->cursor, &(self->overlay_line.original_line.cursor)); @@ -2913,7 +2914,10 @@ screen_update_overlay_text(Screen *self, const char *utf8_text) { static void screen_draw_overlay_line(Screen *self) { if (!self->overlay_line.overlay_text) return; - self->overlay_line.xnum = 0; + // Right-align the overlay to ensure that the pre-edit text just entered is visible when the cursor is near the end of the line. + index_type xstart = self->overlay_line.text_len <= self->columns ? self->columns - self->overlay_line.text_len : 0; + if (self->overlay_line.xstart < xstart) xstart = self->overlay_line.xstart; + index_type columns_exceeded = self->overlay_line.text_len <= self->columns ? 0 : self->overlay_line.text_len - self->columns; bool orig_line_wrap_mode = self->modes.mDECAWM; bool orig_cursor_enable_mode = self->modes.mDECTCEM; bool orig_insert_replace_mode = self->modes.mIRM; @@ -2923,9 +2927,15 @@ screen_draw_overlay_line(Screen *self) { Cursor *orig_cursor = self->cursor; self->cursor = &(self->overlay_line.original_line.cursor); self->cursor->reverse ^= true; - self->cursor->x = self->overlay_line.xstart; + self->cursor->x = xstart; self->cursor->y = self->overlay_line.ynum; self->overlay_line.xnum = 0; + if (xstart > 0) { + // When the cursor is on the second cell of a full-width character for whatever reason, + // make sure the first character in the overlay is visible. + GPUCell *g = self->linebuf->line->gpu_cells + (xstart - 1); + if (g->attrs.width > 1) line_set_char(self->linebuf->line, xstart - 1, 0, 0, NULL, 0); + } index_type before; const int kind = PyUnicode_KIND(self->overlay_line.overlay_text); const void *data = PyUnicode_DATA(self->overlay_line.overlay_text); @@ -2933,7 +2943,24 @@ screen_draw_overlay_line(Screen *self) { for (Py_ssize_t pos = 0; pos < sz; pos++) { before = self->cursor->x; draw_codepoint(self, PyUnicode_READ(kind, data, pos), false); - self->overlay_line.xnum += self->cursor->x - before; + index_type len = self->cursor->x - before; + if (columns_exceeded > 0) { + // Reset the cursor to maintain right alignment when the overlay exceeds the screen width. + if (columns_exceeded > len) { + columns_exceeded -= len; + len = 0; + } else { + len = len > columns_exceeded ? len - columns_exceeded : 0; + columns_exceeded = 0; + if (len > 0) { + // When the last character is full width and only half moved out, make sure the next character is visible. + GPUCell *g = self->linebuf->line->gpu_cells + (len - 1); + if (g->attrs.width > 1) line_set_char(self->linebuf->line, len - 1, 0, 0, NULL, 0); + } + } + self->cursor->x = len; + } + self->overlay_line.xnum += len; } self->overlay_line.cursor_x = self->cursor->x; self->cursor->reverse ^= true; diff --git a/kitty/screen.h b/kitty/screen.h index ece3ed0a1..482bb7a6d 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -71,7 +71,7 @@ typedef struct { PyObject *overlay_text; CPUCell *cpu_cells; GPUCell *gpu_cells; - index_type xstart, ynum, xnum, cursor_x; + index_type xstart, ynum, xnum, cursor_x, text_len; bool is_active; bool is_dirty; struct {