Fixed incorrect cursor position if prompt contains ANSI sequences
- And added delete key handling
This commit is contained in:
parent
1101c53bf6
commit
ca08c9e3e5
1 changed files with 59 additions and 2 deletions
61
main.c
61
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue