summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJérémie Courrèges-Anglas <jca@wxcvbn.org>2013-04-15 01:21:04 +0200
committerJérémie Courrèges-Anglas <jca@wxcvbn.org>2013-04-15 01:21:04 +0200
commit01b4d568b99fc48fdab0ec628a550dfbeaa7b021 (patch)
tree6629463cfe74fc9be48a9c631e419ca7b51308c2
parent5a6fe0574c77342f29370219fb9010b72d6d3a00 (diff)
downloadratpoison-01b4d568b99fc48fdab0ec628a550dfbeaa7b021.zip
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. ;)
-rw-r--r--src/editor.c223
-rw-r--r--src/editor.h5
-rw-r--r--src/input.c19
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);