summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTimo Sirainen <cras@irssi.org>2002-02-15 13:38:24 +0000
committercras <cras@dbcabf3a-b0e7-0310-adc4-f8d773084564>2002-02-15 13:38:24 +0000
commitafeb6fcb7d94157808a9290226adbadd42a824ec (patch)
tree064160f9e46c5799ea4e425e373e5c924b2061c3 /src
parent612c061605b78ce975eb7b23f76bf7abf3fff5bf (diff)
downloadirssi-afeb6fcb7d94157808a9290226adbadd42a824ec.zip
/SET term_type 8bit|utf8|big5 - Removed --with-big5 configure option, it's
now included the same way as utf8, though i'm not sure if it really works but at least it should partially :) Input line is now internally using 32bit chars but it's converted to 8bit chars for external use. Text buffer supports only 8bit + utf8 for now. git-svn-id: http://svn.irssi.org/repos/irssi/trunk@2448 dbcabf3a-b0e7-0310-adc4-f8d773084564
Diffstat (limited to 'src')
-rw-r--r--src/fe-text/gui-entry.c207
-rw-r--r--src/fe-text/gui-entry.h11
-rw-r--r--src/fe-text/gui-expandos.c3
-rw-r--r--src/fe-text/gui-readline.c86
-rw-r--r--src/fe-text/gui-windows.c2
-rw-r--r--src/fe-text/module.h1
-rw-r--r--src/fe-text/statusbar-items.c9
-rw-r--r--src/fe-text/term-terminfo.c139
-rw-r--r--src/fe-text/term.c18
-rw-r--r--src/fe-text/term.h23
-rw-r--r--src/fe-text/textbuffer-view.c4
-rw-r--r--src/fe-text/utf8.c129
-rw-r--r--src/fe-text/utf8.h17
13 files changed, 502 insertions, 147 deletions
diff --git a/src/fe-text/gui-entry.c b/src/fe-text/gui-entry.c
index f70bf0df..2824d4af 100644
--- a/src/fe-text/gui-entry.c
+++ b/src/fe-text/gui-entry.c
@@ -19,6 +19,7 @@
*/
#include "module.h"
+#include "misc.h"
#include "utf8.h"
#include "formats.h"
@@ -26,8 +27,19 @@
#include "gui-printtext.h"
#include "term.h"
+const unichar empty_str[] = { 0 };
+
GUI_ENTRY_REC *active_entry;
+static void entry_text_grow(GUI_ENTRY_REC *entry, int grow_size)
+{
+ if (entry->text_len+grow_size < entry->text_alloc)
+ return;
+
+ entry->text_alloc = nearest_power(entry->text_alloc+grow_size);
+ entry->text = g_realloc(entry->text, entry->text_alloc);
+}
+
GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8)
{
GUI_ENTRY_REC *rec;
@@ -36,7 +48,9 @@ GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8)
rec->xpos = xpos;
rec->ypos = ypos;
rec->width = width;
- rec->text = g_string_new(NULL);
+ rec->text_alloc = 1024;
+ rec->text = g_new(unichar, rec->text_alloc);
+ rec->text[0] = '\0';
rec->utf8 = utf8;
return rec;
}
@@ -48,8 +62,8 @@ void gui_entry_destroy(GUI_ENTRY_REC *entry)
if (active_entry == entry)
gui_entry_set_active(NULL);
- g_free_not_null(entry->prompt);
- g_string_free(entry->text, TRUE);
+ g_free(entry->text);
+ g_free(entry->prompt);
g_free(entry);
}
@@ -76,14 +90,9 @@ static void gui_entry_fix_cursor(GUI_ENTRY_REC *entry)
static void gui_entry_draw_from(GUI_ENTRY_REC *entry, int pos)
{
- const unsigned char *p, *end;
+ const unichar *p;
int xpos, end_xpos;
- if (entry->utf8) {
- /* FIXME: a stupid kludge to make the chars output correctly */
- pos = 0;
- }
-
xpos = entry->xpos + entry->promptlen + pos;
end_xpos = entry->xpos + entry->width;
if (xpos > end_xpos)
@@ -92,20 +101,14 @@ static void gui_entry_draw_from(GUI_ENTRY_REC *entry, int pos)
term_set_color(root_window, ATTR_RESET);
term_move(root_window, xpos, entry->ypos);
- p = (unsigned char *) (entry->scrstart + pos >= entry->text->len ? "" :
- entry->text->str + entry->scrstart + pos);
+ p = entry->scrstart + pos < entry->text_len ?
+ entry->text + entry->scrstart + pos : empty_str;
for (; *p != '\0' && xpos < end_xpos; p++, xpos++) {
- end = p;
- if (entry->utf8)
- get_utf8_char(&end);
-
if (entry->hidden)
term_addch(root_window, ' ');
- else if (*p >= 32 && (end != p || (*p & 127) >= 32)) {
- for (; p < end; p++)
- term_addch(root_window, *p);
- term_addch(root_window, *p);
- } else {
+ else if (*p >= 32 && (entry->utf8 || (*p & 127) >= 32))
+ term_add_unichar(root_window, *p);
+ else {
term_set_color(root_window, ATTR_RESET|ATTR_REVERSE);
term_addch(root_window, *p+'A'-1);
term_set_color(root_window, ATTR_RESET);
@@ -230,38 +233,67 @@ void gui_entry_set_utf8(GUI_ENTRY_REC *entry, int utf8)
void gui_entry_set_text(GUI_ENTRY_REC *entry, const char *str)
{
- g_return_if_fail(entry != NULL);
+ g_return_if_fail(entry != NULL);
g_return_if_fail(str != NULL);
- g_string_assign(entry->text, str);
- entry->pos = entry->text->len;
+ entry->text_len = 0;
+ entry->pos = 0;
+ entry->text[0] = '\0';
- gui_entry_redraw_from(entry, 0);
- gui_entry_fix_cursor(entry);
- gui_entry_draw(entry);
+ gui_entry_insert_text(entry, str);
}
char *gui_entry_get_text(GUI_ENTRY_REC *entry)
{
+ char *buf;
+ int i;
+
g_return_val_if_fail(entry != NULL, NULL);
- return entry->text->str;
+ buf = g_malloc(entry->text_len*6 + 1);
+ if (entry->utf8)
+ utf16_to_utf8(entry->text, buf);
+ else {
+ for (i = 0; i <= entry->text_len; i++)
+ buf[i] = entry->text[i];
+ }
+ return buf;
}
void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str)
{
+ unichar chr;
+ int i, len;
+
g_return_if_fail(entry != NULL);
g_return_if_fail(str != NULL);
gui_entry_redraw_from(entry, entry->pos);
- g_string_insert(entry->text, entry->pos, str);
- entry->pos += strlen(str);
+
+ len = !entry->utf8 ? strlen(str) : strlen_utf8(str);
+ entry_text_grow(entry, len);
+
+ /* make space for the string */
+ g_memmove(entry->text + entry->pos + len, entry->text + entry->pos,
+ (entry->text_len-entry->pos + 1) * sizeof(unichar));
+
+ if (!entry->utf8) {
+ for (i = 0; i < len; i++)
+ entry->text[entry->pos+i] = str[i];
+ } else {
+ chr = entry->text[entry->pos+len];
+ utf8_to_utf16(str, entry->text+entry->pos);
+ entry->text[entry->pos+len] = chr;
+ }
+
+ entry->text_len += len;
+ entry->pos += len;
gui_entry_fix_cursor(entry);
gui_entry_draw(entry);
}
-void gui_entry_insert_char(GUI_ENTRY_REC *entry, char chr)
+void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr)
{
g_return_if_fail(entry != NULL);
@@ -269,13 +301,38 @@ void gui_entry_insert_char(GUI_ENTRY_REC *entry, char chr)
return; /* never insert NUL, CR or LF characters */
gui_entry_redraw_from(entry, entry->pos);
- g_string_insert_c(entry->text, entry->pos, chr);
- entry->pos++;
+
+ entry_text_grow(entry, 1);
+
+ /* make space for the string */
+ g_memmove(entry->text + entry->pos + 1, entry->text + entry->pos,
+ (entry->text_len-entry->pos + 1) * sizeof(unichar));
+
+ entry->text[entry->pos] = chr;
+ entry->text_len++;
+ entry->pos++;
gui_entry_fix_cursor(entry);
gui_entry_draw(entry);
}
+char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry)
+{
+ char *buf;
+ int i;
+
+ g_return_val_if_fail(entry != NULL, NULL);
+
+ buf = g_malloc(entry->cutbuffer_len*6 + 1);
+ if (entry->utf8)
+ utf16_to_utf8(entry->cutbuffer, buf);
+ else {
+ for (i = 0; i <= entry->cutbuffer_len; i++)
+ buf[i] = entry->cutbuffer[i];
+ }
+ return buf;
+}
+
void gui_entry_erase(GUI_ENTRY_REC *entry, int size)
{
g_return_if_fail(entry != NULL);
@@ -283,14 +340,22 @@ void gui_entry_erase(GUI_ENTRY_REC *entry, int size)
if (entry->pos < size)
return;
-#ifdef WANT_BIG5
- if (is_big5(entry->text->str[entry->pos-2],
- entry->text->str[entry->pos-1]))
- size++;
-#endif
+ /* put erased text to cutbuffer */
+ if (entry->cutbuffer_len < size) {
+ g_free(entry->cutbuffer);
+ entry->cutbuffer = g_new(unichar, size+1);
+ }
+
+ entry->cutbuffer_len = size;
+ entry->cutbuffer[size] = '\0';
+ memcpy(entry->cutbuffer, entry->text + entry->pos - size,
+ size * sizeof(unichar));
+
+ g_memmove(entry->text + entry->pos - size, entry->text + entry->pos,
+ (entry->text_len-entry->pos+1) * sizeof(unichar));
entry->pos -= size;
- g_string_erase(entry->text, entry->pos, size);
+ entry->text_len -= size;
gui_entry_redraw_from(entry, entry->pos);
gui_entry_fix_cursor(entry);
@@ -308,52 +373,45 @@ void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space)
to = entry->pos - 1;
if (to_space) {
- while (entry->text->str[to] == ' ' && to > 0)
+ while (entry->text[to] == ' ' && to > 0)
to--;
- while (entry->text->str[to] != ' ' && to > 0)
+ while (entry->text[to] != ' ' && to > 0)
to--;
} else {
- while (!i_isalnum(entry->text->str[to]) && to > 0)
+ while (!i_isalnum(entry->text[to]) && to > 0)
to--;
- while (i_isalnum(entry->text->str[to]) && to > 0)
+ while (i_isalnum(entry->text[to]) && to > 0)
to--;
}
if (to > 0) to++;
- g_string_erase(entry->text, to, entry->pos - to);
- entry->pos = to;
-
- gui_entry_redraw_from(entry, entry->pos);
- gui_entry_fix_cursor(entry);
- gui_entry_draw(entry);
+ gui_entry_erase(entry, entry->pos-to);
}
void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space)
{
- int to;
+ int to, size;
g_return_if_fail(entry != NULL);
- if (entry->pos == entry->text->len)
+ if (entry->pos == entry->text_len)
return;
to = entry->pos;
if (to_space) {
- while (entry->text->str[to] == ' ' && to < entry->text->len)
+ while (entry->text[to] == ' ' && to < entry->text_len)
to++;
- while (entry->text->str[to] != ' ' && to < entry->text->len)
+ while (entry->text[to] != ' ' && to < entry->text_len)
to++;
} else {
- while (!i_isalnum(entry->text->str[to]) && to < entry->text->len)
+ while (!i_isalnum(entry->text[to]) && to < entry->text_len)
to++;
- while (i_isalnum(entry->text->str[to]) && to < entry->text->len)
+ while (i_isalnum(entry->text[to]) && to < entry->text_len)
to++;
}
- g_string_erase(entry->text, entry->pos, to - entry->pos);
-
- gui_entry_redraw_from(entry, entry->pos);
- gui_entry_fix_cursor(entry);
- gui_entry_draw(entry);
+ size = to-entry->pos;
+ entry->pos = to;
+ gui_entry_erase(entry, size);
}
int gui_entry_get_pos(GUI_ENTRY_REC *entry)
@@ -367,7 +425,7 @@ void gui_entry_set_pos(GUI_ENTRY_REC *entry, int pos)
{
g_return_if_fail(entry != NULL);
- if (pos >= 0 && pos <= entry->text->len)
+ if (pos >= 0 && pos <= entry->text_len)
entry->pos = pos;
gui_entry_fix_cursor(entry);
@@ -378,16 +436,7 @@ void gui_entry_move_pos(GUI_ENTRY_REC *entry, int pos)
{
g_return_if_fail(entry != NULL);
-#ifdef WANT_BIG5
- if (pos > 0 && is_big5(entry->text->str[entry->pos],
- entry->text->str[entry->pos+1]))
- pos++;
- else if (pos < 0 && is_big5(entry->text->str[entry->pos-1],
- entry->text->str[entry->pos]))
- pos--;
-#endif
-
- if (entry->pos+pos >= 0 && entry->pos+pos <= entry->text->len)
+ if (entry->pos+pos >= 0 && entry->pos+pos <= entry->text_len)
entry->pos += pos;
gui_entry_fix_cursor(entry);
@@ -401,14 +450,14 @@ static void gui_entry_move_words_left(GUI_ENTRY_REC *entry, int count, int to_sp
pos = entry->pos;
while (count > 0 && pos > 0) {
if (to_space) {
- while (pos > 0 && entry->text->str[pos-1] == ' ')
+ while (pos > 0 && entry->text[pos-1] == ' ')
pos--;
- while (pos > 0 && entry->text->str[pos-1] != ' ')
+ while (pos > 0 && entry->text[pos-1] != ' ')
pos--;
} else {
- while (pos > 0 && !i_isalnum(entry->text->str[pos-1]))
+ while (pos > 0 && !i_isalnum(entry->text[pos-1]))
pos--;
- while (pos > 0 && i_isalnum(entry->text->str[pos-1]))
+ while (pos > 0 && i_isalnum(entry->text[pos-1]))
pos--;
}
count--;
@@ -422,16 +471,16 @@ static void gui_entry_move_words_right(GUI_ENTRY_REC *entry, int count, int to_s
int pos;
pos = entry->pos;
- while (count > 0 && pos < entry->text->len) {
+ while (count > 0 && pos < entry->text_len) {
if (to_space) {
- while (pos < entry->text->len && entry->text->str[pos] == ' ')
+ while (pos < entry->text_len && entry->text[pos] == ' ')
pos++;
- while (pos < entry->text->len && entry->text->str[pos] != ' ')
+ while (pos < entry->text_len && entry->text[pos] != ' ')
pos++;
} else {
- while (pos < entry->text->len && !i_isalnum(entry->text->str[pos]))
+ while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
pos++;
- while (pos < entry->text->len && i_isalnum(entry->text->str[pos]))
+ while (pos < entry->text_len && i_isalnum(entry->text[pos]))
pos++;
}
count--;
diff --git a/src/fe-text/gui-entry.h b/src/fe-text/gui-entry.h
index 364f92da..347be476 100644
--- a/src/fe-text/gui-entry.h
+++ b/src/fe-text/gui-entry.h
@@ -2,7 +2,13 @@
#define __GUI_ENTRY_H
typedef struct {
- GString *text;
+ int text_len, text_alloc; /* as shorts, not chars */
+ unichar *text;
+
+ int cutbuffer_len;
+ unichar *cutbuffer;
+
+ /* all as shorts, not chars */
int xpos, ypos, width; /* entry position in screen */
int pos, scrstart, scrpos; /* cursor position */
int hidden; /* print the chars as spaces in input line (useful for passwords) */
@@ -30,8 +36,9 @@ void gui_entry_set_text(GUI_ENTRY_REC *entry, const char *str);
char *gui_entry_get_text(GUI_ENTRY_REC *entry);
void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str);
-void gui_entry_insert_char(GUI_ENTRY_REC *entry, char chr);
+void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr);
+char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry);
void gui_entry_erase(GUI_ENTRY_REC *entry, int size);
void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space);
void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space);
diff --git a/src/fe-text/gui-expandos.c b/src/fe-text/gui-expandos.c
index b07bf129..74d6b34d 100644
--- a/src/fe-text/gui-expandos.c
+++ b/src/fe-text/gui-expandos.c
@@ -43,7 +43,8 @@ static char *expando_inputline(SERVER_REC *server, void *item, int *free_ret)
/* value of cutbuffer */
static char *expando_cutbuffer(SERVER_REC *server, void *item, int *free_ret)
{
- return cutbuffer;
+ *free_ret = TRUE;
+ return gui_entry_get_cutbuffer(active_entry);
}
void gui_expandos_init(void)
diff --git a/src/fe-text/gui-readline.c b/src/fe-text/gui-readline.c
index 8fe17410..2ec9bd2d 100644
--- a/src/fe-text/gui-readline.c
+++ b/src/fe-text/gui-readline.c
@@ -33,6 +33,7 @@
#include "term.h"
#include "gui-entry.h"
#include "gui-windows.h"
+#include "utf8.h"
#include <signal.h>
@@ -48,7 +49,6 @@ typedef struct {
static KEYBOARD_REC *keyboard;
static ENTRY_REDIRECT_REC *redir;
-char *cutbuffer;
static int readtag;
static time_t idle_time;
@@ -133,9 +133,9 @@ static void window_next_page(void)
gui_window_scroll(active_win, get_scroll_count());
}
-void handle_key(int key)
+void handle_key(unichar key)
{
- char str[3];
+ char str[20];
idle_time = time(NULL);
@@ -147,20 +147,23 @@ void handle_key(int key)
if (key >= 0 && key < 32) {
/* control key */
str[0] = '^';
- str[1] = key+'@';
+ str[1] = (char)key+'@';
str[2] = '\0';
} else if (key == 127) {
str[0] = '^';
str[1] = '?';
str[2] = '\0';
- } else {
- str[0] = key;
+ } else if (!active_entry->utf8) {
+ str[0] = (char)key;
str[1] = '\0';
+ } else {
+ /* need to convert to utf8 */
+ str[utf16_char_to_utf8(key, str)] = '\0';
}
if (!key_pressed(keyboard, str)) {
/* key wasn't used for anything, print it */
- gui_entry_insert_char(active_entry, (char) key);
+ gui_entry_insert_char(active_entry, key);
}
}
@@ -170,7 +173,10 @@ static void key_send_line(void)
char *str, *add_history;
str = gui_entry_get_text(active_entry);
- if (*str == '\0') return;
+ if (*str == '\0') {
+ g_free(str);
+ return;
+ }
/* we can't use gui_entry_get_text() later, since the entry might
have been destroyed after we get back */
@@ -199,6 +205,8 @@ static void key_send_line(void)
if (active_entry != NULL)
gui_entry_set_text(active_entry, "");
command_history_clear_pos(active_win);
+
+ g_free(str);
}
static void key_combo(void)
@@ -208,17 +216,23 @@ static void key_combo(void)
static void key_backward_history(void)
{
const char *text;
+ char *line;
- text = command_history_prev(active_win, gui_entry_get_text(active_entry));
+ line = gui_entry_get_text(active_entry);
+ text = command_history_prev(active_win, line);
gui_entry_set_text(active_entry, text);
+ g_free(line);
}
static void key_forward_history(void)
{
const char *text;
+ char *line;
- text = command_history_next(active_win, gui_entry_get_text(active_entry));
+ line = gui_entry_get_text(active_entry);
+ text = command_history_next(active_win, line);
gui_entry_set_text(active_entry, text);
+ g_free(line);
}
static void key_beginning_of_line(void)
@@ -228,7 +242,7 @@ static void key_beginning_of_line(void)
static void key_end_of_line(void)
{
- gui_entry_set_pos(active_entry, strlen(gui_entry_get_text(active_entry)));
+ gui_entry_set_pos(active_entry, active_entry->text_len);
}
static void key_backward_character(void)
@@ -263,10 +277,8 @@ static void key_forward_to_space(void)
static void key_erase_line(void)
{
- g_free_not_null(cutbuffer);
- cutbuffer = g_strdup(gui_entry_get_text(active_entry));
-
- gui_entry_set_text(active_entry, "");
+ gui_entry_set_pos(active_entry, active_entry->text_len);
+ gui_entry_erase(active_entry, active_entry->text_len);
}
static void key_erase_to_beg_of_line(void)
@@ -274,9 +286,6 @@ static void key_erase_to_beg_of_line(void)
int pos;
pos = gui_entry_get_pos(active_entry);
- g_free_not_null(cutbuffer);
- cutbuffer = g_strndup(gui_entry_get_text(active_entry), pos);
-
gui_entry_erase(active_entry, pos);
}
@@ -285,21 +294,22 @@ static void key_erase_to_end_of_line(void)
int pos;
pos = gui_entry_get_pos(active_entry);
- g_free_not_null(cutbuffer);
- cutbuffer = g_strdup(gui_entry_get_text(active_entry)+pos);
-
- gui_entry_set_pos(active_entry, strlen(gui_entry_get_text(active_entry)));
- gui_entry_erase(active_entry, strlen(gui_entry_get_text(active_entry)) - pos);
+ gui_entry_set_pos(active_entry, active_entry->text_len);
+ gui_entry_erase(active_entry, active_entry->text_len - pos);
}
static void key_yank_from_cutbuffer(void)
{
+ char *cutbuffer;
+
+ cutbuffer = gui_entry_get_cutbuffer(active_entry);
if (cutbuffer != NULL)
gui_entry_insert_text(active_entry, cutbuffer);
}
static void key_transpose_characters(void)
{
+#if 0 /* FIXME: !!! */
char *line, c;
int pos;
@@ -316,11 +326,12 @@ static void key_transpose_characters(void)
gui_entry_insert_char(active_entry, c);
gui_entry_set_pos(active_entry, pos);
gui_entry_move_pos(active_entry, 1);
+#endif
}
static void key_delete_character(void)
{
- if (gui_entry_get_pos(active_entry) < (int)strlen(gui_entry_get_text(active_entry))) {
+ if (gui_entry_get_pos(active_entry) < active_entry->text_len) {
gui_entry_move_pos(active_entry, 1);
gui_entry_erase(active_entry, 1);
}
@@ -353,7 +364,7 @@ static void key_delete_to_next_space(void)
static void sig_input(void)
{
- unsigned char buffer[128];
+ unichar buffer[128];
int ret, i;
if (!active_entry) {
@@ -361,7 +372,7 @@ static void sig_input(void)
return;
}
- ret = term_gets(buffer, sizeof(buffer));
+ ret = term_gets(buffer, sizeof(buffer)/sizeof(buffer[0]));
if (ret == -1) {
/* lost terminal */
if (!term_detached)
@@ -404,13 +415,15 @@ static void key_change_window(const char *data)
static void key_completion(int erase)
{
- char *line;
+ char *text, *line;
int pos;
pos = gui_entry_get_pos(active_entry);
- line = word_complete(active_win, gui_entry_get_text(active_entry),
- &pos, erase);
+ text = gui_entry_get_text(active_entry);
+ line = word_complete(active_win, text, &pos, erase);
+ g_free(text);
+
if (line != NULL) {
gui_entry_set_text(active_entry, line);
gui_entry_set_pos(active_entry, pos);
@@ -430,12 +443,15 @@ static void key_erase_completion(void)
static void key_check_replaces(void)
{
- char *line;
+ char *text, *line;
int pos;
pos = gui_entry_get_pos(active_entry);
- line = auto_word_complete(gui_entry_get_text(active_entry), &pos);
+ text = gui_entry_get_text(active_entry);
+ line = auto_word_complete(text, &pos);
+ g_free(text);
+
if (line != NULL) {
gui_entry_set_text(active_entry, line);
gui_entry_set_pos(active_entry, pos);
@@ -537,11 +553,15 @@ static void key_sig_stop(void)
static void sig_window_auto_changed(void)
{
+ char *text;
+
if (active_entry == NULL)
return;
- command_history_next(active_win, gui_entry_get_text(active_entry));
+ text = gui_entry_get_text(active_entry);
+ command_history_next(active_win, text);
gui_entry_set_text(active_entry, "");
+ g_free(text);
}
static void sig_gui_entry_redirect(SIGNAL_FUNC func, const char *entry,
@@ -563,7 +583,6 @@ void gui_readline_init(void)
char *key, data[MAX_INT_STRLEN];
int n;
- cutbuffer = NULL;
redir = NULL;
idle_time = time(NULL);
input_listen_init(STDIN_FILENO);
@@ -693,7 +712,6 @@ void gui_readline_init(void)
void gui_readline_deinit(void)
{
- g_free_not_null(cutbuffer);
input_listen_deinit();
key_configure_freeze();
diff --git a/src/fe-text/gui-windows.c b/src/fe-text/gui-windows.c
index cd834ee4..1e7316f4 100644
--- a/src/fe-text/gui-windows.c
+++ b/src/fe-text/gui-windows.c
@@ -44,7 +44,7 @@ static GUI_WINDOW_REC *gui_window_init(WINDOW_REC *window,
gui->view = textbuffer_view_create(textbuffer_create(),
window->width, window->height,
settings_get_bool("scroll"),
- settings_get_bool("term_utf8"));
+ term_type == TERM_TYPE_UTF8);
textbuffer_view_set_default_indent(gui->view,
settings_get_int("indent"),
!settings_get_bool("indent_always"),
diff --git a/src/fe-text/module.h b/src/fe-text/module.h
index c6643545..0ca9f703 100644
--- a/src/fe-text/module.h
+++ b/src/fe-text/module.h
@@ -1,4 +1,5 @@
#include "common.h"
+#include "term.h"
#define MODULE_NAME "fe-text"
diff --git a/src/fe-text/statusbar-items.c b/src/fe-text/statusbar-items.c
index 7612510a..d86c1e45 100644
--- a/src/fe-text/statusbar-items.c
+++ b/src/fe-text/statusbar-items.c
@@ -347,8 +347,7 @@ static void item_input(SBAR_ITEM_REC *item, int get_size_only)
rec = g_hash_table_lookup(input_entries, item->bar);
if (rec == NULL) {
rec = gui_entry_create(item->xpos, item->bar->real_ypos,
- item->size,
- settings_get_bool("term_utf8"));
+ item->size, term_type == TERM_TYPE_UTF8);
gui_entry_set_active(rec);
g_hash_table_insert(input_entries, item->bar, rec);
}
@@ -377,10 +376,8 @@ static void sig_statusbar_destroyed(STATUSBAR_REC *bar)
static void read_settings(void)
{
- if (active_entry != NULL) {
- gui_entry_set_utf8(active_entry,
- settings_get_bool("term_utf8"));
- }
+ if (active_entry != NULL)
+ gui_entry_set_utf8(active_entry, term_type == TERM_TYPE_UTF8);
}
void statusbar_items_init(void)
diff --git a/src/fe-text/term-terminfo.c b/src/fe-text/term-terminfo.c
index a1b106a7..fde313b7 100644
--- a/src/fe-text/term-terminfo.c
+++ b/src/fe-text/term-terminfo.c
@@ -22,9 +22,16 @@
#include "signals.h"
#include "term.h"
#include "terminfo-core.h"
+#include "utf8.h"
#include <signal.h>
+/* returns number of characters in the beginning of the buffer being a
+ a single character, or -1 if more input is needed. The character will be
+ saved in result */
+typedef int (*TERM_INPUT_FUNC)(const unsigned char *buffer, int size,
+ unichar *result);
+
struct _TERM_WINDOW {
/* Terminal to use for window */
TERM_REC *term;
@@ -48,6 +55,10 @@ static int last_fg, last_bg, last_attrs;
static int redraw_needed, redraw_tag;
static int freeze_counter;
+static TERM_INPUT_FUNC input_func;
+static unsigned char term_inbuf[256];
+static int term_inbuf_pos;
+
/* SIGCONT handler */
static void sig_cont(int p)
{
@@ -94,6 +105,7 @@ int term_init(void)
term_lines_empty = g_new0(char, term_height);
+ term_set_input_type(TERM_TYPE_8BIT);
term_common_init();
g_atexit(term_deinit);
return TRUE;
@@ -373,6 +385,39 @@ void term_addch(TERM_WINDOW *window, int chr)
putc(chr, window->term->out);
}
+static void term_addch_utf8(TERM_WINDOW *window, unichar chr)
+{
+ unsigned char buf[10];
+ int i, len;
+
+ len = utf16_char_to_utf8(chr, buf);
+ for (i = 0; i < len; i++)
+ putc(buf[i], window->term->out);
+}
+
+void term_add_unichar(TERM_WINDOW *window, unichar chr)
+{
+ if (term_detached) return;
+
+ if (vcmove) term_move_real();
+ term_printed_text(1);
+ if (vcy == term_height && vcx == 0)
+ return; /* last char in screen */
+
+ switch (term_type) {
+ case TERM_TYPE_UTF8:
+ term_addch_utf8(window, chr);
+ break;
+ case TERM_TYPE_BIG5:
+ putc((chr >> 8) & 0xff, window->term->out);
+ putc((chr & 0xff), window->term->out);
+ break;
+ default:
+ putc(chr, window->term->out);
+ break;
+ }
+}
+
void term_addstr(TERM_WINDOW *window, const char *str)
{
int len;
@@ -487,15 +532,80 @@ void term_stop(void)
}
}
-int term_gets(unsigned char *buffer, int size)
+static int input_utf8(const unsigned char *buffer, int size, unichar *result)
+{
+ const unsigned char *end = buffer;
+
+ *result = get_utf8_char(&end, size);
+ switch (*result) {
+ case (unichar) -2:
+ /* not UTF8 - fallback to 8bit ascii */
+ *result = *buffer;
+ return 1;
+ case (unichar) -1:
+ /* need more data */
+ return -1;
+ default:
+ return (int) (end-buffer)+1;
+ }
+}
+
+/* XXX I didn't check the encoding range of big5+. This is standard big5. */
+#define is_big5_los(lo) (0x40 <= (lo) && (lo) <= 0x7E) /* standard */
+#define is_big5_lox(lo) (0x80 <= (lo) && (lo) <= 0xFE) /* extended */
+#define is_big5_hi(hi) (0x81 <= (hi) && (hi) <= 0xFE)
+#define is_big5(hi,lo) (is_big5_hi(hi) && (is_big5_los(lo) || is_big5_lox(lo)))
+
+static int input_big5(const unsigned char *buffer, int size, unichar *result)
+{
+ if (is_big5_hi(*buffer)) {
+ /* could be */
+ if (size == 1)
+ return -1;
+
+ if (is_big5_los(buffer[1]) || is_big5_lox(buffer[1])) {
+ *result = buffer[1] + ((int) *buffer << 8);
+ return 2;
+ }
+ }
+
+ *result = *buffer;
+ return 1;
+}
+
+static int input_8bit(const unsigned char *buffer, int size, unichar *result)
{
- int ret;
+ *result = *buffer;
+ return 1;
+}
+
+void term_set_input_type(int type)
+{
+ switch (type) {
+ case TERM_TYPE_UTF8:
+ input_func = input_utf8;
+ break;
+ case TERM_TYPE_BIG5:
+ input_func = input_big5;
+ break;
+ default:
+ input_func = input_8bit;
+ }
+}
+
+int term_gets(unichar *buffer, int size)
+{
+ int ret, i, char_len;
if (term_detached)
return 0;
/* fread() doesn't work */
- ret = read(fileno(current_term->in), buffer, size);
+ if (size > sizeof(term_inbuf)-term_inbuf_pos)
+ size = sizeof(term_inbuf)-term_inbuf_pos;
+
+ ret = read(fileno(current_term->in),
+ term_inbuf + term_inbuf_pos, size);
if (ret == 0) {
/* EOF - terminal got lost */
if (auto_detach)
@@ -504,5 +614,28 @@ int term_gets(unsigned char *buffer, int size)
} else if (ret == -1 && (errno == EINTR || errno == EAGAIN))
ret = 0;
+ if (ret > 0) {
+ /* convert input to unichars. */
+ term_inbuf_pos += ret;
+ ret = 0;
+ for (i = 0; i < term_inbuf_pos; ) {
+ char_len = input_func(term_inbuf+i, term_inbuf_pos-i,
+ buffer);
+ if (char_len < 0)
+ break;
+
+ i += char_len;
+ buffer++;
+ ret++;
+ }
+
+ if (i >= term_inbuf_pos)
+ term_inbuf_pos = 0;
+ else {
+ memmove(term_inbuf+i, term_inbuf, term_inbuf_pos-i);
+ term_inbuf_pos = i;
+ }
+ }
+
return ret;
}
diff --git a/src/fe-text/term.c b/src/fe-text/term.c
index c32b2491..804157fb 100644
--- a/src/fe-text/term.c
+++ b/src/fe-text/term.c
@@ -35,6 +35,7 @@
#define MIN_SCREEN_WIDTH 20
int term_use_colors;
+int term_type;
static int force_colors;
static int resize_dirty;
@@ -91,10 +92,25 @@ static void cmd_resize(void)
static void read_settings(void)
{
+ const char *str;
int old_colors = term_use_colors;
+ int old_type = term_type;
term_auto_detach(settings_get_bool("term_auto_detach"));
+ /* set terminal type */
+ str = settings_get_str("term_type");
+ if (g_strcasecmp(str, "utf8") == 0)
+ term_type = TERM_TYPE_UTF8;
+ else if (g_strcasecmp(str, "big5") == 0)
+ term_type = TERM_TYPE_BIG5;
+ else
+ term_type = TERM_TYPE_8BIT;
+
+ if (old_type != term_type)
+ term_set_input_type(term_type);
+
+ /* change color stuff */
if (force_colors != settings_get_bool("term_force_colors")) {
force_colors = settings_get_bool("term_force_colors");
term_force_colors(force_colors);
@@ -115,7 +131,7 @@ void term_common_init(void)
settings_add_bool("lookandfeel", "colors", TRUE);
settings_add_bool("lookandfeel", "term_force_colors", FALSE);
settings_add_bool("lookandfeel", "term_auto_detach", FALSE);
- settings_add_bool("lookandfeel", "term_utf8", FALSE);
+ settings_add_str("lookandfeel", "term_type", "8bit");
force_colors = FALSE;
term_use_colors = term_has_colors() && settings_get_bool("colors");
diff --git a/src/fe-text/term.h b/src/fe-text/term.h
index 9cd1b153..3607fad5 100644
--- a/src/fe-text/term.h
+++ b/src/fe-text/term.h
@@ -3,6 +3,7 @@
typedef struct _TERM_WINDOW TERM_WINDOW;
+/* text attributes */
#define ATTR_RESETFG 0x0100
#define ATTR_RESETBG 0x0200
#define ATTR_BOLD 0x0400
@@ -14,16 +15,16 @@ typedef struct _TERM_WINDOW TERM_WINDOW;
#define ATTR_NOCOLORS (ATTR_UNDERLINE|ATTR_REVERSE)
-#ifdef WANT_BIG5
-/* XXX I didn't check the encoding range of big5+. This is standard big5. */
-# define is_big5_los(lo) (((char)0x40<=lo)&&(lo<=(char)0x7E)) /* standard */
-# define is_big5_lox(lo) (((char)0x80<=lo)&&(lo<=(char)0xFE)) /* extended */
-# define is_big5_hi(hi) (((char)0x81<=hi)&&(hi<=(char)0xFE))
-# define is_big5(hi,lo) is_big5_hi(hi) && (is_big5_los(lo) || is_big5_lox(lo))
-#endif
+/* terminal types */
+#define TERM_TYPE_8BIT 0 /* normal 8bit text */
+#define TERM_TYPE_UTF8 1
+#define TERM_TYPE_BIG5 2
+
+typedef guint32 unichar;
extern TERM_WINDOW *root_window;
-extern int term_width, term_height, term_use_colors, term_detached;
+extern int term_width, term_height;
+extern int term_use_colors, term_type, term_detached;
/* Initialize / deinitialize terminal */
int term_init(void);
@@ -63,6 +64,7 @@ void term_set_color(TERM_WINDOW *window, int col);
void term_move(TERM_WINDOW *window, int x, int y);
void term_addch(TERM_WINDOW *window, int chr);
+void term_add_unichar(TERM_WINDOW *window, unichar chr);
void term_addstr(TERM_WINDOW *window, const char *str);
void term_clrtoeol(TERM_WINDOW *window);
@@ -78,7 +80,10 @@ void term_detach(void);
void term_attach(FILE *in, FILE *out);
void term_stop(void);
-int term_gets(unsigned char *buffer, int size);
+
+/* keyboard input handling */
+void term_set_input_type(int type);
+int term_gets(unichar *buffer, int size);
/* internal */
void term_common_init(void);
diff --git a/src/fe-text/textbuffer-view.c b/src/fe-text/textbuffer-view.c
index d98fc85c..dc21aae6 100644
--- a/src/fe-text/textbuffer-view.c
+++ b/src/fe-text/textbuffer-view.c
@@ -231,7 +231,7 @@ view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
}
if (view->utf8)
- get_utf8_char(&ptr);
+ get_utf8_char(&ptr, 6);
xpos++;
if (*ptr++ == ' ') {
@@ -398,7 +398,7 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
if (xpos < term_width) {
const unsigned char *end = text;
if (view->utf8)
- get_utf8_char(&end);
+ get_utf8_char(&end, 6);
if (*text >= 32 &&
(end != text || (*text & 127) >= 32)) {
diff --git a/src/fe-text/utf8.c b/src/fe-text/utf8.c
index 63a834c8..e58307d2 100644
--- a/src/fe-text/utf8.c
+++ b/src/fe-text/utf8.c
@@ -1,3 +1,29 @@
+/* utf8.c - Operations on UTF-8 strings.
+ *
+ * Copyright (C) 2002 Timo Sirainen
+ *
+ * Based on GLib code by
+ *
+ * Copyright (C) 1999 Tom Tromey
+ * Copyright (C) 2000 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "module.h"
#define UTF8_COMPUTE(Char, Mask, Len) \
if (Char < 128) \
@@ -46,19 +72,106 @@
(Result) |= ((Chars)[(Count)] & 0x3f); \
}
-void get_utf8_char(const unsigned char **ptr)
+unichar get_utf8_char(const unsigned char **ptr, int len)
{
- int i, mask = 0, len;
- unsigned int result;
- unsigned char c = (unsigned char) **ptr;
+ int i, result, mask, chrlen;
- UTF8_COMPUTE(c, mask, len);
+ mask = 0;
+ UTF8_COMPUTE(**ptr, mask, chrlen);
if (len == -1)
- return;
+ return (unichar) -2;
+
+ if (chrlen > len)
+ return (unichar) -1;
UTF8_GET(result, *ptr, i, mask, len);
if (result == -1)
- return;
+ return (unichar) -2;
+
+ *ptr += len-1;
+ return result;
+}
+
+int strlen_utf8(const char *str)
+{
+ const unsigned char *p = (const unsigned char *) str;
+ int len;
+
+ len = 0;
+ while (*p != '\0' && get_utf8_char(&p, 6) > 0) {
+ len++;
+ p++;
+ }
+ return len;
+}
+
+int utf16_char_to_utf8(unichar c, unsigned char *outbuf)
+{
+ int len, i, first;
+
+ len = 0;
+ if (c < 0x80) {
+ first = 0;
+ len = 1;
+ } else if (c < 0x800) {
+ first = 0xc0;
+ len = 2;
+ } else if (c < 0x10000) {
+ first = 0xe0;
+ len = 3;
+ } else if (c < 0x200000) {
+ first = 0xf0;
+ len = 4;
+ } else if (c < 0x4000000) {
+ first = 0xf8;
+ len = 5;
+ } else {
+ first = 0xfc;
+ len = 6;
+ }
+
+ if (outbuf) {
+ for (i = len - 1; i > 0; --i) {
+ outbuf[i] = (c & 0x3f) | 0x80;
+ c >>= 6;
+ }
+ outbuf[0] = c | first;
+ }
+
+ return len;
+}
+
+void utf8_to_utf16(const char *str, unichar *out)
+{
+ const unsigned char *p = (const unsigned char *) str;
+ int i, result, mask, len;
+
+ while (*p != '\0') {
+ mask = 0;
+ UTF8_COMPUTE(*p, mask, len);
+ if (len == -1)
+ break;
+
+ UTF8_GET(result, p, i, mask, len);
+ if (result == -1)
+ break;
+
+ p += len;
+ *out++ = result;
+ }
+
+ *out = '\0';
+}
+
+void utf16_to_utf8(const unichar *str, char *out)
+{
+ int len;
+
+ while (*str != '\0') {
+ len = utf16_char_to_utf8(*str, out);
+ out += len;
- *ptr += len-1;
+ str++;
+ }
+ *out = '\0';
}
diff --git a/src/fe-text/utf8.h b/src/fe-text/utf8.h
index 3d8f3783..a37c0b6a 100644
--- a/src/fe-text/utf8.h
+++ b/src/fe-text/utf8.h
@@ -1,6 +1,21 @@
#ifndef __UTF8_H
#define __UTF8_H
-void get_utf8_char(const unsigned char **ptr);
+/* Returns -2 = invalid, -1 = need more data, otherwise unichar. */
+unichar get_utf8_char(const unsigned char **ptr, int len);
+
+/* Returns length of UTF8 string */
+int strlen_utf8(const char *str);
+
+/* UTF-8 -> unichar string. The NUL is copied as well. */
+void utf8_to_utf16(const char *str, unichar *out);
+
+/* unichar -> UTF-8 string. outbuf must be at least 6 chars long.
+ Returns outbuf string length. */
+int utf16_char_to_utf8(unichar c, unsigned char *outbuf);
+
+/* unichar -> UTF-8 string. The NUL is copied as well.
+ Make sure out is at least 6 x length of str. */
+void utf16_to_utf8(const unichar *str, char *out);
#endif