1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-12-04 14:46:47 -05:00

Witekfl's UTF-8 patch v5.

This commit is contained in:
Witold Filipczyk 2006-01-14 22:44:00 +01:00 committed by Jonas Fonseca
parent 3251644dcf
commit 44a1aa9c87
22 changed files with 1099 additions and 159 deletions

View File

@ -167,6 +167,31 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
attr = get_opt_bool("ui.dialogs.underline_button_shortcuts") attr = get_opt_bool("ui.dialogs.underline_button_shortcuts")
? SCREEN_ATTR_UNDERLINE : 0; ? SCREEN_ATTR_UNDERLINE : 0;
if (term->utf8) {
unsigned char *text2 = text;
unsigned char *end = text
+ widget_data->widget->info.button.truetextlen;
int hk_state = 0;
int x1;
for (x1 = 0; x1 - !!hk_state < len && *text2; x1++) {
uint16_t data;
data = (uint16_t)utf_8_to_unicode(&text2, end);
if (!hk_state && (int)(text2 - text) == hk_pos + 1) {
hk_state = 1;
continue;
}
if (hk_state == 1) {
draw_char(term, x + x1 - 1, pos->y, data, attr, shortcut_color);
hk_state = 2;
} else {
draw_char(term, x + x1 - !!hk_state, pos->y, data, 0, color);
}
}
len = x1 - !!hk_state;
} else
if (hk_pos >= 0) { if (hk_pos >= 0) {
int right = widget_data->widget->info.button.truetextlen - hk_pos - 1; int right = widget_data->widget->info.button.truetextlen - hk_pos - 1;

View File

@ -12,6 +12,7 @@
#include "bfu/dialog.h" #include "bfu/dialog.h"
#include "config/kbdbind.h" #include "config/kbdbind.h"
#include "config/options.h" #include "config/options.h"
#include "intl/charsets.h"
#include "intl/gettext/libintl.h" #include "intl/gettext/libintl.h"
#include "terminal/draw.h" #include "terminal/draw.h"
#include "main/timer.h" #include "main/timer.h"
@ -96,13 +97,18 @@ redraw_dialog(struct dialog_data *dlg_data, int layout)
title_color = get_bfu_color(term, "dialog.title"); title_color = get_bfu_color(term, "dialog.title");
if (title_color && box.width > 2) { if (title_color && box.width > 2) {
unsigned char *title = dlg_data->dlg->title; unsigned char *title = dlg_data->dlg->title;
int titlelen = int_min(box.width - 2, strlen(title)); unsigned char *t2 = title;
int x = (box.width - titlelen) / 2 + box.x; int titlelen = strlen(title);
int len = term->utf8 ? strlen_utf8(&t2) : titlelen;
#if 1
len = int_min(box.width - 2, len);
#endif
int x = (box.width - len) / 2 + box.x;
int y = box.y - 1; int y = box.y - 1;
draw_text(term, x - 1, y, " ", 1, 0, title_color); draw_text(term, x - 1, y, " ", 1, 0, title_color);
draw_text(term, x, y, title, titlelen, 0, title_color); draw_text(term, x, y, title, titlelen, 0, title_color);
draw_text(term, x + titlelen, y, " ", 1, 0, title_color); draw_text(term, x + len, y, " ", 1, 0, title_color);
} }
} }

View File

