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:
parent
3251644dcf
commit
44a1aa9c87
@ -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")
|
||||
? 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) {
|
||||
int right = widget_data->widget->info.button.truetextlen - hk_pos - 1;
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "bfu/dialog.h"
|
||||
#include "config/kbdbind.h"
|
||||
#include "config/options.h"
|
||||
#include "intl/charsets.h"
|
||||
#include "intl/gettext/libintl.h"
|
||||
#include "terminal/draw.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");
|
||||
if (title_color && box.width > 2) {
|
||||
unsigned char *title = dlg_data->dlg->title;
|
||||
int titlelen = int_min(box.width - 2, strlen(title));
|
||||
int x = (box.width - titlelen) / 2 + box.x;
|
||||
unsigned char *t2 = title;
|
||||
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;
|
||||
|
||||
draw_text(term, x - 1, y, " ", 1, 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "bfu/msgbox.h"
|
||||
#include "bfu/text.h"
|
||||
#include "config/kbdbind.h"
|
||||
#include "intl/charsets.h"
|
||||
#include "intl/gettext/libintl.h"
|
||||
#include "osdep/osdep.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;
|
||||
}
|
||||
|
||||
#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
|
||||
dlg_format_field(struct terminal *term,
|
||||
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 color_pair *color;
|
||||
int sel = is_selected_widget(dlg_data, widget_data);
|
||||
int len = 0, left = 0;
|
||||
|
||||
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);
|
||||
int_lower_bound(&widget_data->info.field.vpos, 0);
|
||||
}
|
||||
|
||||
color = get_bfu_color(term, "dialog.field");
|
||||
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");
|
||||
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);
|
||||
|
||||
if (!hide) {
|
||||
@ -287,6 +373,9 @@ display_field_do(struct dialog_data *dlg_data, struct widget_data *widget_data,
|
||||
} else {
|
||||
struct box box;
|
||||
|
||||
if (term->utf8) len = strlen_utf8(&text);
|
||||
w = int_min(len, widget_data->box.width);
|
||||
|
||||
copy_box(&box, &widget_data->box);
|
||||
box.width = w;
|
||||
|
||||
@ -295,8 +384,14 @@ display_field_do(struct dialog_data *dlg_data, struct widget_data *widget_data,
|
||||
}
|
||||
|
||||
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_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;
|
||||
|
||||
case ACT_EDIT_RIGHT:
|
||||
if (widget_data->info.field.cpos < strlen(widget_data->cdata))
|
||||
if (widget_data->info.field.cpos < strlen(widget_data->cdata)) {
|
||||
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;
|
||||
|
||||
case ACT_EDIT_LEFT:
|
||||
if (widget_data->info.field.cpos > 0)
|
||||
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;
|
||||
|
||||
case ACT_EDIT_HOME:
|
||||
@ -453,6 +568,19 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
|
||||
goto display_field;
|
||||
|
||||
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) {
|
||||
memmove(widget_data->cdata + widget_data->info.field.cpos - 1,
|
||||
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 (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,
|
||||
widget_data->cdata + 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);
|
||||
*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;
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
enum screen_char_attr hk_attr = get_opt_bool("ui.dialogs.underline_hotkeys")
|
||||
? SCREEN_ATTR_UNDERLINE : 0;
|
||||
unsigned char *text2, *end;
|
||||
unsigned char c;
|
||||
int xbase = x + L_TEXT_SPACE;
|
||||
int w = width - (L_TEXT_SPACE + R_TEXT_SPACE);
|
||||
int hk_state = 0;
|
||||
|
||||
#ifdef CONFIG_DEBUG
|
||||
/* For redundant hotkeys highlighting. */
|
||||
int double_hk = 0;
|
||||
@ -366,6 +368,7 @@ draw_menu_left_text_hk(struct terminal *term, unsigned char *text,
|
||||
hk_color_sel = tmp;
|
||||
}
|
||||
|
||||
if (term->utf8) goto utf8;
|
||||
for (x = 0; x - !!hk_state < w && (c = text[x]); x++) {
|
||||
if (!hk_state && x == hotkey_pos - 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);
|
||||
}
|
||||
}
|
||||
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
|
||||
|
@ -59,7 +59,6 @@ charset_list(struct terminal *term, void *xxx, void *ses_)
|
||||
unsigned char *name = get_cp_name(i);
|
||||
|
||||
if (!name) break;
|
||||
if (is_cp_special(i)) continue;
|
||||
|
||||
add_to_menu(&mi, name, NULL, ACT_MAIN_NONE,
|
||||
display_codepage, get_cp_mime_name(i), 0);
|
||||
|
@ -250,8 +250,11 @@ render_dom_line(struct dom_renderer *renderer, struct screen_char *template,
|
||||
struct document *document = renderer->document;
|
||||
struct conv_table *convert = renderer->convert_table;
|
||||
enum convert_string_mode mode = renderer->convert_mode;
|
||||
int utf8 = document->options.utf8;
|
||||
unsigned char *end, *text;
|
||||
int x;
|
||||
|
||||
|
||||
assert(renderer && template && string && length);
|
||||
|
||||
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);
|
||||
|
||||
if (utf8) goto utf_8;
|
||||
for (x = 0; x < length; x++, renderer->canvas_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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@ -989,6 +1028,7 @@ render_dom_document(struct cache_entry *cached, struct document *document,
|
||||
init_dom_renderer(&renderer, document, buffer, convert_table);
|
||||
|
||||
document->bgcolor = document->options.default_bg;
|
||||
document->options.utf8 = is_cp_special(document->options.cp);
|
||||
|
||||
if (document->options.plain)
|
||||
parser_type = SGML_PARSER_STREAM;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "document/refresh.h"
|
||||
#include "document/renderer.h"
|
||||
#include "intl/charsets.h"
|
||||
#include "osdep/types.h"
|
||||
#include "protocol/uri.h"
|
||||
#include "session/session.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
|
||||
* 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,
|
||||
enum link_state link_state)
|
||||
{
|
||||
@ -413,18 +414,51 @@ set_hline(struct html_context *html_context, unsigned char *chars, int charslen,
|
||||
link_state);
|
||||
int x = part->cx;
|
||||
int y = part->cy;
|
||||
int x2 = x;
|
||||
int len = charslen;
|
||||
int utf8 = html_context->options->utf8;
|
||||
|
||||
assert(part);
|
||||
if_assert_failed return;
|
||||
if_assert_failed return len;
|
||||
|
||||
assert(charslen >= 0);
|
||||
|
||||
if (realloc_spaces(part, x + charslen))
|
||||
return;
|
||||
return len;
|
||||
|
||||
if (part->document) {
|
||||
if (realloc_line(html_context, part->document,
|
||||
Y(y), X(x) + charslen - 1))
|
||||
return;
|
||||
return len;
|
||||
if (utf8) {
|
||||
unsigned char *end;
|
||||
|
||||
for (end = chars + charslen; chars < end; x++) {
|
||||
if (*chars == NBSP_CHAR) {
|
||||
schar->data = ' ';
|
||||
part->spaces[x] = html_context->options->wrap_nbsp;
|
||||
chars++;
|
||||
} else {
|
||||
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 = ' ';
|
||||
@ -433,15 +467,31 @@ set_hline(struct html_context *html_context, unsigned char *chars, int charslen,
|
||||
part->spaces[x] = (*chars == ' ');
|
||||
schar->data = *chars;
|
||||
}
|
||||
|
||||
copy_screen_chars(&POS(x, y), schar, 1);
|
||||
}
|
||||
|
||||
}
|
||||
len = x - x2;
|
||||
} else {
|
||||
if (utf8) {
|
||||
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
|
||||
move_links(struct html_context *html_context, int xf, int yf, int xt, int yt)
|
||||
@ -1170,7 +1220,7 @@ done_link_state_info(void)
|
||||
|
||||
static inline void
|
||||
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 link *link;
|
||||
@ -1222,6 +1272,7 @@ process_link(struct html_context *html_context, enum link_state link_state,
|
||||
if (x_offset) {
|
||||
charslen -= x_offset;
|
||||
chars += x_offset;
|
||||
utf8_len -= x_offset;
|
||||
}
|
||||
|
||||
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. */
|
||||
if (realloc_points(link, link->npoints + charslen)) {
|
||||
if (realloc_points(link, link->npoints + utf8_len)) {
|
||||
struct point *point = &link->points[link->npoints];
|
||||
int x = X(part->cx) + x_offset;
|
||||
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->y = y;
|
||||
}
|
||||
@ -1295,6 +1346,7 @@ put_chars(struct html_context *html_context, unsigned char *chars, int charslen)
|
||||
enum link_state link_state;
|
||||
int update_after_subscript = renderer_context.subscript;
|
||||
struct part *part;
|
||||
int utf8_len;
|
||||
|
||||
assert(html_context);
|
||||
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)
|
||||
put_link_number(html_context);
|
||||
}
|
||||
|
||||
set_hline(html_context, chars, charslen, link_state);
|
||||
|
||||
utf8_len = set_hline(html_context, chars, charslen, link_state);
|
||||
if (link_state != LINK_STATE_NONE) {
|
||||
|
||||
#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
|
||||
|
||||
process_link(html_context, link_state, chars, charslen);
|
||||
process_link(html_context, link_state, chars, charslen,
|
||||
utf8_len);
|
||||
}
|
||||
|
||||
if (renderer_context.nowrap
|
||||
&& part->cx + charslen > overlap(par_format))
|
||||
&& part->cx + utf8_len > overlap(par_format))
|
||||
return;
|
||||
|
||||
part->cx += charslen;
|
||||
part->cx += utf8_len;
|
||||
renderer_context.nobreak = 0;
|
||||
|
||||
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);
|
||||
part->xa += charslen;
|
||||
part->xa += utf8_len;
|
||||
int_lower_bound(&part->max_width, part->xa
|
||||
+ par_format.leftmargin + par_format.rightmargin
|
||||
- (chars[charslen - 1] == ' '
|
||||
@ -1963,6 +2013,7 @@ render_html_document(struct cache_entry *cached, struct document *document,
|
||||
&document->cp,
|
||||
&document->cp_status,
|
||||
document->options.hard_assume);
|
||||
html_context->options->utf8 = is_cp_special(document->options.cp);
|
||||
|
||||
if (title.length) {
|
||||
document->title = convert_string(renderer_context.convert_table,
|
||||
|
@ -71,6 +71,7 @@ struct document_options {
|
||||
|
||||
unsigned int plain:1;
|
||||
unsigned int wrap:1;
|
||||
unsigned int utf8:1;
|
||||
|
||||
/* XXX: Everything past this comment is specialy handled by compare_opt() */
|
||||
unsigned char *framename;
|
||||
|
@ -234,8 +234,10 @@ add_document_line(struct plain_renderer *renderer,
|
||||
struct screen_char *template = &renderer->template;
|
||||
struct screen_char saved_renderer_template = *template;
|
||||
struct screen_char *pos, *startpos;
|
||||
unsigned char *end, *text;
|
||||
int lineno = renderer->lineno;
|
||||
int expanded = 0;
|
||||
int utf8 = document->options.utf8;
|
||||
int width = line_width;
|
||||
int line_pos;
|
||||
|
||||
@ -276,6 +278,7 @@ add_document_line(struct plain_renderer *renderer,
|
||||
|
||||
assert(expanded >= 0);
|
||||
|
||||
if (utf8) goto utf_8;
|
||||
startpos = pos = realloc_line(document, width + expanded, lineno);
|
||||
if (!pos) {
|
||||
mem_free(line);
|
||||
@ -401,7 +404,139 @@ add_document_line(struct plain_renderer *renderer,
|
||||
*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);
|
||||
|
||||
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->width = 0;
|
||||
document->options.utf8 = is_cp_special(document->options.cp);
|
||||
|
||||
/* Setup the style */
|
||||
init_template(&renderer.template, &document->options);
|
||||
|
@ -140,6 +140,12 @@ u2cp_(unicode_val_T u, int to, int no_nbsp_hack)
|
||||
int s;
|
||||
|
||||
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. */
|
||||
if (u == 0xa0) return no_nbsp_hack ? " " : NBSP_CHAR_STRING;
|
||||
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);
|
||||
}
|
||||
|
||||
to &= ~SYSTEM_CHARSET_FLAG;
|
||||
|
||||
for (j = 0; codepages[to].table[j].c; j++)
|
||||
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 *
|
||||
inline unsigned char *
|
||||
encode_utf_8(unicode_val_T u)
|
||||
{
|
||||
memset(utf_buffer, 0, 7);
|
||||
@ -200,6 +205,91 @@ encode_utf_8(unicode_val_T u)
|
||||
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 */
|
||||
unsigned char *
|
||||
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 unsigned int nb_entity_cache[ENTITY_CACHE_MAXLEN];
|
||||
static int first_time = 1;
|
||||
unsigned int slen;
|
||||
unsigned int slen = 0;
|
||||
unsigned char *result = 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) {
|
||||
memset(&nb_entity_cache, 0, ENTITY_CACHE_MAXLEN * sizeof(unsigned int));
|
||||
first_time = 0;
|
||||
@ -488,7 +583,7 @@ get_entity_string(const unsigned char *str, const int strlen, int encoding)
|
||||
fprintf(stderr, "miss\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
skip:
|
||||
if (*str == '#') { /* Numeric entity. */
|
||||
int l = (int) strlen;
|
||||
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 (codepages[encoding].table == table_utf_8) {
|
||||
return result;
|
||||
}
|
||||
end:
|
||||
/* Take care of potential buffer overflow. */
|
||||
if (strlen < sizeof(entity_cache[slen][0].str)) {
|
||||
|
@ -53,6 +53,10 @@ unsigned char *get_cp_name(int);
|
||||
unsigned char *get_cp_mime_name(int);
|
||||
int is_cp_special(int);
|
||||
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 *u2cp_(unicode_val_T, int, int no_nbsp_hack);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "elinks.h"
|
||||
|
||||
#include "config/options.h"
|
||||
#include "intl/charsets.h"
|
||||
#include "terminal/color.h"
|
||||
#include "terminal/draw.h"
|
||||
#include "terminal/screen.h"
|
||||
@ -102,7 +103,7 @@ draw_char_color(struct terminal *term, int x, int y, struct color_pair *color)
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -200,7 +201,7 @@ draw_border(struct terminal *term, struct box *box,
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
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
|
||||
draw_text(struct terminal *term, int x, int y,
|
||||
unsigned char *text, int length,
|
||||
@ -288,6 +324,11 @@ draw_text(struct terminal *term, int x, int y,
|
||||
assert(text && length >= 0);
|
||||
if_assert_failed return;
|
||||
|
||||
if (term->utf8) {
|
||||
draw_text_utf8(term, x, y, text, length, attr, color);
|
||||
return;
|
||||
}
|
||||
|
||||
if (length <= 0) return;
|
||||
pos = get_char(term, x, y);
|
||||
if (!pos) return;
|
||||
|
@ -19,7 +19,7 @@ enum screen_char_attr {
|
||||
/* One position in the terminal screen's image. */
|
||||
struct screen_char {
|
||||
/* Contains either character value or frame data. */
|
||||
unsigned char data;
|
||||
uint16_t data;
|
||||
|
||||
/* Attributes are screen_char_attr bits. */
|
||||
unsigned char attr;
|
||||
@ -202,7 +202,7 @@ void draw_char_color(struct terminal *term, int x, int y,
|
||||
struct color_pair *color);
|
||||
|
||||
/* 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. */
|
||||
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. */
|
||||
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);
|
||||
|
||||
/* Draws area defined by @box using the same colors and attributes. */
|
||||
|
@ -245,7 +245,6 @@ handle_interlink_event(struct terminal *term, struct term_event *ev)
|
||||
|
||||
case EVENT_KBD:
|
||||
{
|
||||
int utf8_io = -1;
|
||||
int key = get_kbd_key(ev);
|
||||
|
||||
reset_timer();
|
||||
@ -260,9 +259,7 @@ handle_interlink_event(struct terminal *term, struct term_event *ev)
|
||||
}
|
||||
|
||||
if (interlink->utf_8.len) {
|
||||
utf8_io = get_opt_bool_tree(term->spec, "utf_8_io");
|
||||
|
||||
if ((key & 0xC0) == 0x80 && utf8_io) {
|
||||
if ((key & 0xC0) == 0x80 && term->utf8) {
|
||||
interlink->utf_8.ucs <<= 6;
|
||||
interlink->utf_8.ucs |= key & 0x3F;
|
||||
if (! --interlink->utf_8.len) {
|
||||
@ -280,15 +277,14 @@ handle_interlink_event(struct terminal *term, struct term_event *ev)
|
||||
}
|
||||
}
|
||||
|
||||
if (key < 0x80 || key > 0xFF
|
||||
|| (utf8_io == -1
|
||||
? !get_opt_bool_tree(term->spec, "utf_8_io")
|
||||
: !utf8_io)) {
|
||||
if (key < 0x80 || key > 0xFF || !term->utf8) {
|
||||
|
||||
term_send_event(term, ev);
|
||||
break;
|
||||
|
||||
} else if ((key & 0xC0) == 0xC0 && (key & 0xFE) != 0xFE) {
|
||||
}
|
||||
|
||||
else if ((key & 0xC0) == 0xC0 && (key & 0xFE) != 0xFE) {
|
||||
unsigned int mask, cov = 0x80;
|
||||
int len = 0;
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
unsigned char frame_dumb[48] = " ||||++||++++++--|-+||++--|-+----++++++++ ";
|
||||
static unsigned char frame_vt100[48] = "aaaxuuukkuxkjjjkmvwtqnttmlvwtqnvvwwmmllnnjla ";
|
||||
|
||||
#if 0
|
||||
/* For UTF8 I/O */
|
||||
static unsigned char frame_vt100_u[48] = {
|
||||
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,
|
||||
197, 217, 218, 177, 32, 32, 32, 32
|
||||
};
|
||||
#endif
|
||||
|
||||
static unsigned char frame_freebsd[48] = {
|
||||
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"),
|
||||
};
|
||||
|
||||
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[] = {
|
||||
/* end border: */ TERM_STRING("\x0f"),
|
||||
/* begin border: */ TERM_STRING("\x0e"),
|
||||
@ -99,11 +106,6 @@ struct screen_driver {
|
||||
* uniquely identify the screen_driver. */
|
||||
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. */
|
||||
unsigned char *frame;
|
||||
|
||||
@ -119,6 +121,9 @@ struct screen_driver {
|
||||
/* These are directly derived from the terminal options. */
|
||||
unsigned int transparent:1;
|
||||
|
||||
/* UTF-8 I/O */
|
||||
unsigned int utf8:1;
|
||||
|
||||
/* The terminal._template_ name. */
|
||||
unsigned char name[1]; /* XXX: Keep last! */
|
||||
};
|
||||
@ -126,56 +131,56 @@ struct screen_driver {
|
||||
static struct screen_driver dumb_screen_driver = {
|
||||
NULL_LIST_HEAD,
|
||||
/* type: */ TERM_DUMB,
|
||||
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
|
||||
/* frame: */ frame_dumb,
|
||||
/* frame_seqs: */ NULL,
|
||||
/* underline: */ underline_seqs,
|
||||
/* color_mode: */ COLOR_MODE_16,
|
||||
/* transparent: */ 1,
|
||||
/* utf-8: */ 0,
|
||||
};
|
||||
|
||||
static struct screen_driver vt100_screen_driver = {
|
||||
NULL_LIST_HEAD,
|
||||
/* type: */ TERM_VT100,
|
||||
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
|
||||
/* frame: */ frame_vt100,
|
||||
/* frame_seqs: */ vt100_frame_seqs,
|
||||
/* underline: */ underline_seqs,
|
||||
/* color_mode: */ COLOR_MODE_16,
|
||||
/* transparent: */ 1,
|
||||
/* utf-8: */ 0,
|
||||
};
|
||||
|
||||
static struct screen_driver linux_screen_driver = {
|
||||
NULL_LIST_HEAD,
|
||||
/* type: */ TERM_LINUX,
|
||||
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
|
||||
/* frame: */ NULL, /* No restrict_852 */
|
||||
/* frame_seqs: */ NULL, /* No m11_hack */
|
||||
/* underline: */ underline_seqs,
|
||||
/* color_mode: */ COLOR_MODE_16,
|
||||
/* transparent: */ 1,
|
||||
/* utf-8: */ 0,
|
||||
};
|
||||
|
||||
static struct screen_driver koi8_screen_driver = {
|
||||
NULL_LIST_HEAD,
|
||||
/* type: */ TERM_KOI8,
|
||||
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
|
||||
/* frame: */ frame_koi,
|
||||
/* frame_seqs: */ NULL,
|
||||
/* underline: */ underline_seqs,
|
||||
/* color_mode: */ COLOR_MODE_16,
|
||||
/* transparent: */ 1,
|
||||
/* utf-8: */ 0,
|
||||
};
|
||||
|
||||
static struct screen_driver freebsd_screen_driver = {
|
||||
NULL_LIST_HEAD,
|
||||
/* type: */ TERM_FREEBSD,
|
||||
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
|
||||
/* frame: */ frame_freebsd,
|
||||
/* frame_seqs: */ NULL, /* No m11_hack */
|
||||
/* underline: */ underline_seqs,
|
||||
/* color_mode: */ COLOR_MODE_16,
|
||||
/* transparent: */ 1,
|
||||
/* utf-8: */ 0,
|
||||
};
|
||||
|
||||
/* XXX: Keep in sync with enum term_mode_type. */
|
||||
@ -187,13 +192,14 @@ static struct screen_driver *screen_drivers[] = {
|
||||
/* TERM_FREEBSD: */ &freebsd_screen_driver,
|
||||
};
|
||||
|
||||
#define use_utf8_io(driver) ((driver)->utf8)
|
||||
|
||||
static INIT_LIST_HEAD(active_screen_drivers);
|
||||
|
||||
static void
|
||||
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->transparent = get_opt_bool_tree(term_spec, "transparency");
|
||||
@ -204,30 +210,6 @@ update_screen_driver(struct screen_driver *driver, struct option *term_spec)
|
||||
driver->underline = NULL;
|
||||
}
|
||||
|
||||
if (utf8_io) {
|
||||
driver->charsets[0] = get_opt_codepage_tree(term_spec, "charset");
|
||||
if (driver->type == TERM_LINUX) {
|
||||
if (get_opt_bool_tree(term_spec, "restrict_852"))
|
||||
driver->frame = frame_restrict;
|
||||
|
||||
driver->charsets[1] = get_cp_index("cp437");
|
||||
|
||||
} else if (driver->type == TERM_FREEBSD) {
|
||||
driver->charsets[1] = get_cp_index("cp437");
|
||||
|
||||
} else if (driver->type == TERM_VT100) {
|
||||
driver->frame = frame_vt100_u;
|
||||
driver->charsets[1] = get_cp_index("cp437");
|
||||
|
||||
} else if (driver->type == TERM_KOI8) {
|
||||
driver->charsets[1] = get_cp_index("koi8-r");
|
||||
|
||||
} 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;
|
||||
@ -235,6 +217,9 @@ update_screen_driver(struct screen_driver *driver, struct option *term_spec)
|
||||
if (get_opt_bool_tree(term_spec, "m11_hack"))
|
||||
driver->frame_seqs = m11_hack_frame_seqs;
|
||||
|
||||
if (driver->utf8)
|
||||
driver->frame_seqs = utf8_linux_frame_seqs;
|
||||
|
||||
} else if (driver->type == TERM_FREEBSD) {
|
||||
if (get_opt_bool_tree(term_spec, "m11_hack"))
|
||||
driver->frame_seqs = m11_hack_frame_seqs;
|
||||
@ -243,7 +228,6 @@ update_screen_driver(struct screen_driver *driver, struct option *term_spec)
|
||||
driver->frame = frame_vt100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
screen_driver_change_hook(struct session *ses, struct option *term_spec,
|
||||
@ -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->utf8 = use_utf8_io(driver);
|
||||
|
||||
return driver;
|
||||
}
|
||||
|
||||
@ -299,6 +285,7 @@ get_screen_driver(struct terminal *term)
|
||||
/* Some simple probably useless MRU ;) */
|
||||
move_to_top_of_list(active_screen_drivers, driver);
|
||||
|
||||
term->utf8 = use_utf8_io(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_fg_color(a, b) (TERM_COLOR_FOREGROUND(a) == TERM_COLOR_FOREGROUND(b))
|
||||
|
||||
#define use_utf8_io(driver) ((driver)->charsets[0] != -1)
|
||||
|
||||
static inline void
|
||||
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)) {
|
||||
add_char_to_string(screen, ' ');
|
||||
@ -379,13 +365,15 @@ add_char_data(struct string *screen, struct screen_driver *driver,
|
||||
data = driver->frame[data - 176];
|
||||
|
||||
if (use_utf8_io(driver)) {
|
||||
int charset = driver->charsets[!!border];
|
||||
|
||||
add_to_string(screen, cp2utf_8(charset, data));
|
||||
if (border)
|
||||
add_char_to_string(screen, (unsigned char)data);
|
||||
else
|
||||
if (data != UCS_NO_CHAR)
|
||||
add_to_string(screen, encode_utf_8(data));
|
||||
return;
|
||||
}
|
||||
|
||||
add_char_to_string(screen, data);
|
||||
add_char_to_string(screen, (unsigned char)data);
|
||||
}
|
||||
|
||||
/* Time critical section. */
|
||||
|
@ -110,6 +110,9 @@ struct terminal {
|
||||
* work and even maintaining these structures ;-). */
|
||||
unsigned int master:1;
|
||||
|
||||
/* Indicates whether UTF-8 I/O is used */
|
||||
unsigned int utf8:1;
|
||||
|
||||
/* The current tab number. */
|
||||
int current_tab;
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "document/options.h"
|
||||
#include "document/renderer.h"
|
||||
#include "document/view.h"
|
||||
#include "intl/charsets.h"
|
||||
#include "intl/gettext/libintl.h"
|
||||
#include "main/select.h"
|
||||
#include "main/main.h"
|
||||
@ -322,6 +323,9 @@ add_document_to_string(struct string *string, struct document *document)
|
||||
assert(string && document);
|
||||
if_assert_failed return NULL;
|
||||
|
||||
if (is_cp_special(document->options.cp))
|
||||
goto utf_8;
|
||||
|
||||
for (y = 0; y < document->height; y++) {
|
||||
int white = 0;
|
||||
int x;
|
||||
@ -354,7 +358,43 @@ add_document_to_string(struct string *string, struct document *document)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -382,6 +422,9 @@ dump_to_file(struct document *document, int fd)
|
||||
|
||||
if (!buf) return -1;
|
||||
|
||||
if (is_cp_special(document->options.cp))
|
||||
goto utf_8;
|
||||
|
||||
for (y = 0; y < document->height; y++) {
|
||||
int white = 0;
|
||||
int x;
|
||||
@ -418,13 +461,60 @@ dump_to_file(struct document *document, int fd)
|
||||
if (write_char('\n', fd, buf, &bptr))
|
||||
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) {
|
||||
fail:
|
||||
mem_free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ref:
|
||||
if (document->nlinks && get_opt_bool("document.dump.references")) {
|
||||
int x;
|
||||
unsigned char *header = "\nReferences\n\n Visible links\n";
|
||||
|
@ -158,16 +158,22 @@ init_form_state(struct form_control *fc, struct form_state *fs)
|
||||
mem_free_set(&fs->value, NULL);
|
||||
|
||||
switch (fc->type) {
|
||||
unsigned char *text;
|
||||
|
||||
case FC_TEXT:
|
||||
case FC_PASSWORD:
|
||||
case FC_TEXTAREA:
|
||||
fs->value = stracpy(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;
|
||||
break;
|
||||
case FC_FILE:
|
||||
fs->value = stracpy("");
|
||||
fs->state = 0;
|
||||
fs->utf8_pos = 0;
|
||||
fs->vpos = 0;
|
||||
break;
|
||||
case FC_SELECT:
|
||||
@ -330,12 +336,14 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
|
||||
dy = box->y - vs->y;
|
||||
switch (fc->type) {
|
||||
unsigned char *s;
|
||||
unsigned char *text, *end;
|
||||
int len;
|
||||
int i, x, y;
|
||||
|
||||
case FC_TEXT:
|
||||
case FC_PASSWORD:
|
||||
case FC_FILE:
|
||||
if (term->utf8) goto utf_8;
|
||||
int_bounds(&fs->vpos, fs->state - fc->size + 1, fs->state);
|
||||
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);
|
||||
}
|
||||
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:
|
||||
draw_textarea(term, fs, doc_view, link);
|
||||
break;
|
||||
@ -378,6 +416,7 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
|
||||
else
|
||||
/* XXX: when can this happen? --pasky */
|
||||
s = "";
|
||||
if (term->utf8) goto utf_8_select;
|
||||
len = s ? strlen(s) : 0;
|
||||
for (i = 0; i < link->npoints; i++) {
|
||||
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] : '_');
|
||||
}
|
||||
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_IMAGE:
|
||||
case FC_RESET:
|
||||
@ -1195,6 +1246,7 @@ field_op(struct session *ses, struct document_view *doc_view,
|
||||
unsigned char *text;
|
||||
int length;
|
||||
enum frame_event_status status = FRAME_EVENT_REFRESH;
|
||||
int utf8 = ses->tab->term->utf8;
|
||||
|
||||
assert(ses && doc_view && link && ev);
|
||||
if_assert_failed return FRAME_EVENT_OK;
|
||||
@ -1214,49 +1266,79 @@ field_op(struct session *ses, struct document_view *doc_view,
|
||||
|
||||
switch (action_id) {
|
||||
case ACT_EDIT_LEFT:
|
||||
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;
|
||||
case ACT_EDIT_RIGHT:
|
||||
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;
|
||||
case ACT_EDIT_HOME:
|
||||
if (fc->type == FC_TEXTAREA) {
|
||||
status = textarea_op_home(fs, fc);
|
||||
status = textarea_op_home(fs, fc, utf8);
|
||||
} else {
|
||||
fs->state = 0;
|
||||
fs->utf8_pos = 0;
|
||||
}
|
||||
break;
|
||||
case ACT_EDIT_UP:
|
||||
if (fc->type != FC_TEXTAREA)
|
||||
status = FRAME_EVENT_IGNORED;
|
||||
else
|
||||
status = textarea_op_up(fs, fc);
|
||||
status = textarea_op_up(fs, fc, utf8);
|
||||
break;
|
||||
case ACT_EDIT_DOWN:
|
||||
if (fc->type != FC_TEXTAREA)
|
||||
status = FRAME_EVENT_IGNORED;
|
||||
else
|
||||
status = textarea_op_down(fs, fc);
|
||||
status = textarea_op_down(fs, fc, utf8);
|
||||
break;
|
||||
case ACT_EDIT_END:
|
||||
if (fc->type == FC_TEXTAREA) {
|
||||
status = textarea_op_end(fs, fc);
|
||||
status = textarea_op_end(fs, fc, utf8);
|
||||
} else {
|
||||
fs->state = strlen(fs->value);
|
||||
if (utf8) {
|
||||
unsigned char *text = fs->value;
|
||||
|
||||
fs->utf8_pos = strlen_utf8(&text);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACT_EDIT_BEGINNING_OF_BUFFER:
|
||||
if (fc->type == FC_TEXTAREA) {
|
||||
status = textarea_op_bob(fs, fc);
|
||||
status = textarea_op_bob(fs, fc, utf8);
|
||||
} else {
|
||||
fs->state = 0;
|
||||
fs->utf8_pos = 0;
|
||||
}
|
||||
break;
|
||||
case ACT_EDIT_END_OF_BUFFER:
|
||||
if (fc->type == FC_TEXTAREA) {
|
||||
status = textarea_op_eob(fs, fc);
|
||||
status = textarea_op_eob(fs, fc, utf8);
|
||||
} else {
|
||||
fs->state = strlen(fs->value);
|
||||
if (utf8) {
|
||||
unsigned char *text = fs->value;
|
||||
|
||||
fs->utf8_pos = strlen_utf8(&text);
|
||||
}
|
||||
}
|
||||
break;
|
||||
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))
|
||||
fs->value[0] = 0;
|
||||
fs->state = 0;
|
||||
fs->utf8_pos = 0;
|
||||
break;
|
||||
case ACT_EDIT_PASTE_CLIPBOARD:
|
||||
if (form_field_is_readonly(fc)) break;
|
||||
@ -1289,13 +1372,19 @@ field_op(struct session *ses, struct document_view *doc_view,
|
||||
fs->value = v;
|
||||
memmove(v, text, length + 1);
|
||||
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);
|
||||
break;
|
||||
case ACT_EDIT_ENTER:
|
||||
if (fc->type == FC_TEXTAREA) {
|
||||
status = textarea_op_enter(fs, fc);
|
||||
status = textarea_op_enter(fs, fc, utf8);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1320,7 +1409,19 @@ field_op(struct session *ses, struct document_view *doc_view,
|
||||
status = FRAME_EVENT_OK;
|
||||
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;
|
||||
text = fs->value + fs->state;
|
||||
|
||||
@ -1338,7 +1439,18 @@ field_op(struct session *ses, struct document_view *doc_view,
|
||||
status = FRAME_EVENT_OK;
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
fs->state = (int) (text - fs->value);
|
||||
if (utf8 && fc->type != FC_TEXTAREA) {
|
||||
unsigned char *text = fs->value;
|
||||
|
||||
fs->utf8_pos = strlen_utf8(&text);
|
||||
}
|
||||
break;
|
||||
case ACT_EDIT_KILL_TO_EOL:
|
||||
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)
|
||||
|| strlen(fs->value) >= fc->maxlength
|
||||
|| !insert_in_string(&fs->value, fs->state, "?", 1)) {
|
||||
|| strlen(fs->value) >= fc->maxlength) {
|
||||
status = FRAME_EVENT_OK;
|
||||
break;
|
||||
}
|
||||
if (utf8) {
|
||||
static unsigned char buf[7];
|
||||
static int i = 0;
|
||||
unicode_val_T data;
|
||||
unsigned char *t;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ struct form_state {
|
||||
|
||||
unsigned char *value;
|
||||
int state;
|
||||
int utf8_pos;
|
||||
int vpos;
|
||||
int vypos;
|
||||
|
||||
|
@ -112,6 +112,7 @@ get_link_cursor_offset(struct document_view *doc_view, struct link *link)
|
||||
{
|
||||
struct form_control *fc;
|
||||
struct form_state *fs;
|
||||
int utf8 = doc_view->document->options.utf8;
|
||||
|
||||
switch (link->type) {
|
||||
case LINK_CHECKBOX:
|
||||
@ -123,12 +124,15 @@ get_link_cursor_offset(struct document_view *doc_view, struct link *link)
|
||||
case LINK_FIELD:
|
||||
fc = get_link_form_control(link);
|
||||
fs = find_form_state(doc_view, fc);
|
||||
if (utf8) {
|
||||
return fs ? fs->utf8_pos - fs->vpos : 0;
|
||||
} else
|
||||
return fs ? fs->state - fs->vpos : 0;
|
||||
|
||||
case LINK_AREA:
|
||||
fc = get_link_form_control(link);
|
||||
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_MAP:
|
||||
|
@ -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
|
||||
* logical position in the textarea view. */
|
||||
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;
|
||||
int x, y;
|
||||
@ -155,6 +155,14 @@ area_cursor(struct form_control *fc, struct form_state *fs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
@ -170,8 +178,8 @@ area_cursor(struct form_control *fc, struct form_state *fs)
|
||||
return y * fc->cols + x;
|
||||
}
|
||||
|
||||
void
|
||||
draw_textarea(struct terminal *term, struct form_state *fs,
|
||||
static void
|
||||
draw_textarea_utf8(struct terminal *term, struct form_state *fs,
|
||||
struct document_view *doc_view, struct link *link)
|
||||
{
|
||||
struct line_info *line, *linex;
|
||||
@ -192,7 +200,91 @@ draw_textarea(struct terminal *term, struct form_state *fs,
|
||||
vy = doc_view->vs->y;
|
||||
|
||||
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);
|
||||
if (!linex) return;
|
||||
line = linex;
|
||||
@ -448,8 +540,8 @@ menu_textarea_edit(struct terminal *term, void *xxx, void *ses_)
|
||||
}
|
||||
|
||||
static enum frame_event_status
|
||||
textarea_op(struct form_state *fs, struct form_control *fc,
|
||||
int (*do_op)(struct form_state *, struct line_info *, int))
|
||||
textarea_op(struct form_state *fs, struct form_control *fc, int utf8,
|
||||
int (*do_op)(struct form_state *, struct line_info *, int, int))
|
||||
{
|
||||
struct line_info *line;
|
||||
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);
|
||||
state = fs->state;
|
||||
if (do_op(fs, line, current)) {
|
||||
if (do_op(fs, line, current, utf8)) {
|
||||
mem_free(line);
|
||||
return FRAME_EVENT_IGNORED;
|
||||
}
|
||||
|
||||
mem_free(line);
|
||||
|
||||
return fs->state == state ? FRAME_EVENT_OK : FRAME_EVENT_REFRESH;
|
||||
}
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) 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;
|
||||
int_upper_bound(&fs->state, line[current-1].end);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 (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;
|
||||
int_upper_bound(&fs->state, line[current+1].end);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
fs->state = strlen(fs->value);
|
||||
@ -517,7 +649,7 @@ do_op_end(struct form_state *fs, struct line_info *line, int current)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -527,7 +659,7 @@ do_op_bob(struct form_state *fs, struct line_info *line, int current)
|
||||
}
|
||||
|
||||
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) {
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
* Preserve the column if possible. */
|
||||
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
|
||||
@ -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
|
||||
* the whole thing to the end of the last line. */
|
||||
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
|
||||
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);
|
||||
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_state *fs;
|
||||
struct link *link;
|
||||
int utf8 = doc_view->document->options.utf8;
|
||||
|
||||
assert(doc_view && doc_view->vs && doc_view->document);
|
||||
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
|
||||
* it is available at end or start. */
|
||||
if (direction == 1)
|
||||
textarea_op_eob(fs, fc);
|
||||
textarea_op_eob(fs, fc, utf8);
|
||||
else
|
||||
textarea_op_bob(fs, fc);
|
||||
textarea_op_bob(fs, fc, utf8);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ struct link;
|
||||
struct session;
|
||||
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);
|
||||
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 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_up(struct form_state *fs, struct form_control *fc);
|
||||
enum frame_event_status textarea_op_down(struct form_state *fs, struct form_control *fc);
|
||||
enum frame_event_status textarea_op_end(struct form_state *fs, struct form_control *fc);
|
||||
enum frame_event_status textarea_op_bob(struct form_state *fs, struct form_control *fc);
|
||||
enum frame_event_status textarea_op_eob(struct form_state *fs, struct form_control *fc);
|
||||
enum frame_event_status textarea_op_enter(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, int utf8);
|
||||
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, int utf8);
|
||||
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, int utf8);
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user