From ca08c9e3e591a2fbdb318dee56be9124d581dfea Mon Sep 17 00:00:00 2001 From: Aleksandr Lebedev Date: Tue, 21 Apr 2026 15:05:17 +0200 Subject: [PATCH] Fixed incorrect cursor position if prompt contains ANSI sequences - And added delete key handling --- main.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index 59433e9..0e6e717 100644 --- a/main.c +++ b/main.c @@ -161,6 +161,47 @@ size_t utf8_display_width(const char *buf, size_t len) return width; } +size_t visible_width(const char *s) +{ + size_t i = 0; + size_t width = 0; + + while (s[i]) { + + // ANSI escape sequence + if (s[i] == '\x1b' && s[i+1] == '[') { + i += 2; + + while (s[i] && !((s[i] >= '@' && s[i] <= '~'))) + i++; + + if (s[i]) i++; + continue; + } + + unsigned char c = s[i]; + + if ((c & 0x80) == 0) { + i += 1; + width += 1; + } + else if ((c & 0xE0) == 0xC0) { + i += 2; + width += 1; + } + else if ((c & 0xF0) == 0xE0) { + i += 3; + width += 1; + } + else { + i += 4; + width += 1; + } + } + + return width; +} + char* __readline_interactive(char* prompt) { enable_raw_mode(); @@ -179,7 +220,7 @@ char* __readline_interactive(char* prompt) write(STDOUT_FILENO, buf, len); swrite(STDOUT_FILENO, "\x1b[K"); - size_t prompt_width = utf8_display_width(prompt, strlen(prompt)); + size_t prompt_width = visible_width(prompt); size_t cell_cursor = utf8_display_width(buf, cursor); char seq[64]; snprintf(seq, sizeof(seq), "\r\x1b[%zuC", prompt_width + cell_cursor); @@ -193,7 +234,7 @@ char* __readline_interactive(char* prompt) if (clen <= 0) continue; if (utf8[0] == '\x1b') { - char seq[2]; + char seq[3]; if (read(STDIN_FILENO, &seq[0], 1) != 1) continue; if (read(STDIN_FILENO, &seq[1], 1) != 1) continue; @@ -208,6 +249,22 @@ char* __readline_interactive(char* prompt) case 'D': // Arrow left cursor = prev_char_start(buffer, cursor); break; + case '3': + if (read(STDIN_FILENO, &seq[2], 1) != 1) continue; + switch (seq[2]) + { + case '~': // Delete + if (cursor < len) { + + size_t next = next_char_start(buffer, len, cursor); + size_t diff = next - cursor; + + memmove(buffer + cursor, buffer + next, len - next); + len -= diff; + } + break; + } + break; } } } else if (utf8[0] == '\r') { // enter