@ -17,6 +17,7 @@
#include "bfu/msgbox.h" #include "bfu/msgbox.h"
#include "bfu/text.h" #include "bfu/text.h"
#include "config/kbdbind.h" #include "config/kbdbind.h"
#include "intl/charsets.h"
#include "intl/gettext/libintl.h" #include "intl/gettext/libintl.h"
#include "osdep/osdep.h" #include "osdep/osdep.h"
#include "session/session.h" #include "session/session.h"
@ -101,6 +102,71 @@ check_nonempty(struct dialog_data *dlg_data, struct widget_data *widget_data)
return EVENT_NOT_PROCESSED; return EVENT_NOT_PROCESSED;
} }
#if 0
void
dlg_format_field(struct terminal *term,
struct widget_data *widget_data,
int x, int *y, int w, int *rw, enum format_align align)
{
static int max_label_width;
static int *prev_y; /* Assert the uniqueness of y */ /* TODO: get rid of this !! --Zas */
unsigned char *label = widget_data->widget->text;
struct color_pair *text_color = NULL;
int label_width = 0;
int float_label = widget_data->widget->info.field.flags & (INPFIELD_FLOAT|INPFIELD_FLOAT2);
if (label && *label && float_label) {
unsigned char *l2 = label;
int len = strlen(label);
label_width = term->utf8 ? strlen_utf8(&l2) : len;
if (prev_y == y) {
int_lower_bound(&max_label_width, label_width);
} else {
max_label_width = label_width;
prev_y = y;
}
/* Right align the floating label up against the
* input field */
x += max_label_width - label_width;
w -= max_label_width - len;
}
if (label && *label) {
if (term) text_color = get_bfu_color(term, "dialog.text");
dlg_format_text_do(term, label, x, y, w, rw, text_color, ALIGN_LEFT);
}
/* XXX: We want the field and label on the same line if the terminal
* width allows it. */
if (label && *label && float_label) {
if (widget_data->widget->info.field.flags & INPFIELD_FLOAT) {
(*y) -= INPUTFIELD_HEIGHT;
dlg_format_text_do(term, INPUTFIELD_FLOAT_SEPARATOR,
x + label_width, y, w, rw,
text_color, ALIGN_LEFT);
w -= INPUTFIELD_FLOAT_SEPARATOR_LEN + INPUTFIELD_FLOATLABEL_PADDING;
x += INPUTFIELD_FLOAT_SEPARATOR_LEN + INPUTFIELD_FLOATLABEL_PADDING;
}
/* FIXME: Is 5 chars for input field enough? --jonas */
if (label_width < w - 5) {
(*y) -= INPUTFIELD_HEIGHT;
w -= label_width;
x += label_width;
}
}
if (rw) int_lower_bound(rw, int_min(w, DIALOG_MIN_WIDTH));
set_box(&widget_data->box, x, *y, w, INPUTFIELD_HEIGHT);
(*y) += INPUTFIELD_HEIGHT;
}
#endif
void void
dlg_format_field(struct terminal *term, dlg_format_field(struct terminal *term,
struct widget_data *widget_data, struct widget_data *widget_data,
@ -265,11 +331,30 @@ display_field_do(struct dialog_data *dlg_data, struct widget_data *widget_data,
struct terminal *term = dlg_data->win->term; struct terminal *term = dlg_data->win->term;
struct color_pair *color; struct color_pair *color;
int sel = is_selected_widget(dlg_data, widget_data); int sel = is_selected_widget(dlg_data, widget_data);
int len = 0, left = 0;
int_bounds(&widget_data->info.field.vpos, if (term->utf8) {
unsigned char *t = widget_data->cdata;
unsigned char *t2 = t;
int p = widget_data->info.field.cpos;
unsigned char tmp = t[p];
int x;
t[p] = '\0';
len = strlen_utf8(&t2);
int_bounds(&left, len - widget_data->box.width + 1, len);
int_lower_bound(&left, 0);
for (t2 = t, x = 0; x < left; x++) {
utf_8_to_unicode(&t2, &t[p]);
}
t[p] = tmp;
widget_data->info.field.vpos = (int)(t2 - t);
} else {
int_bounds(&widget_data->info.field.vpos,
widget_data->info.field.cpos - widget_data->box.width + 1, widget_data->info.field.cpos - widget_data->box.width + 1,
widget_data->info.field.cpos); widget_data->info.field.cpos);
int_lower_bound(&widget_data->info.field.vpos, 0); int_lower_bound(&widget_data->info.field.vpos, 0);
}
color = get_bfu_color(term, "dialog.field"); color = get_bfu_color(term, "dialog.field");
if (color) if (color)
@ -277,7 +362,8 @@ display_field_do(struct dialog_data *dlg_data, struct widget_data *widget_data,
color = get_bfu_color(term, "dialog.field-text"); color = get_bfu_color(term, "dialog.field-text");
if (color) { if (color) {
int len = strlen(widget_data->cdata + widget_data->info.field.vpos); unsigned char *text = widget_data->cdata + widget_data->info.field.vpos;
int len = strlen(text);
int w = int_min(len, widget_data->box.width); int w = int_min(len, widget_data->box.width);
if (!hide) { if (!hide) {
@ -287,6 +373,9 @@ display_field_do(struct dialog_data *dlg_data, struct widget_data *widget_data,
} else { } else {
struct box box; struct box box;
if (term->utf8) len = strlen_utf8(&text);
w = int_min(len, widget_data->box.width);
copy_box(&box, &widget_data->box); copy_box(&box, &widget_data->box);
box.width = w; box.width = w;
@ -295,8 +384,14 @@ display_field_do(struct dialog_data *dlg_data, struct widget_data *widget_data,
} }
if (sel) { if (sel) {
int x = widget_data->box.x + widget_data->info.field.cpos - widget_data->info.field.vpos; int x;
if (term->utf8) {
x = widget_data->box.x + len - left;
} else {
x = widget_data->box.x + widget_data->info.field.cpos - widget_data->info.field.vpos;
}
set_cursor(term, x, widget_data->box.y, 0); set_cursor(term, x, widget_data->box.y, 0);
set_window_ptr(dlg_data->win, widget_data->box.x, widget_data->box.y); set_window_ptr(dlg_data->win, widget_data->box.x, widget_data->box.y);
} }
@ -435,13 +530,33 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
break; break;
case ACT_EDIT_RIGHT: case ACT_EDIT_RIGHT:
if (widget_data->info.field.cpos < strlen(widget_data->cdata)) if (widget_data->info.field.cpos < strlen(widget_data->cdata)) {
widget_data->info.field.cpos++; if (term->utf8) {
unsigned char *next = widget_data->cdata + widget_data->info.field.cpos;
unsigned char *end = strchr(next, '\0');
utf_8_to_unicode(&next, end);
widget_data->info.field.cpos = (int)(next - widget_data->cdata);
} else
widget_data->info.field.cpos++;
}
goto display_field; goto display_field;
case ACT_EDIT_LEFT: case ACT_EDIT_LEFT:
if (widget_data->info.field.cpos > 0) if (widget_data->info.field.cpos > 0)
widget_data->info.field.cpos--; widget_data->info.field.cpos--;
if (widget_data->info.field.cpos && term->utf8) {
unsigned char *t = widget_data->cdata;
unsigned char *t2 = t;
int p = widget_data->info.field.cpos;
unsigned char tmp = t[p];
t[p] = '\0';
strlen_utf8(&t2);
t[p] = tmp;
widget_data->info.field.cpos = (int)(t2 - t);
}
goto display_field; goto display_field;
case ACT_EDIT_HOME: case ACT_EDIT_HOME:
@ -453,6 +568,19 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
goto display_field; goto display_field;
case ACT_EDIT_BACKSPACE: case ACT_EDIT_BACKSPACE:
if (widget_data->info.field.cpos && term->utf8) {
unsigned char *t = widget_data->cdata;
unsigned char *t2 = t;
int p = widget_data->info.field.cpos - 1;
unsigned char tmp = t[p];
t[p] = '\0';
strlen_utf8(&t2);
t[p] = tmp;
memmove(t2, &t[p + 1], strlen(&t[p + 1]) + 1);
widget_data->info.field.cpos = (int)(t2 - t);
goto display_field;
}
if (widget_data->info.field.cpos) { if (widget_data->info.field.cpos) {
memmove(widget_data->cdata + widget_data->info.field.cpos - 1, memmove(widget_data->cdata + widget_data->info.field.cpos - 1,
widget_data->cdata + widget_data->info.field.cpos, widget_data->cdata + widget_data->info.field.cpos,
@ -467,6 +595,15 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
if (widget_data->info.field.cpos >= cdata_len) goto display_field; if (widget_data->info.field.cpos >= cdata_len) goto display_field;
if (term->utf8) {
unsigned char *next = widget_data->cdata + widget_data->info.field.cpos;
unsigned char *dest = next;
unsigned char *end = strchr(next, '\0');
utf_8_to_unicode(&next, end);
memmove(dest, next, strlen(next) + 1);
goto display_field;
}
memmove(widget_data->cdata + widget_data->info.field.cpos, memmove(widget_data->cdata + widget_data->info.field.cpos,
widget_data->cdata + widget_data->info.field.cpos + 1, widget_data->cdata + widget_data->info.field.cpos + 1,
cdata_len - widget_data->info.field.cpos + 1); cdata_len - widget_data->info.field.cpos + 1);
@ -548,7 +685,20 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
memmove(text + 1, text, textlen + 1); memmove(text + 1, text, textlen + 1);
*text = get_kbd_key(ev); *text = get_kbd_key(ev);
if (term->utf8) {
static unsigned char buf[7];
unsigned char *t = buf;
static int i = 0;
unicode_val_T data;
buf[i++] = *text;
buf[i] = '\0';
data = utf_8_to_unicode(&t, buf + i);
if (i == 6) i = 0;
if (data == UCS_NO_CHAR)
return EVENT_PROCESSED;
else i = 0;
}
goto display_field; goto display_field;
} }
} }

View File

@ -346,10 +346,12 @@ draw_menu_left_text_hk(struct terminal *term, unsigned char *text,
struct color_pair *hk_color_sel = get_bfu_color(term, "menu.hotkey.selected"); struct color_pair *hk_color_sel = get_bfu_color(term, "menu.hotkey.selected");
enum screen_char_attr hk_attr = get_opt_bool("ui.dialogs.underline_hotkeys") enum screen_char_attr hk_attr = get_opt_bool("ui.dialogs.underline_hotkeys")
? SCREEN_ATTR_UNDERLINE : 0; ? SCREEN_ATTR_UNDERLINE : 0;
unsigned char *text2, *end;
unsigned char c; unsigned char c;
int xbase = x + L_TEXT_SPACE; int xbase = x + L_TEXT_SPACE;
int w = width - (L_TEXT_SPACE + R_TEXT_SPACE); int w = width - (L_TEXT_SPACE + R_TEXT_SPACE);
int hk_state = 0; int hk_state = 0;
#ifdef CONFIG_DEBUG #ifdef CONFIG_DEBUG
/* For redundant hotkeys highlighting. */ /* For redundant hotkeys highlighting. */
int double_hk = 0; int double_hk = 0;
@ -366,6 +368,7 @@ draw_menu_left_text_hk(struct terminal *term, unsigned char *text,
hk_color_sel = tmp; hk_color_sel = tmp;
} }
if (term->utf8) goto utf8;
for (x = 0; x - !!hk_state < w && (c = text[x]); x++) { for (x = 0; x - !!hk_state < w && (c = text[x]); x++) {
if (!hk_state && x == hotkey_pos - 1) { if (!hk_state && x == hotkey_pos - 1) {
hk_state = 1; hk_state = 1;
@ -384,6 +387,32 @@ draw_menu_left_text_hk(struct terminal *term, unsigned char *text,
draw_char(term, xbase + x - !!hk_state, y, c, 0, color); draw_char(term, xbase + x - !!hk_state, y, c, 0, color);
} }
} }
return;
utf8:
end = strchr(text, '\0');
text2 = text;
for (x = 0; x - !!hk_state < w && *text2; x++) {
unicode_val_T data;
data = utf_8_to_unicode(&text2, end);
if (!hk_state && (int)(text2 - text) == hotkey_pos) {
hk_state = 1;
continue;
}
if (hk_state == 1) {
#ifdef CONFIG_DEBUG
draw_char(term, xbase + x - 1, y, data, hk_attr,
(double_hk ? hk_color_sel : hk_color));
#else
draw_char(term, xbase + x - 1, y, data, hk_attr, hk_color);
#endif
hk_state = 2;
} else {
draw_char(term, xbase + x - !!hk_state, y, data, 0, color);
}
}
} }
static inline void static inline void

View File

@ -59,7 +59,6 @@ charset_list(struct terminal *term, void *xxx, void *ses_)
unsigned char *name = get_cp_name(i); unsigned char *name = get_cp_name(i);
if (!name) break; if (!name) break;
if (is_cp_special(i)) continue;
add_to_menu(&mi, name, NULL, ACT_MAIN_NONE, add_to_menu(&mi, name, NULL, ACT_MAIN_NONE,
display_codepage, get_cp_mime_name(i), 0); display_codepage, get_cp_mime_name(i), 0);

View File

@ -250,8 +250,11 @@ render_dom_line(struct dom_renderer *renderer, struct screen_char *template,
struct document *document = renderer->document; struct document *document = renderer->document;
struct conv_table *convert = renderer->convert_table; struct conv_table *convert = renderer->convert_table;
enum convert_string_mode mode = renderer->convert_mode; enum convert_string_mode mode = renderer->convert_mode;
int utf8 = document->options.utf8;
unsigned char *end, *text;
int x; int x;
assert(renderer && template && string && length); assert(renderer && template && string && length);
string = convert_string(convert, string, length, document->options.cp, string = convert_string(convert, string, length, document->options.cp,
@ -265,6 +268,7 @@ render_dom_line(struct dom_renderer *renderer, struct screen_char *template,
add_search_node(renderer, length); add_search_node(renderer, length);
if (utf8) goto utf_8;
for (x = 0; x < length; x++, renderer->canvas_x++) { for (x = 0; x < length; x++, renderer->canvas_x++) {
unsigned char data = string[x]; unsigned char data = string[x];
@ -293,7 +297,42 @@ render_dom_line(struct dom_renderer *renderer, struct screen_char *template,
copy_screen_chars(POS(renderer), template, 1); copy_screen_chars(POS(renderer), template, 1);
} }
goto end;
utf_8:
end = string + length;
for (text = string; text < end; renderer->canvas_x++) {
unsigned char data = *text;
unicode_val_T d2;
/* This is mostly to be able to break out so the indentation
* level won't get to high. */
switch (data) {
case ASCII_TAB:
{
int tab_width = 7 - (X(renderer) & 7);
int width = WIDTH(renderer, end - text + tab_width);
template->data = ' ';
if (!realloc_line(document, width, Y(renderer)))
break;
/* Only loop over the expanded tab chars and let the
* ``main loop'' add the actual tab char. */
for (; tab_width-- > 0; renderer->canvas_x++)
copy_screen_chars(POS(renderer), template, 1);
text++;
break;
}
default:
d2 = utf_8_to_unicode(&text, end);
if (d2 == UCS_NO_CHAR) text++;
template->data = (uint16_t)d2;
}
copy_screen_chars(POS(renderer), template, 1);
}
end:
mem_free(string); mem_free(string);
} }
@ -989,6 +1028,7 @@ render_dom_document(struct cache_entry *cached, struct document *document,
init_dom_renderer(&renderer, document, buffer, convert_table); init_dom_renderer(&renderer, document, buffer, convert_table);
document->bgcolor = document->options.default_bg; document->bgcolor = document->options.default_bg;
document->options.utf8 = is_cp_special(document->options.cp);
if (document->options.plain) if (document->options.plain)
parser_type = SGML_PARSER_STREAM; parser_type = SGML_PARSER_STREAM;

View File

@ -23,6 +23,7 @@
#include "document/refresh.h" #include "document/refresh.h"
#include "document/renderer.h" #include "document/renderer.h"
#include "intl/charsets.h" #include "intl/charsets.h"
#include "osdep/types.h"
#include "protocol/uri.h" #include "protocol/uri.h"
#include "session/session.h" #include "session/session.h"
#include "terminal/color.h" #include "terminal/color.h"
@ -404,7 +405,7 @@ get_format_screen_char(struct html_context *html_context,
/* First possibly do the format change and then find out what coordinates /* First possibly do the format change and then find out what coordinates
* to use since sub- or superscript might change them */ * to use since sub- or superscript might change them */
static inline void static inline int
set_hline(struct html_context *html_context, unsigned char *chars, int charslen, set_hline(struct html_context *html_context, unsigned char *chars, int charslen,
enum link_state link_state) enum link_state link_state)
{ {
@ -413,34 +414,83 @@ set_hline(struct html_context *html_context, unsigned char *chars, int charslen,
link_state); link_state);
int x = part->cx; int x = part->cx;
int y = part->cy; int y = part->cy;
int x2 = x;
int len = charslen;
int utf8 = html_context->options->utf8;
assert(part); assert(part);
if_assert_failed return; if_assert_failed return len;
assert(charslen >= 0);
if (realloc_spaces(part, x + charslen)) if (realloc_spaces(part, x + charslen))
return; return len;
if (part->document) { if (part->document) {
if (realloc_line(html_context, part->document, if (realloc_line(html_context, part->document,
Y(y), X(x) + charslen - 1)) Y(y), X(x) + charslen - 1))
return; return len;
if (utf8) {
unsigned char *end;
for (; charslen > 0; charslen--, x++, chars++) { for (end = chars + charslen; chars < end; x++) {
if (*chars == NBSP_CHAR) { if (*chars == NBSP_CHAR) {
schar->data = ' '; schar->data = ' ';
part->spaces[x] = html_context->options->wrap_nbsp; part->spaces[x] = html_context->options->wrap_nbsp;
} else { chars++;
part->spaces[x] = (*chars == ' '); } else {
schar->data = *chars; unicode_val_T data;
part->spaces[x] = (*chars == ' ');
data = utf_8_to_unicode(&chars, end);
if (data == UCS_NO_CHAR) {
/* HR */
unsigned char attr = schar->attr;
schar->data = *chars++;
schar->attr = SCREEN_ATTR_FRAME;
copy_screen_chars(&POS(x, y), schar, 1);
schar->attr = attr;
continue;
} else {
schar->data = (uint16_t)data;
}
}
copy_screen_chars(&POS(x, y), schar, 1);
}
} else {
for (; charslen > 0; charslen--, x++, chars++) {
if (*chars == NBSP_CHAR) {
schar->data = ' ';
part->spaces[x] = html_context->options->wrap_nbsp;
} else {
part->spaces[x] = (*chars == ' ');
schar->data = *chars;
}
copy_screen_chars(&POS(x, y), schar, 1);
} }
copy_screen_chars(&POS(x, y), schar, 1);
} }
len = x - x2;
} else { } else {
for (; charslen > 0; charslen--, x++, chars++) { if (utf8) {
part->spaces[x] = (*chars == ' '); unsigned char *end;
for (end = chars + charslen; chars < end; x++) {
unicode_val_T data;
part->spaces[x] = (*chars == ' ');
data = utf_8_to_unicode(&chars, end);
if (data == UCS_NO_CHAR) chars++;
}
len = x - x2;
} else {
for (; charslen > 0; charslen--, x++, chars++) {
part->spaces[x] = (*chars == ' ');
}
} }
} }
return len;
} }
static void static void
@ -1170,7 +1220,7 @@ done_link_state_info(void)
static inline void static inline void
process_link(struct html_context *html_context, enum link_state link_state, process_link(struct html_context *html_context, enum link_state link_state,
unsigned char *chars, int charslen) unsigned char *chars, int charslen, int utf8_len)
{ {
struct part *part = html_context->part; struct part *part = html_context->part;
struct link *link; struct link *link;
@ -1222,6 +1272,7 @@ process_link(struct html_context *html_context, enum link_state link_state,
if (x_offset) { if (x_offset) {
charslen -= x_offset; charslen -= x_offset;
chars += x_offset; chars += x_offset;
utf8_len -= x_offset;
} }
link = new_link(html_context, chars, charslen); link = new_link(html_context, chars, charslen);
@ -1236,14 +1287,14 @@ process_link(struct html_context *html_context, enum link_state link_state,
} }
/* Add new canvas positions to the link. */ /* Add new canvas positions to the link. */
if (realloc_points(link, link->npoints + charslen)) { if (realloc_points(link, link->npoints + utf8_len)) {
struct point *point = &link->points[link->npoints]; struct point *point = &link->points[link->npoints];
int x = X(part->cx) + x_offset; int x = X(part->cx) + x_offset;
int y = Y(part->cy); int y = Y(part->cy);
link->npoints += charslen; link->npoints += utf8_len;
for (; charslen > 0; charslen--, point++, x++) { for (; utf8_len > 0; utf8_len--, point++, x++) {
point->x = x; point->x = x;
point->y = y; point->y = y;
} }
@ -1295,6 +1346,7 @@ put_chars(struct html_context *html_context, unsigned char *chars, int charslen)
enum link_state link_state; enum link_state link_state;
int update_after_subscript = renderer_context.subscript; int update_after_subscript = renderer_context.subscript;
struct part *part; struct part *part;
int utf8_len;
assert(html_context); assert(html_context);
if_assert_failed return; if_assert_failed return;
@ -1353,9 +1405,7 @@ put_chars(struct html_context *html_context, unsigned char *chars, int charslen)
else if (html_context->options->links_numbering) else if (html_context->options->links_numbering)
put_link_number(html_context); put_link_number(html_context);
} }
utf8_len = set_hline(html_context, chars, charslen, link_state);
set_hline(html_context, chars, charslen, link_state);
if (link_state != LINK_STATE_NONE) { if (link_state != LINK_STATE_NONE) {
#define is_drawing_subs_or_sups() \ #define is_drawing_subs_or_sups() \
@ -1375,15 +1425,15 @@ put_chars(struct html_context *html_context, unsigned char *chars, int charslen)
} }
#undef is_drawing_subs_or_sups #undef is_drawing_subs_or_sups
process_link(html_context, link_state, chars, charslen,
process_link(html_context, link_state, chars, charslen); utf8_len);
} }
if (renderer_context.nowrap if (renderer_context.nowrap
&& part->cx + charslen > overlap(par_format)) && part->cx + utf8_len > overlap(par_format))
return; return;
part->cx += charslen; part->cx += utf8_len;
renderer_context.nobreak = 0; renderer_context.nobreak = 0;
if (!(html_context->options->wrap || html_is_preformatted())) { if (!(html_context->options->wrap || html_is_preformatted())) {
@ -1399,7 +1449,7 @@ put_chars(struct html_context *html_context, unsigned char *chars, int charslen)
} }
assert(charslen > 0); assert(charslen > 0);
part->xa += charslen; part->xa += utf8_len;
int_lower_bound(&part->max_width, part->xa int_lower_bound(&part->max_width, part->xa
+ par_format.leftmargin + par_format.rightmargin + par_format.leftmargin + par_format.rightmargin
- (chars[charslen - 1] == ' ' - (chars[charslen - 1] == ' '
@ -1963,6 +2013,7 @@ render_html_document(struct cache_entry *cached, struct document *document,
&document->cp, &document->cp,
&document->cp_status, &document->cp_status,
document->options.hard_assume); document->options.hard_assume);
html_context->options->utf8 = is_cp_special(document->options.cp);
if (title.length) { if (title.length) {
document->title = convert_string(renderer_context.convert_table, document->title = convert_string(renderer_context.convert_table,

View File

@ -71,6 +71,7 @@ struct document_options {
unsigned int plain:1; unsigned int plain:1;
unsigned int wrap:1; unsigned int wrap:1;
unsigned int utf8:1;
/* XXX: Everything past this comment is specialy handled by compare_opt() */ /* XXX: Everything past this comment is specialy handled by compare_opt() */
unsigned char *framename; unsigned char *framename;

View File

@ -234,8 +234,10 @@ add_document_line(struct plain_renderer *renderer,
struct screen_char *template = &renderer->template; struct screen_char *template = &renderer->template;
struct screen_char saved_renderer_template = *template; struct screen_char saved_renderer_template = *template;
struct screen_char *pos, *startpos; struct screen_char *pos, *startpos;
unsigned char *end, *text;
int lineno = renderer->lineno; int lineno = renderer->lineno;
int expanded = 0; int expanded = 0;
int utf8 = document->options.utf8;
int width = line_width; int width = line_width;
int line_pos; int line_pos;
@ -276,6 +278,7 @@ add_document_line(struct plain_renderer *renderer,
assert(expanded >= 0); assert(expanded >= 0);
if (utf8) goto utf_8;
startpos = pos = realloc_line(document, width + expanded, lineno); startpos = pos = realloc_line(document, width + expanded, lineno);
if (!pos) { if (!pos) {
mem_free(line); mem_free(line);
@ -401,7 +404,139 @@ add_document_line(struct plain_renderer *renderer,
*template = saved_renderer_template; *template = saved_renderer_template;
} }
} }
goto end;
utf_8:
end = line + width;
startpos = pos = realloc_line(document, width + expanded, lineno);
if (!pos) {
mem_free(line);
return 0;
}
expanded = 0;
for (text = line; text < end; ) {
unsigned char line_char = *text;
unsigned char next_char, prev_char;
line_pos = text - line;
prev_char = text > line ? *(text - 1) : '\0';
next_char = (text + 1 < end) ? *(text + 1) : '\0';
/* Do not expand tabs that precede back-spaces; this saves the
* back-space code some trouble. */
if (line_char == ASCII_TAB && next_char != ASCII_BS) {
int tab_width = 7 - ((line_pos + expanded) & 7);
expanded += tab_width;
template->data = ' ';
do
copy_screen_chars(pos++, template, 1);
while (tab_width--);
*template = saved_renderer_template;
text++;
} else if (line_char == ASCII_BS) {
if (!(expanded + line_pos)) {
/* We've backspaced to the start of the line */
if (expanded > 0)
expanded--; /* Don't count it */
continue;
}
if (pos > startpos)
pos--; /* Backspace */
/* Handle x^H_ as _^Hx, but prevent an infinite loop
* swapping two underscores. */
if (next_char == '_' && prev_char != '_') {
/* x^H_ becomes _^Hx */
if (text - 1 >= line)
*(text - 1) = next_char;
if (text + 1 < end)
*(text + 1) = prev_char;
/* Go back and reparse the swapped characters */
if (text - 2 >= line)
text -= 2;
continue;
}
if (expanded - 2 >= 0) {
/* Don't count the backspace character or the
* deleted character when returning the line's
* width or when expanding tabs. */
expanded -= 2;
}
if (pos->data == '_' && next_char == '_') {
/* Is _^H_ an underlined underscore
* or an emboldened underscore? */
if (expanded + line_pos >= 0
&& pos - 1 >= startpos
&& (pos - 1)->attr) {
/* There is some preceding text,
* and it has an attribute; copy it */
template->attr |= (pos - 1)->attr;
} else {
/* Default to bold; seems more useful
* than underlining the underscore */
template->attr |= SCREEN_ATTR_BOLD;
}
} else if (pos->data == '_') {
/* Underline _^Hx */
template->attr |= SCREEN_ATTR_UNDERLINE;
} else if (pos->data == next_char) {
/* Embolden x^Hx */
template->attr |= SCREEN_ATTR_BOLD;
}
/* Handle _^Hx^Hx as both bold and underlined */
if (template->attr)
template->attr |= pos->attr;
text++;
} else {
int added_chars = 0;
if (document->options.plain_display_links
&& isalpha(line_char) && isalpha(next_char)) {
/* We only want to check for a URI if there are
* at least two consecutive alphabetic
* characters, or if we are at the very start of
* the line. It improves performance a bit.
* --Zas */
added_chars = print_document_link(renderer,
lineno, line,
line_pos,
width,
expanded,
pos);
}
if (added_chars) {
text += added_chars;
pos += added_chars;
} else {
unicode_val_T data = utf_8_to_unicode(&text, end);
if (data == UCS_NO_CHAR) text++;
template->data = (uint16_t)data;
copy_screen_chars(pos++, template, 1);
/* Detect copy of nul chars to screen, this
* should not occur. --Zas */
assert(line_char);
}
*template = saved_renderer_template;
}
}
end:
mem_free(line); mem_free(line);
realloc_line(document, pos - startpos, lineno); realloc_line(document, pos - startpos, lineno);
@ -559,6 +694,7 @@ render_plain_document(struct cache_entry *cached, struct document *document,
document->bgcolor = document->options.default_bg; document->bgcolor = document->options.default_bg;
document->width = 0; document->width = 0;
document->options.utf8 = is_cp_special(document->options.cp);
/* Setup the style */ /* Setup the style */
init_template(&renderer.template, &document->options); init_template(&renderer.template, &document->options);

View File

@ -140,6 +140,12 @@ u2cp_(unicode_val_T u, int to, int no_nbsp_hack)
int s; int s;
if (u < 128) return strings[u]; if (u < 128) return strings[u];
to &= ~SYSTEM_CHARSET_FLAG;
if (codepages[to].table == table_utf_8)
return encode_utf_8(u);
/* To mark non breaking spaces, we use a special char NBSP_CHAR. */ /* To mark non breaking spaces, we use a special char NBSP_CHAR. */
if (u == 0xa0) return no_nbsp_hack ? " " : NBSP_CHAR_STRING; if (u == 0xa0) return no_nbsp_hack ? " " : NBSP_CHAR_STRING;
if (u == 0xad) return ""; if (u == 0xad) return "";
@ -151,7 +157,6 @@ u2cp_(unicode_val_T u, int to, int no_nbsp_hack)
return u2cp_(strange, to, no_nbsp_hack); return u2cp_(strange, to, no_nbsp_hack);
} }
to &= ~SYSTEM_CHARSET_FLAG;
for (j = 0; codepages[to].table[j].c; j++) for (j = 0; codepages[to].table[j].c; j++)
if (codepages[to].table[j].u == u) if (codepages[to].table[j].u == u)
@ -165,7 +170,7 @@ u2cp_(unicode_val_T u, int to, int no_nbsp_hack)
static unsigned char utf_buffer[7]; static unsigned char utf_buffer[7];
static unsigned char * inline unsigned char *
encode_utf_8(unicode_val_T u) encode_utf_8(unicode_val_T u)
{ {
memset(utf_buffer, 0, 7); memset(utf_buffer, 0, 7);
@ -200,6 +205,91 @@ encode_utf_8(unicode_val_T u)
return utf_buffer; return utf_buffer;
} }
inline int
strlen_utf8(unsigned char **str)
{
unsigned char *s = *str;
unsigned char *end = strchr(s, '\0');
int x;
int len;
for (x = 0;; x++, s += len) {
if (*s < 0x80) len = 1;
else if (*s < 0xe0) len = 2;
else if (*s < 0xf0) len = 3;
else if (*s < 0xf8) len = 4;
else if (*s < 0xfc) len = 5;
else len = 6;
if (s + len > end) break;
}
*str = s;
return x;
}
inline unicode_val_T
utf_8_to_unicode(unsigned char **string, unsigned char *end)
{
unsigned char *str = *string;
unicode_val_T u;
int length;
if (str[0] < 0x80)
length = 1;
else if (str[0] < 0xe0)
length = 2;
else if (str[0] < 0xf0)
length = 3;
else if (str[0] < 0xf8)
length = 4;
else if (str[0] < 0xfc)
length = 5;
else
length = 6;
if (str + length > end) {
return UCS_NO_CHAR;
}
switch (length) {
case 1:
u = str[0];
break;
case 2:
u = (str[0] & 0x1f) << 6;
u += (str[1] & 0x3f);
break;
case 3:
u = (str[0] & 0x0f) << 12;
u += ((str[1] & 0x3f) << 6);
u += (str[2] & 0x3f);
break;
case 4:
u = (str[0] & 0x0f) << 18;
u += ((str[1] & 0x3f) << 12);
u += ((str[2] & 0x3f) << 6);
u += (str[3] & 0x3f);
break;
case 5:
u = (str[0] & 0x0f) << 24;
u += ((str[1] & 0x3f) << 18);
u += ((str[2] & 0x3f) << 12);
u += ((str[3] & 0x3f) << 6);
u += (str[4] & 0x3f);
break;
case 6:
default:
u = (str[0] & 0x01) << 30;
u += ((str[1] & 0x3f) << 24);
u += ((str[2] & 0x3f) << 18);
u += ((str[3] & 0x3f) << 12);
u += ((str[4] & 0x3f) << 6);
u += (str[5] & 0x3f);
break;
}
*string = str + length;
return u > 0xffff ? '*' : u;
}
/* This slow and ugly code is used by the terminal utf_8_io */ /* This slow and ugly code is used by the terminal utf_8_io */
unsigned char * unsigned char *
cp2utf_8(int from, int c) cp2utf_8(int from, int c)
@ -430,11 +520,16 @@ get_entity_string(const unsigned char *str, const int strlen, int encoding)
static struct entity_cache entity_cache[ENTITY_CACHE_MAXLEN][ENTITY_CACHE_SIZE]; static struct entity_cache entity_cache[ENTITY_CACHE_MAXLEN][ENTITY_CACHE_SIZE];
static unsigned int nb_entity_cache[ENTITY_CACHE_MAXLEN]; static unsigned int nb_entity_cache[ENTITY_CACHE_MAXLEN];
static int first_time = 1; static int first_time = 1;
unsigned int slen; unsigned int slen = 0;
unsigned char *result = NULL; unsigned char *result = NULL;
if (strlen <= 0) return NULL; if (strlen <= 0) return NULL;
/* TODO: caching UTF-8 */
encoding &= ~SYSTEM_CHARSET_FLAG;
if (codepages[encoding].table == table_utf_8)
goto skip;
if (first_time) { if (first_time) {
memset(&nb_entity_cache, 0, ENTITY_CACHE_MAXLEN * sizeof(unsigned int)); memset(&nb_entity_cache, 0, ENTITY_CACHE_MAXLEN * sizeof(unsigned int));
first_time = 0; first_time = 0;
@ -488,7 +583,7 @@ get_entity_string(const unsigned char *str, const int strlen, int encoding)
fprintf(stderr, "miss\n"); fprintf(stderr, "miss\n");
#endif #endif
} }
skip:
if (*str == '#') { /* Numeric entity. */ if (*str == '#') { /* Numeric entity. */
int l = (int) strlen; int l = (int) strlen;
unsigned char *st = (unsigned char *) str; unsigned char *st = (unsigned char *) str;
@ -540,6 +635,9 @@ get_entity_string(const unsigned char *str, const int strlen, int encoding)
if (element) result = u2cp(element->c, encoding); if (element) result = u2cp(element->c, encoding);
} }
if (codepages[encoding].table == table_utf_8) {
return result;
}
end: end:
/* Take care of potential buffer overflow. */ /* Take care of potential buffer overflow. */
if (strlen < sizeof(entity_cache[slen][0].str)) { if (strlen < sizeof(entity_cache[slen][0].str)) {

View File

@ -53,6 +53,10 @@ unsigned char *get_cp_name(int);
unsigned char *get_cp_mime_name(int); unsigned char *get_cp_mime_name(int);
int is_cp_special(int); int is_cp_special(int);
void free_conv_table(void); void free_conv_table(void);
inline unsigned char *encode_utf_8(unicode_val_T);
inline int strlen_utf8(unsigned char **);
inline unicode_val_T utf_8_to_unicode(unsigned char **, unsigned char *);
unsigned char *cp2utf_8(int, int); unsigned char *cp2utf_8(int, int);
unsigned char *u2cp_(unicode_val_T, int, int no_nbsp_hack); unsigned char *u2cp_(unicode_val_T, int, int no_nbsp_hack);

View File

@ -7,6 +7,7 @@
#include "elinks.h" #include "elinks.h"
#include "config/options.h" #include "config/options.h"
#include "intl/charsets.h"
#include "terminal/color.h" #include "terminal/color.h"
#include "terminal/draw.h" #include "terminal/draw.h"
#include "terminal/screen.h" #include "terminal/screen.h"
@ -102,7 +103,7 @@ draw_char_color(struct terminal *term, int x, int y, struct color_pair *color)
} }
void void
draw_char_data(struct terminal *term, int x, int y, unsigned char data) draw_char_data(struct terminal *term, int x, int y, uint16_t data)
{ {
struct screen_char *screen_char = get_char(term, x, y); struct screen_char *screen_char = get_char(term, x, y);
@ -200,7 +201,7 @@ draw_border(struct terminal *term, struct box *box,
void void
draw_char(struct terminal *term, int x, int y, draw_char(struct terminal *term, int x, int y,
unsigned char data, enum screen_char_attr attr, uint16_t data, enum screen_char_attr attr,
struct color_pair *color) struct color_pair *color)
{ {
struct screen_char *screen_char = get_char(term, x, y); struct screen_char *screen_char = get_char(term, x, y);
@ -277,6 +278,41 @@ draw_shadow(struct terminal *term, struct box *box,
draw_box(term, &dbox, ' ', 0, color); draw_box(term, &dbox, ' ', 0, color);
} }
static void
draw_text_utf8(struct terminal *term, int x, int y,
unsigned char *text, int length,
enum screen_char_attr attr, struct color_pair *color)
{
struct screen_char *start, *pos;
unsigned char *end = text + length;
unicode_val_T data;
assert(text && length >= 0);
if_assert_failed return;
if (length <= 0) return;
if (x >= term->width) return;
data = utf_8_to_unicode(&text, end);
if (data == UCS_NO_CHAR) return;
start = get_char(term, x++, y);
start->data = (uint16_t)data;
if (color) {
start->attr = attr;
set_term_color(start, color, 0,
get_opt_int_tree(term->spec, "colors"));
}
for (pos = start + 1; x < term->width; x++, pos++) {
data = utf_8_to_unicode(&text, end);
if (data == UCS_NO_CHAR) break;
if (color) copy_screen_chars(pos, start, 1);
pos->data = (uint16_t)data;
}
set_screen_dirty(term->screen, y, y);
}
void void
draw_text(struct terminal *term, int x, int y, draw_text(struct terminal *term, int x, int y,
unsigned char *text, int length, unsigned char *text, int length,
@ -288,6 +324,11 @@ draw_text(struct terminal *term, int x, int y,
assert(text && length >= 0); assert(text && length >= 0);
if_assert_failed return; if_assert_failed return;
if (term->utf8) {
draw_text_utf8(term, x, y, text, length, attr, color);
return;
}
if (length <= 0) return; if (length <= 0) return;
pos = get_char(term, x, y); pos = get_char(term, x, y);
if (!pos) return; if (!pos) return;

View File

@ -19,7 +19,7 @@ enum screen_char_attr {
/* One position in the terminal screen's image. */ /* One position in the terminal screen's image. */
struct screen_char { struct screen_char {
/* Contains either character value or frame data. */ /* Contains either character value or frame data. */
unsigned char data; uint16_t data;
/* Attributes are screen_char_attr bits. */ /* Attributes are screen_char_attr bits. */
unsigned char attr; unsigned char attr;
@ -202,7 +202,7 @@ void draw_char_color(struct terminal *term, int x, int y,
struct color_pair *color); struct color_pair *color);
/* Sets the data of a screen position. */ /* Sets the data of a screen position. */
void draw_char_data(struct terminal *term, int x, int y, unsigned char data); void draw_char_data(struct terminal *term, int x, int y, uint16_t data);
/* Sets the data to @border and of a screen position. */ /* Sets the data to @border and of a screen position. */
void draw_border_char(struct terminal *term, int x, int y, void draw_border_char(struct terminal *term, int x, int y,
@ -214,7 +214,7 @@ void draw_border_cross(struct terminal *, int x, int y,
/* Draws a char. */ /* Draws a char. */
void draw_char(struct terminal *term, int x, int y, void draw_char(struct terminal *term, int x, int y,
unsigned char data, enum screen_char_attr attr, uint16_t data, enum screen_char_attr attr,
struct color_pair *color); struct color_pair *color);
/* Draws area defined by @box using the same colors and attributes. */ /* Draws area defined by @box using the same colors and attributes. */

View File

@ -245,7 +245,6 @@ handle_interlink_event(struct terminal *term, struct term_event *ev)
case EVENT_KBD: case EVENT_KBD:
{ {
int utf8_io = -1;
int key = get_kbd_key(ev); int key = get_kbd_key(ev);
reset_timer(); reset_timer();
@ -260,9 +259,7 @@ handle_interlink_event(struct terminal *term, struct term_event *ev)
} }
if (interlink->utf_8.len) { if (interlink->utf_8.len) {
utf8_io = get_opt_bool_tree(term->spec, "utf_8_io"); if ((key & 0xC0) == 0x80 && term->utf8) {
if ((key & 0xC0) == 0x80 && utf8_io) {
interlink->utf_8.ucs <<= 6; interlink->utf_8.ucs <<= 6;
interlink->utf_8.ucs |= key & 0x3F; interlink->utf_8.ucs |= key & 0x3F;
if (! --interlink->utf_8.len) { if (! --interlink->utf_8.len) {
@ -280,15 +277,14 @@ handle_interlink_event(struct terminal *term, struct term_event *ev)
} }
} }
if (key < 0x80 || key > 0xFF if (key < 0x80 || key > 0xFF || !term->utf8) {
|| (utf8_io == -1
? !get_opt_bool_tree(term->spec, "utf_8_io")
: !utf8_io)) {
term_send_event(term, ev); term_send_event(term, ev);
break; break;
} else if ((key & 0xC0) == 0xC0 && (key & 0xFE) != 0xFE) { }
else if ((key & 0xC0) == 0xC0 && (key & 0xFE) != 0xFE) {
unsigned int mask, cov = 0x80; unsigned int mask, cov = 0x80;
int len = 0; int len = 0;

View File

@ -30,6 +30,7 @@
unsigned char frame_dumb[48] = " ||||++||++++++--|-+||++--|-+----++++++++ "; unsigned char frame_dumb[48] = " ||||++||++++++--|-+||++--|-+----++++++++ ";
static unsigned char frame_vt100[48] = "aaaxuuukkuxkjjjkmvwtqnttmlvwtqnvvwwmmllnnjla "; static unsigned char frame_vt100[48] = "aaaxuuukkuxkjjjkmvwtqnttmlvwtqnvvwwmmllnnjla ";
#if 0
/* For UTF8 I/O */ /* For UTF8 I/O */
static unsigned char frame_vt100_u[48] = { static unsigned char frame_vt100_u[48] = {
177, 177, 177, 179, 180, 180, 180, 191, 177, 177, 177, 179, 180, 180, 180, 191,
@ -39,6 +40,7 @@ static unsigned char frame_vt100_u[48] = {
193, 194, 194, 192, 192, 218, 218, 197, 193, 194, 194, 192, 192, 218, 218, 197,
197, 217, 218, 177, 32, 32, 32, 32 197, 217, 218, 177, 32, 32, 32, 32
}; };
#endif
static unsigned char frame_freebsd[48] = { static unsigned char frame_freebsd[48] = {
130, 138, 128, 153, 150, 150, 150, 140, 130, 138, 128, 153, 150, 150, 150, 140,
@ -78,6 +80,11 @@ static struct string m11_hack_frame_seqs[] = {
/* begin border: */ TERM_STRING("\033[11m"), /* begin border: */ TERM_STRING("\033[11m"),
}; };
static struct string utf8_linux_frame_seqs[] = {
/* end border: */ TERM_STRING("\033[10m\033%G"),
/* begin border: */ TERM_STRING("\033%@\033[11m"),
};
static struct string vt100_frame_seqs[] = { static struct string vt100_frame_seqs[] = {
/* end border: */ TERM_STRING("\x0f"), /* end border: */ TERM_STRING("\x0f"),
/* begin border: */ TERM_STRING("\x0e"), /* begin border: */ TERM_STRING("\x0e"),
@ -99,11 +106,6 @@ struct screen_driver {
* uniquely identify the screen_driver. */ * uniquely identify the screen_driver. */
enum term_mode_type type; enum term_mode_type type;
/* Charsets when doing UTF8 I/O. */
/* [0] is the common charset and [1] is the frame charset.
* Test wether to use UTF8 I/O using the use_utf8_io() macro. */
int charsets[2];
/* The frame translation table. May be NULL. */ /* The frame translation table. May be NULL. */
unsigned char *frame; unsigned char *frame;
@ -119,6 +121,9 @@ struct screen_driver {
/* These are directly derived from the terminal options. */ /* These are directly derived from the terminal options. */
unsigned int transparent:1; unsigned int transparent:1;
/* UTF-8 I/O */
unsigned int utf8:1;
/* The terminal._template_ name. */ /* The terminal._template_ name. */
unsigned char name[1]; /* XXX: Keep last! */ unsigned char name[1]; /* XXX: Keep last! */
}; };
@ -126,56 +131,56 @@ struct screen_driver {
static struct screen_driver dumb_screen_driver = { static struct screen_driver dumb_screen_driver = {
NULL_LIST_HEAD, NULL_LIST_HEAD,
/* type: */ TERM_DUMB, /* type: */ TERM_DUMB,
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
/* frame: */ frame_dumb, /* frame: */ frame_dumb,
/* frame_seqs: */ NULL, /* frame_seqs: */ NULL,
/* underline: */ underline_seqs, /* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16, /* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1, /* transparent: */ 1,
/* utf-8: */ 0,
}; };
static struct screen_driver vt100_screen_driver = { static struct screen_driver vt100_screen_driver = {
NULL_LIST_HEAD, NULL_LIST_HEAD,
/* type: */ TERM_VT100, /* type: */ TERM_VT100,
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
/* frame: */ frame_vt100, /* frame: */ frame_vt100,
/* frame_seqs: */ vt100_frame_seqs, /* frame_seqs: */ vt100_frame_seqs,
/* underline: */ underline_seqs, /* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16, /* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1, /* transparent: */ 1,
/* utf-8: */ 0,
}; };
static struct screen_driver linux_screen_driver = { static struct screen_driver linux_screen_driver = {
NULL_LIST_HEAD, NULL_LIST_HEAD,
/* type: */ TERM_LINUX, /* type: */ TERM_LINUX,
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
/* frame: */ NULL, /* No restrict_852 */ /* frame: */ NULL, /* No restrict_852 */
/* frame_seqs: */ NULL, /* No m11_hack */ /* frame_seqs: */ NULL, /* No m11_hack */
/* underline: */ underline_seqs, /* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16, /* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1, /* transparent: */ 1,
/* utf-8: */ 0,
}; };
static struct screen_driver koi8_screen_driver = { static struct screen_driver koi8_screen_driver = {
NULL_LIST_HEAD, NULL_LIST_HEAD,
/* type: */ TERM_KOI8, /* type: */ TERM_KOI8,
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
/* frame: */ frame_koi, /* frame: */ frame_koi,
/* frame_seqs: */ NULL, /* frame_seqs: */ NULL,
/* underline: */ underline_seqs, /* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16, /* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1, /* transparent: */ 1,
/* utf-8: */ 0,
}; };
static struct screen_driver freebsd_screen_driver = { static struct screen_driver freebsd_screen_driver = {
NULL_LIST_HEAD, NULL_LIST_HEAD,
/* type: */ TERM_FREEBSD, /* type: */ TERM_FREEBSD,
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
/* frame: */ frame_freebsd, /* frame: */ frame_freebsd,
/* frame_seqs: */ NULL, /* No m11_hack */ /* frame_seqs: */ NULL, /* No m11_hack */
/* underline: */ underline_seqs, /* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16, /* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1, /* transparent: */ 1,
/* utf-8: */ 0,
}; };
/* XXX: Keep in sync with enum term_mode_type. */ /* XXX: Keep in sync with enum term_mode_type. */
@ -187,13 +192,14 @@ static struct screen_driver *screen_drivers[] = {
/* TERM_FREEBSD: */ &freebsd_screen_driver, /* TERM_FREEBSD: */ &freebsd_screen_driver,
}; };
#define use_utf8_io(driver) ((driver)->utf8)
static INIT_LIST_HEAD(active_screen_drivers); static INIT_LIST_HEAD(active_screen_drivers);
static void static void
update_screen_driver(struct screen_driver *driver, struct option *term_spec) update_screen_driver(struct screen_driver *driver, struct option *term_spec)
{ {
int utf8_io = get_opt_bool_tree(term_spec, "utf_8_io"); driver->utf8 = get_opt_bool_tree(term_spec, "utf_8_io");
driver->color_mode = get_opt_int_tree(term_spec, "colors"); driver->color_mode = get_opt_int_tree(term_spec, "colors");
driver->transparent = get_opt_bool_tree(term_spec, "transparency"); driver->transparent = get_opt_bool_tree(term_spec, "transparency");
@ -204,44 +210,22 @@ update_screen_driver(struct screen_driver *driver, struct option *term_spec)
driver->underline = NULL; driver->underline = NULL;
} }
if (utf8_io) { if (driver->type == TERM_LINUX) {
driver->charsets[0] = get_opt_codepage_tree(term_spec, "charset"); if (get_opt_bool_tree(term_spec, "restrict_852"))
if (driver->type == TERM_LINUX) { driver->frame = frame_restrict;
if (get_opt_bool_tree(term_spec, "restrict_852"))
driver->frame = frame_restrict;
driver->charsets[1] = get_cp_index("cp437"); if (get_opt_bool_tree(term_spec, "m11_hack"))
driver->frame_seqs = m11_hack_frame_seqs;
} else if (driver->type == TERM_FREEBSD) { if (driver->utf8)
driver->charsets[1] = get_cp_index("cp437"); driver->frame_seqs = utf8_linux_frame_seqs;
} else if (driver->type == TERM_VT100) { } else if (driver->type == TERM_FREEBSD) {
driver->frame = frame_vt100_u; if (get_opt_bool_tree(term_spec, "m11_hack"))
driver->charsets[1] = get_cp_index("cp437"); driver->frame_seqs = m11_hack_frame_seqs;
} else if (driver->type == TERM_KOI8) { } else if (driver->type == TERM_VT100) {
driver->charsets[1] = get_cp_index("koi8-r"); driver->frame = frame_vt100;
} else {
driver->charsets[1] = driver->charsets[0];
}
} else {
driver->charsets[0] = -1;
if (driver->type == TERM_LINUX) {
if (get_opt_bool_tree(term_spec, "restrict_852"))
driver->frame = frame_restrict;
if (get_opt_bool_tree(term_spec, "m11_hack"))
driver->frame_seqs = m11_hack_frame_seqs;
} else if (driver->type == TERM_FREEBSD) {
if (get_opt_bool_tree(term_spec, "m11_hack"))
driver->frame_seqs = m11_hack_frame_seqs;
} else if (driver->type == TERM_VT100) {
driver->frame = frame_vt100;
}
} }
} }
@ -281,6 +265,8 @@ add_screen_driver(enum term_mode_type type, struct terminal *term, int env_len)
term->spec->change_hook = screen_driver_change_hook; term->spec->change_hook = screen_driver_change_hook;
term->utf8 = use_utf8_io(driver);
return driver; return driver;
} }
@ -299,6 +285,7 @@ get_screen_driver(struct terminal *term)
/* Some simple probably useless MRU ;) */ /* Some simple probably useless MRU ;) */
move_to_top_of_list(active_screen_drivers, driver); move_to_top_of_list(active_screen_drivers, driver);
term->utf8 = use_utf8_io(driver);
return driver; return driver;
} }
@ -364,11 +351,10 @@ struct screen_state {
#define compare_bg_color(a, b) (TERM_COLOR_BACKGROUND(a) == TERM_COLOR_BACKGROUND(b)) #define compare_bg_color(a, b) (TERM_COLOR_BACKGROUND(a) == TERM_COLOR_BACKGROUND(b))
#define compare_fg_color(a, b) (TERM_COLOR_FOREGROUND(a) == TERM_COLOR_FOREGROUND(b)) #define compare_fg_color(a, b) (TERM_COLOR_FOREGROUND(a) == TERM_COLOR_FOREGROUND(b))
#define use_utf8_io(driver) ((driver)->charsets[0] != -1)
static inline void static inline void
add_char_data(struct string *screen, struct screen_driver *driver, add_char_data(struct string *screen, struct screen_driver *driver,
unsigned char data, unsigned char border) unicode_val_T data, unsigned char border)
{ {
if (!isscreensafe(data)) { if (!isscreensafe(data)) {
add_char_to_string(screen, ' '); add_char_to_string(screen, ' ');
@ -379,13 +365,15 @@ add_char_data(struct string *screen, struct screen_driver *driver,
data = driver->frame[data - 176]; data = driver->frame[data - 176];
if (use_utf8_io(driver)) { if (use_utf8_io(driver)) {
int charset = driver->charsets[!!border]; if (border)
add_char_to_string(screen, (unsigned char)data);
add_to_string(screen, cp2utf_8(charset, data)); else
if (data != UCS_NO_CHAR)
add_to_string(screen, encode_utf_8(data));
return; return;
} }
add_char_to_string(screen, data); add_char_to_string(screen, (unsigned char)data);
} }
/* Time critical section. */ /* Time critical section. */

View File

@ -110,6 +110,9 @@ struct terminal {
* work and even maintaining these structures ;-). */ * work and even maintaining these structures ;-). */
unsigned int master:1; unsigned int master:1;
/* Indicates whether UTF-8 I/O is used */
unsigned int utf8:1;
/* The current tab number. */ /* The current tab number. */
int current_tab; int current_tab;

View File

@ -26,6 +26,7 @@
#include "document/options.h" #include "document/options.h"
#include "document/renderer.h" #include "document/renderer.h"
#include "document/view.h" #include "document/view.h"
#include "intl/charsets.h"
#include "intl/gettext/libintl.h" #include "intl/gettext/libintl.h"
#include "main/select.h" #include "main/select.h"
#include "main/main.h" #include "main/main.h"
@ -322,6 +323,9 @@ add_document_to_string(struct string *string, struct document *document)
assert(string && document); assert(string && document);
if_assert_failed return NULL; if_assert_failed return NULL;
if (is_cp_special(document->options.cp))
goto utf_8;
for (y = 0; y < document->height; y++) { for (y = 0; y < document->height; y++) {
int white = 0; int white = 0;
int x; int x;
@ -354,7 +358,43 @@ add_document_to_string(struct string *string, struct document *document)
add_char_to_string(string, '\n'); add_char_to_string(string, '\n');
} }
goto end;
utf_8:
for (y = 0; y < document->height; y++) {
struct screen_char *pos = document->data[y].chars;
int white = 0;
int x;
for (x = 0; x < document->data[y].length; x++) {
uint16_t data = pos->data;
unsigned int frame = (pos->attr & SCREEN_ATTR_FRAME);
if (!isscreensafe(data)) {
white++;
continue;
} else if (frame && data >= 176 && data < 224) {
data = frame_dumb[data - 176];
if (data <= ' ') {
/* Count spaces. */
white++;
} else {
/* Print spaces if any. */
if (white) {
add_xchar_to_string(string, ' ', white);
white = 0;
}
if (frame)
add_char_to_string(string, data);
else
add_to_string(string, encode_utf_8(data));
}
}
}
add_char_to_string(string, '\n');
}
end:
return string; return string;
} }
@ -382,6 +422,9 @@ dump_to_file(struct document *document, int fd)
if (!buf) return -1; if (!buf) return -1;
if (is_cp_special(document->options.cp))
goto utf_8;
for (y = 0; y < document->height; y++) { for (y = 0; y < document->height; y++) {
int white = 0; int white = 0;
int x; int x;
@ -418,13 +461,60 @@ dump_to_file(struct document *document, int fd)
if (write_char('\n', fd, buf, &bptr)) if (write_char('\n', fd, buf, &bptr))
goto fail; goto fail;
} }
goto ref;
utf_8:
for (y = 0; y < document->height; y++) {
int white = 0;
int x;
for (x = 0; x < document->data[y].length; x++) {
uint16_t c;
unsigned char attr = document->data[y].chars[x].attr;
c = document->data[y].chars[x].data;
if ((attr & SCREEN_ATTR_FRAME)
&& c >= 176 && c < 224)
c = frame_dumb[c - 176];
else {
unsigned char *utf8_buf = encode_utf_8(c);
while (*utf8_buf) {
if (write_char(*utf8_buf++,
fd, buf, &bptr)) goto fail;
}
continue;
}
if (c <= ' ') {
/* Count spaces. */
white++;
continue;
}
/* Print spaces if any. */
while (white) {
if (write_char(' ', fd, buf, &bptr))
goto fail;
white--;
}
/* Print normal char. */
if (write_char(c, fd, buf, &bptr))
goto fail;
}
/* Print end of line. */
if (write_char('\n', fd, buf, &bptr))
goto fail;
}
if (hard_write(fd, buf, bptr) != bptr) { if (hard_write(fd, buf, bptr) != bptr) {
fail: fail:
mem_free(buf); mem_free(buf);
return -1; return -1;
} }
ref:
if (document->nlinks && get_opt_bool("document.dump.references")) { if (document->nlinks && get_opt_bool("document.dump.references")) {
int x; int x;
unsigned char *header = "\nReferences\n\n Visible links\n"; unsigned char *header = "\nReferences\n\n Visible links\n";

View File

@ -158,16 +158,22 @@ init_form_state(struct form_control *fc, struct form_state *fs)
mem_free_set(&fs->value, NULL); mem_free_set(&fs->value, NULL);
switch (fc->type) { switch (fc->type) {
unsigned char *text;
case FC_TEXT: case FC_TEXT:
case FC_PASSWORD: case FC_PASSWORD:
case FC_TEXTAREA: case FC_TEXTAREA:
fs->value = stracpy(fc->default_value); fs->value = stracpy(fc->default_value);
fs->state = strlen(fc->default_value); fs->state = strlen(fc->default_value);
text = fs->value;
if (fc->type != FC_TEXTAREA)
fs->utf8_pos = strlen_utf8(&text);
fs->vpos = 0; fs->vpos = 0;
break; break;
case FC_FILE: case FC_FILE:
fs->value = stracpy(""); fs->value = stracpy("");
fs->state = 0; fs->state = 0;
fs->utf8_pos = 0;
fs->vpos = 0; fs->vpos = 0;
break; break;
case FC_SELECT: case FC_SELECT:
@ -330,12 +336,14 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
dy = box->y - vs->y; dy = box->y - vs->y;
switch (fc->type) { switch (fc->type) {
unsigned char *s; unsigned char *s;
unsigned char *text, *end;
int len; int len;
int i, x, y; int i, x, y;
case FC_TEXT: case FC_TEXT:
case FC_PASSWORD: case FC_PASSWORD:
case FC_FILE: case FC_FILE:
if (term->utf8) goto utf_8;
int_bounds(&fs->vpos, fs->state - fc->size + 1, fs->state); int_bounds(&fs->vpos, fs->state - fc->size + 1, fs->state);
if (!link->npoints) break; if (!link->npoints) break;
@ -360,6 +368,36 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
draw_char_data(term, x, y, data); draw_char_data(term, x, y, data);
} }
break; break;
utf_8:
text = fs->value;
end = strchr(text, '\0');
int_bounds(&fs->vpos, fs->utf8_pos - fc->size + 1, fs->utf8_pos);
if (!link->npoints) break;
y = link->points[0].y + dy;
if (!row_is_in_box(box, y))
break;
for (i = 0; i < fs->vpos; i++) {
utf_8_to_unicode(&text, end);
}
s = text;
len = strlen_utf8(&s);
x = link->points[0].x + dx;
for (i = 0; i < fc->size; i++, x++) {
uint16_t data;
if (!col_is_in_box(box, x)) continue;
if (fs->value && i >= -fs->vpos && i < len)
data = fc->type != FC_PASSWORD
? utf_8_to_unicode(&text, end) : '*';
else
data = '_';
draw_char_data(term, x, y, data);
}
break;
case FC_TEXTAREA: case FC_TEXTAREA:
draw_textarea(term, fs, doc_view, link); draw_textarea(term, fs, doc_view, link);
break; break;
@ -378,6 +416,7 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
else else
/* XXX: when can this happen? --pasky */ /* XXX: when can this happen? --pasky */
s = ""; s = "";
if (term->utf8) goto utf_8_select;
len = s ? strlen(s) : 0; len = s ? strlen(s) : 0;
for (i = 0; i < link->npoints; i++) { for (i = 0; i < link->npoints; i++) {
x = link->points[i].x + dx; x = link->points[i].x + dx;
@ -386,6 +425,18 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
draw_char_data(term, x, y, i < len ? s[i] : '_'); draw_char_data(term, x, y, i < len ? s[i] : '_');
} }
break; break;
utf_8_select:
text = s;
end = strchr(s, '\0');
len = strlen_utf8(&text);
for (i = 0; i < link->npoints; i++) {
x = link->points[i].x + dx;
y = link->points[i].y + dy;
if (is_in_box(box, x, y))
draw_char_data(term, x, y, i < len
? utf_8_to_unicode(&s, end) : '_');
}
break;
case FC_SUBMIT: case FC_SUBMIT:
case FC_IMAGE: case FC_IMAGE:
case FC_RESET: case FC_RESET:
@ -1195,6 +1246,7 @@ field_op(struct session *ses, struct document_view *doc_view,
unsigned char *text; unsigned char *text;
int length; int length;
enum frame_event_status status = FRAME_EVENT_REFRESH; enum frame_event_status status = FRAME_EVENT_REFRESH;
int utf8 = ses->tab->term->utf8;
assert(ses && doc_view && link && ev); assert(ses && doc_view && link && ev);
if_assert_failed return FRAME_EVENT_OK; if_assert_failed return FRAME_EVENT_OK;
@ -1214,49 +1266,79 @@ field_op(struct session *ses, struct document_view *doc_view,
switch (action_id) { switch (action_id) {
case ACT_EDIT_LEFT: case ACT_EDIT_LEFT:
fs->state = int_max(fs->state - 1, 0); if (utf8) {
unsigned char *text = fs->value;
unsigned char *end = fs->value + fs->state - 1;
int old = fs->state;
while (utf_8_to_unicode(&text, end) != UCS_NO_CHAR);
fs->state = (int)(text - fs->value);
if (old != fs->state) fs->utf8_pos--;
} else
fs->state = int_max(fs->state - 1, 0);
break; break;
case ACT_EDIT_RIGHT: case ACT_EDIT_RIGHT:
fs->state = int_min(fs->state + 1, strlen(fs->value)); if (utf8) {
unsigned char *text = fs->value + fs->state;
unsigned char *end = strchr(text, '\0');
int old = fs->state;
utf_8_to_unicode(&text, end);
fs->state = (int)(text - fs->value);
if (old != fs->state) fs->utf8_pos++;
} else
fs->state = int_min(fs->state + 1, strlen(fs->value));
break; break;
case ACT_EDIT_HOME: case ACT_EDIT_HOME:
if (fc->type == FC_TEXTAREA) { if (fc->type == FC_TEXTAREA) {
status = textarea_op_home(fs, fc); status = textarea_op_home(fs, fc, utf8);
} else { } else {
fs->state = 0; fs->state = 0;
fs->utf8_pos = 0;
} }
break; break;
case ACT_EDIT_UP: case ACT_EDIT_UP:
if (fc->type != FC_TEXTAREA) if (fc->type != FC_TEXTAREA)
status = FRAME_EVENT_IGNORED; status = FRAME_EVENT_IGNORED;
else else
status = textarea_op_up(fs, fc); status = textarea_op_up(fs, fc, utf8);
break; break;
case ACT_EDIT_DOWN: case ACT_EDIT_DOWN:
if (fc->type != FC_TEXTAREA) if (fc->type != FC_TEXTAREA)
status = FRAME_EVENT_IGNORED; status = FRAME_EVENT_IGNORED;
else else
status = textarea_op_down(fs, fc); status = textarea_op_down(fs, fc, utf8);
break; break;
case ACT_EDIT_END: case ACT_EDIT_END:
if (fc->type == FC_TEXTAREA) { if (fc->type == FC_TEXTAREA) {
status = textarea_op_end(fs, fc); status = textarea_op_end(fs, fc, utf8);
} else { } else {
fs->state = strlen(fs->value); fs->state = strlen(fs->value);
if (utf8) {
unsigned char *text = fs->value;
fs->utf8_pos = strlen_utf8(&text);
}
} }
break; break;
case ACT_EDIT_BEGINNING_OF_BUFFER: case ACT_EDIT_BEGINNING_OF_BUFFER:
if (fc->type == FC_TEXTAREA) { if (fc->type == FC_TEXTAREA) {
status = textarea_op_bob(fs, fc); status = textarea_op_bob(fs, fc, utf8);
} else { } else {
fs->state = 0; fs->state = 0;
fs->utf8_pos = 0;
} }
break; break;
case ACT_EDIT_END_OF_BUFFER: case ACT_EDIT_END_OF_BUFFER:
if (fc->type == FC_TEXTAREA) { if (fc->type == FC_TEXTAREA) {
status = textarea_op_eob(fs, fc); status = textarea_op_eob(fs, fc, utf8);
} else { } else {
fs->state = strlen(fs->value); fs->state = strlen(fs->value);
if (utf8) {
unsigned char *text = fs->value;
fs->utf8_pos = strlen_utf8(&text);
}
} }
break; break;
case ACT_EDIT_OPEN_EXTERNAL: case ACT_EDIT_OPEN_EXTERNAL:
@ -1274,6 +1356,7 @@ field_op(struct session *ses, struct document_view *doc_view,
if (!form_field_is_readonly(fc)) if (!form_field_is_readonly(fc))
fs->value[0] = 0; fs->value[0] = 0;
fs->state = 0; fs->state = 0;
fs->utf8_pos = 0;
break; break;
case ACT_EDIT_PASTE_CLIPBOARD: case ACT_EDIT_PASTE_CLIPBOARD:
if (form_field_is_readonly(fc)) break; if (form_field_is_readonly(fc)) break;
@ -1289,13 +1372,19 @@ field_op(struct session *ses, struct document_view *doc_view,
fs->value = v; fs->value = v;
memmove(v, text, length + 1); memmove(v, text, length + 1);
fs->state = strlen(fs->value); fs->state = strlen(fs->value);
if (utf8 && fc->type != FC_TEXTAREA) {
unsigned char *text = fs->value;
fs->utf8_pos = strlen_utf8(&text);
}
} }
} }
mem_free(text); mem_free(text);
break; break;
case ACT_EDIT_ENTER: case ACT_EDIT_ENTER:
if (fc->type == FC_TEXTAREA) { if (fc->type == FC_TEXTAREA) {
status = textarea_op_enter(fs, fc); status = textarea_op_enter(fs, fc, utf8);
break; break;
} }
@ -1320,7 +1409,19 @@ field_op(struct session *ses, struct document_view *doc_view,
status = FRAME_EVENT_OK; status = FRAME_EVENT_OK;
break; break;
} }
if (utf8) {
int i;
unsigned char *text = fs->value;
unsigned char *end = fs->value + fs->state;
for (i = 0; i < fs->utf8_pos - 1; i++)
utf_8_to_unicode(&text, end);
length = strlen(end) + 1;
memmove(text, end, length);
fs->state = (int)(text - fs->value);
fs->utf8_pos--;
break;
}
length = strlen(fs->value + fs->state) + 1; length = strlen(fs->value + fs->state) + 1;
text = fs->value + fs->state; text = fs->value + fs->state;
@ -1338,7 +1439,18 @@ field_op(struct session *ses, struct document_view *doc_view,
status = FRAME_EVENT_OK; status = FRAME_EVENT_OK;
break; break;
} }
if (utf8) {
unsigned char *end = fs->value + length;
unsigned char *text = fs->value + fs->state;
unsigned char *old = text;
utf_8_to_unicode(&text, end);
if (old != text) {
memmove(old, text,
(int)(end - text) + 1);
}
break;
}
text = fs->value + fs->state; text = fs->value + fs->state;
memmove(text, text + 1, length - fs->state); memmove(text, text + 1, length - fs->state);
@ -1368,6 +1480,11 @@ field_op(struct session *ses, struct document_view *doc_view,
memmove(text, fs->value + fs->state, length); memmove(text, fs->value + fs->state, length);
fs->state = (int) (text - fs->value); fs->state = (int) (text - fs->value);
if (utf8 && fc->type != FC_TEXTAREA) {
unsigned char *text = fs->value;
fs->utf8_pos = strlen_utf8(&text);
}
break; break;
case ACT_EDIT_KILL_TO_EOL: case ACT_EDIT_KILL_TO_EOL:
if (form_field_is_readonly(fc)) { if (form_field_is_readonly(fc)) {
@ -1421,13 +1538,41 @@ field_op(struct session *ses, struct document_view *doc_view,
} }
if (form_field_is_readonly(fc) if (form_field_is_readonly(fc)
|| strlen(fs->value) >= fc->maxlength || strlen(fs->value) >= fc->maxlength) {
|| !insert_in_string(&fs->value, fs->state, "?", 1)) {
status = FRAME_EVENT_OK; status = FRAME_EVENT_OK;
break; break;
} }
if (utf8) {
static unsigned char buf[7];
static int i = 0;
unicode_val_T data;
unsigned char *t;
fs->value[fs->state++] = get_kbd_key(ev); t = buf;
buf[i++] = get_kbd_key(ev);
buf[i] = 0;
data = utf_8_to_unicode(&t, buf + i);
if (data != UCS_NO_CHAR) {
if (!insert_in_string(&fs->value, fs->state, buf, i)) {
i = 0;
return FRAME_EVENT_OK;
}
fs->state += i;
fs->utf8_pos++;
i = 0;
break;
}
if (i == 6) {
i = 0;
return FRAME_EVENT_OK;
} else {
return FRAME_EVENT_OK;
}
} else {
if (!insert_in_string(&fs->value, fs->state, "?", 1))
return FRAME_EVENT_OK;
fs->value[fs->state++] = get_kbd_key(ev);
}
break; break;
} }

View File

@ -39,6 +39,7 @@ struct form_state {
unsigned char *value; unsigned char *value;
int state; int state;
int utf8_pos;
int vpos; int vpos;
int vypos; int vypos;

View File

@ -112,6 +112,7 @@ get_link_cursor_offset(struct document_view *doc_view, struct link *link)
{ {
struct form_control *fc; struct form_control *fc;
struct form_state *fs; struct form_state *fs;
int utf8 = doc_view->document->options.utf8;
switch (link->type) { switch (link->type) {
case LINK_CHECKBOX: case LINK_CHECKBOX:
@ -123,12 +124,15 @@ get_link_cursor_offset(struct document_view *doc_view, struct link *link)
case LINK_FIELD: case LINK_FIELD:
fc = get_link_form_control(link); fc = get_link_form_control(link);
fs = find_form_state(doc_view, fc); fs = find_form_state(doc_view, fc);
return fs ? fs->state - fs->vpos : 0; if (utf8) {
return fs ? fs->utf8_pos - fs->vpos : 0;
} else
return fs ? fs->state - fs->vpos : 0;
case LINK_AREA: case LINK_AREA:
fc = get_link_form_control(link); fc = get_link_form_control(link);
fs = find_form_state(doc_view, fc); fs = find_form_state(doc_view, fc);
return fs ? area_cursor(fc, fs) : 0; return fs ? area_cursor(fc, fs, utf8) : 0;
case LINK_HYPERTEXT: case LINK_HYPERTEXT:
case LINK_MAP: case LINK_MAP:

View File

@ -138,7 +138,7 @@ get_textarea_line_number(struct line_info *line, int cursor_position)
/* Fixes up the vpos and vypos members of the form_state. Returns the /* Fixes up the vpos and vypos members of the form_state. Returns the
* logical position in the textarea view. */ * logical position in the textarea view. */
int int
area_cursor(struct form_control *fc, struct form_state *fs) area_cursor(struct form_control *fc, struct form_state *fs, int utf8)
{ {
struct line_info *line; struct line_info *line;
int x, y; int x, y;
@ -155,7 +155,15 @@ area_cursor(struct form_control *fc, struct form_state *fs)
return 0; return 0;
} }
x = fs->state - line[y].start; if (utf8) {
unsigned char *text = fs->value + line[y].start;
unsigned char tmp = fs->value[fs->state];
fs->value[fs->state] = '\0';
x = strlen_utf8(&text);
fs->value[fs->state] = tmp;
} else
x = fs->state - line[y].start;
mem_free(line); mem_free(line);
@ -170,8 +178,8 @@ area_cursor(struct form_control *fc, struct form_state *fs)
return y * fc->cols + x; return y * fc->cols + x;
} }
void static void
draw_textarea(struct terminal *term, struct form_state *fs, draw_textarea_utf8(struct terminal *term, struct form_state *fs,
struct document_view *doc_view, struct link *link) struct document_view *doc_view, struct link *link)
{ {
struct line_info *line, *linex; struct line_info *line, *linex;
@ -192,7 +200,91 @@ draw_textarea(struct terminal *term, struct form_state *fs,
vy = doc_view->vs->y; vy = doc_view->vs->y;
if (!link->npoints) return; if (!link->npoints) return;
area_cursor(fc, fs); area_cursor(fc, fs, 1);
linex = format_text(fs->value, fc->cols, fc->wrap, 0);
if (!linex) return;
line = linex;
sl = fs->vypos;
while (line->start != -1 && sl) sl--, line++;
x = link->points[0].x + box->x - vx;
y = link->points[0].y + box->y - vy;
ye = y + fc->rows;
for (; line->start != -1 && y < ye; line++, y++) {
int i;
unsigned char *text, *end;
text = fs->value + line->start;
end = fs->value + line->end;
for (i = 0; i < fs->vpos; i++)
utf_8_to_unicode(&text, end);
if (!row_is_in_box(box, y)) continue;
for (i = 0; i < fc->cols; i++) {
uint16_t data;
int xi = x + i;
if (!col_is_in_box(box, xi))
continue;
if (i >= -fs->vpos
&& text < end)
data = utf_8_to_unicode(&text, end);
else
data = '_';
draw_char_data(term, xi, y, data);
}
}
for (; y < ye; y++) {
int i;
if (!row_is_in_box(box, y)) continue;
for (i = 0; i < fc->cols; i++) {
int xi = x + i;
if (col_is_in_box(box, xi))
draw_char_data(term, xi, y, '_');
}
}
mem_free(linex);
}
void
draw_textarea(struct terminal *term, struct form_state *fs,
struct document_view *doc_view, struct link *link)
{
struct line_info *line, *linex;
struct form_control *fc;
struct box *box;
int vx, vy;
int sl, ye;
int x, y;
assert(term && doc_view && doc_view->document && doc_view->vs && link);
if_assert_failed return;
if (term->utf8) {
draw_textarea_utf8(term, fs, doc_view, link);
return;
}
fc = get_link_form_control(link);
assertm(fc, "link %d has no form control", (int) (link - doc_view->document->links));
if_assert_failed return;
box = &doc_view->box;
vx = doc_view->vs->x;
vy = doc_view->vs->y;
if (!link->npoints) return;
area_cursor(fc, fs, 0);
linex = format_text(fs->value, fc->cols, fc->wrap, 0); linex = format_text(fs->value, fc->cols, fc->wrap, 0);
if (!linex) return; if (!linex) return;
line = linex; line = linex;
@ -448,8 +540,8 @@ menu_textarea_edit(struct terminal *term, void *xxx, void *ses_)
} }
static enum frame_event_status static enum frame_event_status
textarea_op(struct form_state *fs, struct form_control *fc, textarea_op(struct form_state *fs, struct form_control *fc, int utf8,
int (*do_op)(struct form_state *, struct line_info *, int)) int (*do_op)(struct form_state *, struct line_info *, int, int))
{ {
struct line_info *line; struct line_info *line;
int current, state; int current, state;
@ -462,47 +554,87 @@ textarea_op(struct form_state *fs, struct form_control *fc,
current = get_textarea_line_number(line, fs->state); current = get_textarea_line_number(line, fs->state);
state = fs->state; state = fs->state;
if (do_op(fs, line, current)) { if (do_op(fs, line, current, utf8)) {
mem_free(line); mem_free(line);
return FRAME_EVENT_IGNORED; return FRAME_EVENT_IGNORED;
} }
mem_free(line); mem_free(line);
return fs->state == state ? FRAME_EVENT_OK : FRAME_EVENT_REFRESH; return fs->state == state ? FRAME_EVENT_OK : FRAME_EVENT_REFRESH;
} }
static int static int
do_op_home(struct form_state *fs, struct line_info *line, int current) x_pos(struct form_state *fs, struct line_info *line, int current)
{
unsigned char *text = fs->value + line[current].start;
unsigned char tmp = fs->value[fs->state];
int len;
fs->value[fs->state] = '\0';
len = strlen_utf8(&text);
fs->value[fs->state] = tmp;
return len;
}
static void
new_pos(struct form_state *fs, struct line_info *line, int current, int len)
{
unsigned char *text = fs->value + line[current].start;
unsigned char *end = fs->value + line[current].end;
int i;
for (i = 0; i < len; i++) {
unicode_val_T data = utf_8_to_unicode(&text, end);
if (data == UCS_NO_CHAR) break;
}
fs->state = (int)(text - fs->value);
}
static int
do_op_home(struct form_state *fs, struct line_info *line, int current, int utf8)
{ {
if (current != -1) fs->state = line[current].start; if (current != -1) fs->state = line[current].start;
return 0; return 0;
} }
static int static int
do_op_up(struct form_state *fs, struct line_info *line, int current) do_op_up(struct form_state *fs, struct line_info *line, int current, int utf8)
{ {
if (current == -1) return 0; if (current == -1) return 0;
if (!current) return 1; if (!current) return 1;
if (utf8) {
int len = x_pos(fs, line, current);
new_pos(fs, line, current - 1, len);
return 0;
}
fs->state -= line[current].start - line[current-1].start; fs->state -= line[current].start - line[current-1].start;
int_upper_bound(&fs->state, line[current-1].end); int_upper_bound(&fs->state, line[current-1].end);
return 0; return 0;
} }
static int static int
do_op_down(struct form_state *fs, struct line_info *line, int current) do_op_down(struct form_state *fs, struct line_info *line, int current, int utf8)
{ {
if (current == -1) return 0; if (current == -1) return 0;
if (line[current+1].start == -1) return 1; if (line[current+1].start == -1) return 1;
if (utf8) {
int len = x_pos(fs, line, current);
new_pos(fs, line, current + 1, len);
return 0;
}
fs->state += line[current+1].start - line[current].start; fs->state += line[current+1].start - line[current].start;
int_upper_bound(&fs->state, line[current+1].end); int_upper_bound(&fs->state, line[current+1].end);
return 0; return 0;
} }
static int static int
do_op_end(struct form_state *fs, struct line_info *line, int current) do_op_end(struct form_state *fs, struct line_info *line, int current, int utf8)
{ {
if (current == -1) { if (current == -1) {
fs->state = strlen(fs->value); fs->state = strlen(fs->value);
@ -517,7 +649,7 @@ do_op_end(struct form_state *fs, struct line_info *line, int current)
} }
static int static int
do_op_bob(struct form_state *fs, struct line_info *line, int current) do_op_bob(struct form_state *fs, struct line_info *line, int current, int utf8)
{ {
if (current == -1) return 0; if (current == -1) return 0;
@ -527,7 +659,7 @@ do_op_bob(struct form_state *fs, struct line_info *line, int current)
} }
static int static int
do_op_eob(struct form_state *fs, struct line_info *line, int current) do_op_eob(struct form_state *fs, struct line_info *line, int current, int utf8)
{ {
if (current == -1) { if (current == -1) {
fs->state = strlen(fs->value); fs->state = strlen(fs->value);
@ -544,35 +676,35 @@ do_op_eob(struct form_state *fs, struct line_info *line, int current)
} }
enum frame_event_status enum frame_event_status
textarea_op_home(struct form_state *fs, struct form_control *fc) textarea_op_home(struct form_state *fs, struct form_control *fc, int utf8)
{ {
return textarea_op(fs, fc, do_op_home); return textarea_op(fs, fc, utf8, do_op_home);
} }
enum frame_event_status enum frame_event_status
textarea_op_up(struct form_state *fs, struct form_control *fc) textarea_op_up(struct form_state *fs, struct form_control *fc, int utf8)
{ {
return textarea_op(fs, fc, do_op_up); return textarea_op(fs, fc, utf8, do_op_up);
} }
enum frame_event_status enum frame_event_status
textarea_op_down(struct form_state *fs, struct form_control *fc) textarea_op_down(struct form_state *fs, struct form_control *fc, int utf8)
{ {
return textarea_op(fs, fc, do_op_down); return textarea_op(fs, fc, utf8, do_op_down);
} }
enum frame_event_status enum frame_event_status
textarea_op_end(struct form_state *fs, struct form_control *fc) textarea_op_end(struct form_state *fs, struct form_control *fc, int utf8)
{ {
return textarea_op(fs, fc, do_op_end); return textarea_op(fs, fc, utf8, do_op_end);
} }
/* Set the form state so the cursor is on the first line of the buffer. /* Set the form state so the cursor is on the first line of the buffer.
* Preserve the column if possible. */ * Preserve the column if possible. */
enum frame_event_status enum frame_event_status
textarea_op_bob(struct form_state *fs, struct form_control *fc) textarea_op_bob(struct form_state *fs, struct form_control *fc, int utf8)
{ {
return textarea_op(fs, fc, do_op_bob); return textarea_op(fs, fc, utf8, do_op_bob);
} }
/* Set the form state so the cursor is on the last line of the buffer. Preserve /* Set the form state so the cursor is on the last line of the buffer. Preserve
@ -580,13 +712,13 @@ textarea_op_bob(struct form_state *fs, struct form_control *fc)
* then shifting the state by the delta of both lines start position bounding * then shifting the state by the delta of both lines start position bounding
* the whole thing to the end of the last line. */ * the whole thing to the end of the last line. */
enum frame_event_status enum frame_event_status
textarea_op_eob(struct form_state *fs, struct form_control *fc) textarea_op_eob(struct form_state *fs, struct form_control *fc, int utf8)
{ {
return textarea_op(fs, fc, do_op_eob); return textarea_op(fs, fc, utf8, do_op_eob);
} }
enum frame_event_status enum frame_event_status
textarea_op_enter(struct form_state *fs, struct form_control *fc) textarea_op_enter(struct form_state *fs, struct form_control *fc, int utf8)
{ {
assert(fs && fs->value && fc); assert(fs && fs->value && fc);
if_assert_failed return FRAME_EVENT_OK; if_assert_failed return FRAME_EVENT_OK;
@ -607,6 +739,7 @@ set_textarea(struct document_view *doc_view, int direction)
struct form_control *fc; struct form_control *fc;
struct form_state *fs; struct form_state *fs;
struct link *link; struct link *link;
int utf8 = doc_view->document->options.utf8;
assert(doc_view && doc_view->vs && doc_view->document); assert(doc_view && doc_view->vs && doc_view->document);
assert(direction == 1 || direction == -1); assert(direction == 1 || direction == -1);
@ -628,7 +761,7 @@ set_textarea(struct document_view *doc_view, int direction)
/* Depending on which way we entered the textarea move cursor so that /* Depending on which way we entered the textarea move cursor so that
* it is available at end or start. */ * it is available at end or start. */
if (direction == 1) if (direction == 1)
textarea_op_eob(fs, fc); textarea_op_eob(fs, fc, utf8);
else else
textarea_op_bob(fs, fc); textarea_op_bob(fs, fc, utf8);
} }

View File

@ -13,7 +13,7 @@ struct link;
struct session; struct session;
struct terminal; struct terminal;
int area_cursor(struct form_control *fc, struct form_state *fs); int area_cursor(struct form_control *fc, struct form_state *fs, int utf8);
void draw_textarea(struct terminal *term, struct form_state *fs, struct document_view *doc_view, struct link *link); void draw_textarea(struct terminal *term, struct form_state *fs, struct document_view *doc_view, struct link *link);
unsigned char *encode_textarea(struct submitted_value *sv); unsigned char *encode_textarea(struct submitted_value *sv);
@ -21,13 +21,13 @@ extern int textarea_editor;
void textarea_edit(int, struct terminal *, struct form_state *, struct document_view *, struct link *); void textarea_edit(int, struct terminal *, struct form_state *, struct document_view *, struct link *);
void menu_textarea_edit(struct terminal *term, void *xxx, void *ses_); void menu_textarea_edit(struct terminal *term, void *xxx, void *ses_);
enum frame_event_status textarea_op_home(struct form_state *fs, struct form_control *fc); enum frame_event_status textarea_op_home(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_up(struct form_state *fs, struct form_control *fc); enum frame_event_status textarea_op_up(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_down(struct form_state *fs, struct form_control *fc); enum frame_event_status textarea_op_down(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_end(struct form_state *fs, struct form_control *fc); enum frame_event_status textarea_op_end(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_bob(struct form_state *fs, struct form_control *fc); enum frame_event_status textarea_op_bob(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_eob(struct form_state *fs, struct form_control *fc); enum frame_event_status textarea_op_eob(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_enter(struct form_state *fs, struct form_control *fc); enum frame_event_status textarea_op_enter(struct form_state *fs, struct form_control *fc, int utf8);
void set_textarea(struct document_view *doc_view, int direction); void set_textarea(struct document_view *doc_view, int direction);