From 01b4d568b99fc48fdab0ec628a550dfbeaa7b021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Courr=C3=A8ges-Anglas?= Date: Mon, 15 Apr 2013 01:21:04 +0200 Subject: Support UTF-8 in the input bar * introduce RP_IS_UTF8_{CHAR,CONT,START} macros. Those yield non-zero only if the locale is UTF-8. * use those macros in editor.c to properly handle UTF-8 multibyte characters. * use them also in input.c:update_input_window, to draw the cursor Reviewing and comments are welcome. Patches for generic support of multibyte encodings are welcome too. UTF-8 was chosen because of its processing simplicity and its wide use, not because of any political opinion or religious belief. ;) --- src/editor.c | 223 +++++++++++++++++++++++++++++++++++------------------------ src/editor.h | 5 ++ src/input.c | 19 +++-- 3 files changed, 150 insertions(+), 97 deletions(-) diff --git a/src/editor.c b/src/editor.c index ac10d1f..6c17754 100644 --- a/src/editor.c +++ b/src/editor.c @@ -157,36 +157,48 @@ execute_edit_action (rp_input_line *line, KeySym ch, unsigned int modifier, char static edit_status editor_forward_char (rp_input_line *line) { - if (line->position < line->length) + if (line->position == line->length) + return EDIT_NO_OP; + + if (RP_IS_UTF8_START (line->buffer[line->position])) { - line->position++; - return EDIT_MOVE; + do + line->position++; + while (RP_IS_UTF8_CONT (line->buffer[line->position])); } else - return EDIT_NO_OP; + line->position++; + return EDIT_MOVE; } static edit_status editor_backward_char (rp_input_line *line) { - if (line->position > 0) - { - line->position--; - return EDIT_MOVE; - } - else + if (line->position == 0) return EDIT_NO_OP; + + do + line->position--; + while (line->position > 0 && RP_IS_UTF8_CONT (line->buffer[line->position])); + + return EDIT_MOVE; } static edit_status editor_forward_word (rp_input_line *line) { - if (line->position < line->length) - { - for (; line->position < line->length && !isalnum (line->buffer[line->position]); line->position++); - for (; line->position < line->length && isalnum (line->buffer[line->position]); line->position++); - } + if (line->position == line->length) + return EDIT_NO_OP; + + while (line->position < line->length + && !isalnum (line->buffer[line->position])) + line->position++; + + while (line->position < line->length + && (isalnum (line->buffer[line->position]) + || RP_IS_UTF8_CHAR (line->buffer[line->position]))) + line->position++; return EDIT_MOVE; } @@ -194,11 +206,16 @@ editor_forward_word (rp_input_line *line) static edit_status editor_backward_word (rp_input_line *line) { - if (line->position > 0) - { - for (; line->position > 0 && !isalnum (line->buffer[line->position - 1]); line->position--); - for (; line->position > 0 && isalnum (line->buffer[line->position - 1]); line->position--); - } + if (line->position == 0) + return EDIT_NO_OP; + + while (line->position > 0 && !isalnum (line->buffer[line->position])) + line->position--; + + while (line->position > 0 + && (isalnum (line->buffer[line->position]) + || RP_IS_UTF8_CHAR (line->buffer[line->position]))) + line->position--; return EDIT_MOVE; } @@ -206,77 +223,100 @@ editor_backward_word (rp_input_line *line) static edit_status editor_beginning_of_line (rp_input_line *line) { - if (line->position > 0) - line->position = 0; - - return EDIT_MOVE; + if (line->position == 0) + return EDIT_NO_OP; + else + { + line->position = 0; + return EDIT_MOVE; + } } static edit_status editor_end_of_line (rp_input_line *line) { - if (line->position < line->length) - line->position = line->length; - - return EDIT_MOVE; + if (line->position == line->length) + return EDIT_NO_OP; + else + { + line->position = line->length; + return EDIT_MOVE; + } } static edit_status editor_delete_char (rp_input_line *line) { - int i; + size_t diff = 0; - if (line->position < line->length) - { - for (i = line->position; i < line->length; i++) - line->buffer[i] = line->buffer[i + 1]; + if (line->position == line->length) + return EDIT_NO_OP; - line->length--; - return EDIT_DELETE; + if (RP_IS_UTF8_START (line->buffer[line->position])) + { + do + diff++; + while (RP_IS_UTF8_CONT (line->buffer[line->position + diff])); } else - return EDIT_NO_OP; + diff++; + + memmove (&line->buffer[line->position], + &line->buffer[line->position + diff], + line->length - line->position + diff + 1); + + line->length -= diff; + + return EDIT_DELETE; } static edit_status editor_backward_delete_char (rp_input_line *line) { - int i; - - if (line->position > 0) - { - for (i = line->position - 1; i < line->length; i++) - line->buffer[i] = line->buffer[i + 1]; + size_t diff = 1; - line->position--; - line->length--; - return EDIT_DELETE; - } - else + if (line->position == 0) return EDIT_NO_OP; + + while (line->position - diff > 0 + && RP_IS_UTF8_CONT (line->buffer[line->position - diff])) + diff++; + + memmove (&line->buffer[line->position - diff], + &line->buffer[line->position], + line->length - line->position + 1); + + line->position -= diff; + line->length -= diff; + + return EDIT_DELETE; } static edit_status editor_kill_word (rp_input_line *line) { - int i, diff; + size_t diff = 0; + if (line->position == line->length) + return EDIT_NO_OP; - if (line->position < line->length) - { - for (i = line->position; i < line->length && !isalnum (line->buffer[i]); i++); - for (; i < line->length && isalnum (line->buffer[i]); i++); + while (line->position + diff < line->length && + !isalnum (line->buffer[line->position + diff])) + diff++; - diff = i - line->position; + while (line->position + diff < line->length + && (isalnum (line->buffer[line->position + diff]) + || RP_IS_UTF8_CHAR (line->buffer[line->position + diff]))) + diff++; - /* Add the word to the X11 selection. */ - set_nselection (&line->buffer[line->position], diff); + /* Add the word to the X11 selection. */ + set_nselection (&line->buffer[line->position], diff); - for (i = line->position; i <= line->length - diff; i++) - line->buffer[i] = line->buffer[i + diff]; + memmove (&line->buffer[line->position], + &line->buffer[line->position + diff], + line->length - line->position + diff + 1); - line->length -= diff; - } + line->length -= diff; return EDIT_DELETE; } @@ -284,25 +324,29 @@ editor_kill_word (rp_input_line *line) static edit_status editor_backward_kill_word (rp_input_line *line) { - int i, diff; + size_t diff = 1; - if (line->position > 0) - { - for (i = line->position; i > 0 && !isalnum (line->buffer[i - 1]); i--); - for (; i > 0 && isalnum (line->buffer[i - 1]); i--); + if (line->position == 0) + return EDIT_NO_OP; - diff = line->position - i; + while (line->position - diff > 0 && + !isalnum (line->buffer[line->position - diff])) + diff++; - line->position = i; + while (line->position - diff > 0 + && (isalnum (line->buffer[line->position - diff]) + || RP_IS_UTF8_CHAR (line->buffer[line->position - diff]))) + diff++; - /* Add the word to the X11 selection. */ - set_nselection (&line->buffer[line->position], diff); + /* Add the word to the X11 selection. */ + set_nselection (&line->buffer[line->position - diff], diff); - for (; i <= line->length - diff; i++) - line->buffer[i] = line->buffer[i + diff]; + memmove (&line->buffer[line->position - diff], + &line->buffer[line->position], + line->length - line->position + 1); - line->length -= diff; - } + line->position -= diff; + line->length -= diff; return EDIT_DELETE; } @@ -310,14 +354,14 @@ editor_backward_kill_word (rp_input_line *line) static edit_status editor_kill_line (rp_input_line *line) { - if (line->position < line->length) - { - /* Add the line to the X11 selection. */ - set_selection (&line->buffer[line->position]); + if (line->position == line->length) + return EDIT_NO_OP; - line->length = line->position; - line->buffer[line->length] = 0; - } + /* Add the line to the X11 selection. */ + set_selection (&line->buffer[line->position]); + + line->length = line->position; + line->buffer[line->length] = '\0'; return EDIT_DELETE; } @@ -326,14 +370,9 @@ editor_kill_line (rp_input_line *line) static void backward_kill_line (rp_input_line *line) { - int i; - - /* If we're at the beginning, we have nothing to do. */ - if (line->position <= 0) - return; - - for (i = line->position; i<= line->length; i++) - line->buffer[i - line->position] = line->buffer[i]; + memmove (&line->buffer[0], + &line->buffer[line->position], + line->length - line->position + 1); line->length -= line->position; line->position = 0; @@ -342,7 +381,7 @@ backward_kill_line (rp_input_line *line) static edit_status editor_backward_kill_line (rp_input_line *line) { - if (line->position <= 0) + if (line->position == 0) return EDIT_NO_OP; /* Add the line to the X11 selection. */ @@ -429,7 +468,7 @@ editor_no_action (rp_input_line *line UNUSED) static edit_status editor_insert (rp_input_line *line, char *keysym_buf) { - int nbytes; + size_t nbytes; PRINT_DEBUG (("keysym_buf: '%s'\n", keysym_buf)); @@ -441,8 +480,10 @@ editor_insert (rp_input_line *line, char *keysym_buf) line->buffer = xrealloc (line->buffer, line->size); } - memmove (&line->buffer[line->position + nbytes], &line->buffer[line->position], line->length - line->position); - strncpy (&line->buffer[line->position], keysym_buf, nbytes); + memmove (&line->buffer[line->position + nbytes], + &line->buffer[line->position], + line->length - line->position + 1); + memcpy (&line->buffer[line->position], keysym_buf, nbytes); line->length += nbytes; line->position += nbytes; diff --git a/src/editor.h b/src/editor.h index f3ffa31..b6e4b76 100644 --- a/src/editor.h +++ b/src/editor.h @@ -35,6 +35,11 @@ edit_status EDIT_NO_OP }; +/* UTF-8 handling macros */ +#define RP_IS_UTF8_CHAR(c) (defaults.utf8_locale && (c) & 0xC0) +#define RP_IS_UTF8_START(c) (defaults.utf8_locale && ((c) & 0xC0) == 0xC0) +#define RP_IS_UTF8_CONT(c) (defaults.utf8_locale && ((c) & 0xC0) == 0x80) + /* Input line functions */ rp_input_line *input_line_new (char *prompt, char *preinput, int history_id, completion_fn fn); void input_line_free (rp_input_line *line); diff --git a/src/input.c b/src/input.c index 86866f7..5757bf7 100644 --- a/src/input.c +++ b/src/input.c @@ -428,16 +428,23 @@ read_key (KeySym *keysym, unsigned int *modifiers, char *keysym_name, int len) static void update_input_window (rp_screen *s, rp_input_line *line) { - int prompt_width = rp_text_width (s, line->prompt, -1); - int input_width = rp_text_width (s, line->buffer, line->length); - int total_width; + int prompt_width, input_width, total_width; + int char_len = 0, height; GC lgc; XGCValues gcv; - int height; + prompt_width = rp_text_width (s, line->prompt, -1); + input_width = rp_text_width (s, line->buffer, line->length); total_width = defaults.bar_x_padding * 2 + prompt_width + input_width + MAX_FONT_WIDTH (defaults.font); height = (FONT_HEIGHT (s) + defaults.bar_y_padding * 2); + if (RP_IS_UTF8_START (line->buffer[line->position])) + do + char_len++; + while (RP_IS_UTF8_CONT (line->buffer[line->position + char_len])); + else + char_len = 1; + if (total_width < defaults.input_window_size + prompt_width) { total_width = defaults.input_window_size + prompt_width; @@ -466,12 +473,12 @@ update_input_window (rp_screen *s, rp_input_line *line) gcv.foreground = s->fg_color ^ s->bg_color; lgc = XCreateGC (dpy, s->input_window, GCFunction | GCForeground, &gcv); - /* Draw a cheap-o cursor - MkII */ + /* Draw a cheap-o cursor - MkIII */ XFillRectangle (dpy, s->input_window, lgc, defaults.bar_x_padding + prompt_width + rp_text_width (s, line->buffer, line->position), defaults.bar_y_padding, - rp_text_width (s, &line->buffer[line->position], 1), + rp_text_width (s, &line->buffer[line->position], char_len), FONT_HEIGHT (s)); XFlush (dpy); -- cgit v1.2.3