mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
Merge with /srv/git/elinks.git
This commit is contained in:
commit
3e2f7f48b5
6
AUTHORS
6
AUTHORS
@ -331,6 +331,9 @@ Len Lattanzi <Len_Lattanzi@StanfordAlumni.org>
|
||||
M. K. Srikant <srix@vsnl.com>
|
||||
Small fix in forms
|
||||
|
||||
M. Levinson <levinsm@users.sourceforge.net>
|
||||
Python scripting fixes
|
||||
|
||||
Marco Bodrato <bodrato@linuz.sns.it>
|
||||
Twinterm support
|
||||
|
||||
@ -420,6 +423,9 @@ Omar Khayam <omark@cyentec.com>
|
||||
<otte@duke.edu>
|
||||
Fix stdin reading on Mac OS X
|
||||
|
||||
Pavol Babincak <scroolik@gmail.com>
|
||||
Improved UTF-8 support with double-width chars
|
||||
|
||||
Peder Stray <peder@ifi.uio.no>
|
||||
Fix handling of key presses turning up as key prefixes
|
||||
|
||||
|
@ -156,6 +156,7 @@ CONFIG_SPIDERMONKEY = @CONFIG_SPIDERMONKEY@
|
||||
CONFIG_SSL = @CONFIG_SSL@
|
||||
CONFIG_SYSMOUSE = @CONFIG_SYSMOUSE@
|
||||
CONFIG_URI_REWRITE = @CONFIG_URI_REWRITE@
|
||||
CONFIG_UTF_8 = @CONFIG_UTF_8@
|
||||
CONFIG_XBEL_BOOKMARKS = @CONFIG_XBEL_BOOKMARKS@
|
||||
CONFIG_XMLTO = @CONFIG_XMLTO@
|
||||
CONFIG_GSSAPI = @CONFIG_GSSAPI@
|
||||
|
@ -19,7 +19,7 @@ AC_DEFUN([EL_LOG_CONFIG],
|
||||
[msgdots2="`echo $about | sed 's/[0-9]/./g'`"]
|
||||
[msgdots1="`echo $msgdots2 | sed 's/[a-z]/./g'`"]
|
||||
[msgdots0="`echo $msgdots1 | sed 's/[A-Z]/./g'`"]
|
||||
[msgdots="`echo $msgdots0 | sed 's/[_ ()]/./g'`"]
|
||||
[msgdots="`echo $msgdots0 | sed 's/[-_ ()]/./g'`"]
|
||||
DOTS="................................"
|
||||
dots=`echo $DOTS | sed "s/$msgdots//"`
|
||||
|
||||
|
94
configure.in
94
configure.in
@ -168,6 +168,7 @@ AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_HEADER_TIME
|
||||
|
||||
AC_CHECK_HEADERS(wctype.h)
|
||||
AC_CHECK_HEADERS(fcntl.h limits.h time.h unistd.h)
|
||||
AC_CHECK_HEADERS(sigaction.h)
|
||||
AC_CHECK_HEADERS(arpa/inet.h)
|
||||
@ -770,17 +771,42 @@ dnl Check for Python
|
||||
dnl ===================================================================
|
||||
enable_python="no";
|
||||
|
||||
AC_ARG_WITH(python, [ --with-python=[prefix] enable Python support],
|
||||
[
|
||||
if test "$withval" != no; then
|
||||
# FIXME: If withval is a valid directory append it to PATH
|
||||
# so that you can specify one of several Python installations.
|
||||
if test "$withval" != yes; then
|
||||
python_prefix="$withval"
|
||||
AC_ARG_WITH(python, [ --with-python=[DIR] enable Python support],
|
||||
[ if test "x$withval" != xno; then enable_python=yes; fi ])
|
||||
|
||||
EL_SAVE_FLAGS
|
||||
cf_result=no
|
||||
|
||||
AC_MSG_CHECKING([for Python])
|
||||
|
||||
if test "$enable_python" = "yes"; then
|
||||
AC_MSG_RESULT(yes);
|
||||
|
||||
if test -d "$withval"; then
|
||||
PYTHON_PATH="$withval:$PATH"
|
||||
else
|
||||
python_prefix=""
|
||||
PYTHON_PATH="$PATH"
|
||||
fi
|
||||
enable_python=yes
|
||||
|
||||
AC_PATH_PROG(PYTHON, python, no, $PYTHON_PATH)
|
||||
|
||||
if test "$PYTHON" != no; then
|
||||
cf_result="yes";
|
||||
|
||||
PYTHON_CFLAGS="`$PYTHON -c 'from distutils import sysconfig; print "-I%s -I%s" % (sysconfig.get_python_inc(), sysconfig.get_python_inc(plat_specific=True))'`"
|
||||
PYTHON_LIBS="`$PYTHON -c 'from distutils import sysconfig; var = sysconfig.get_config_var; print "%s %s %s -L%s -lpython%s" % (var("LINKFORSHARED"), var("LIBS"), var("SYSLIBS"), var("LIBPL"), var("VERSION"))'`"
|
||||
LIBS="$PYTHON_LIBS $LIBS"
|
||||
CPPFLAGS="$CPPFLAGS $PYTHON_CFLAGS"
|
||||
AC_TRY_LINK([#include <Python.h>],
|
||||
[Py_Initialize();],
|
||||
cf_result=yes, cf_result=no)
|
||||
|
||||
if test "$cf_result" != "yes"; then
|
||||
EL_RESTORE_FLAGS
|
||||
else
|
||||
EL_CONFIG(CONFIG_SCRIPTING_PYTHON, [Python])
|
||||
AC_SUBST(PYTHON_LIBS)
|
||||
AC_SUBST(PYTHON_CFLAGS)
|
||||
cat <<EOF
|
||||
***********************************************************************
|
||||
The Python support is incomplete and not so well integrated to ELinks
|
||||
@ -790,48 +816,16 @@ well tested (success stories heartily welcomed!).
|
||||
***********************************************************************
|
||||
EOF
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
cf_result=no
|
||||
|
||||
EL_SAVE_FLAGS
|
||||
|
||||
if test "$enable_python" = "yes"; then
|
||||
if test -n "$python_prefix" && test -d "$python_prefix/bin"; then
|
||||
PYTHON_PATH="$python_prefix/bin:$PATH"
|
||||
else
|
||||
PYTHON_PATH="$PATH"
|
||||
fi
|
||||
AC_PATH_PROG(PYTHON, python, no, $PYTHON_PATH)
|
||||
if test "$PYTHON" = "no" ; then
|
||||
cf_result=no
|
||||
if test -n "$withval" && test "x$withval" != xno; then
|
||||
AC_MSG_ERROR([Python not found])
|
||||
else
|
||||
PYTHON_CFLAGS="-I`$PYTHON -c 'from distutils import sysconfig; print sysconfig.get_python_inc()' 2> /dev/null`"
|
||||
PYTHON_LIBS="-lpython`$PYTHON -c 'from distutils import sysconfig; print sysconfig.get_config_var("VERSION")' 2> /dev/null`"
|
||||
if test -n "$python_prefix" && test -d "$python_prefix/lib"; then
|
||||
PYTHON_LIBS="-L$python_prefix/lib $PYTHON_LIBS"
|
||||
AC_MSG_WARN([Python support disabled])
|
||||
fi
|
||||
fi
|
||||
LIBS="$PYTHON_LIBS $LIBS"
|
||||
CFLAGS="$PYTHON_CFLAGS $CFLAGS"
|
||||
AC_TRY_LINK([#include <Python.h>],
|
||||
[Py_Initialize();],
|
||||
cf_result=yes, cf_result=no)
|
||||
|
||||
if test "$cf_result" != "yes"; then
|
||||
EL_RESTORE_FLAGS
|
||||
else
|
||||
EL_CONFIG(CONFIG_SCRIPTING_PYTHON, [Python])
|
||||
|
||||
CFLAGS="$CFLAGS_X"
|
||||
AC_SUBST(PYTHON_LIBS)
|
||||
AC_SUBST(PYTHON_CFLAGS)
|
||||
AC_MSG_RESULT(no);
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([for Python])
|
||||
if test "$cf_result"; then AC_MSG_RESULT($cf_result); fi
|
||||
|
||||
|
||||
dnl ===================================================================
|
||||
@ -1283,6 +1277,10 @@ EL_ARG_ENABLE(CONFIG_OWN_LIBC, own-libc, [Own libc stubs],
|
||||
EL_ARG_ENABLE(CONFIG_SMALL, small, [Small binary],
|
||||
[ --enable-small reduce binary size as far as possible (but see the bottom of doc/small.txt!)])
|
||||
|
||||
EL_ARG_ENABLE(CONFIG_UTF_8, utf-8, [UTF-8],
|
||||
[ --enable-utf-8 enable UTF-8 support])
|
||||
|
||||
|
||||
AC_ARG_ENABLE(weehoofooboomookerchoo,
|
||||
[
|
||||
Also check out the features.conf file for more information about features!
|
||||
@ -1323,6 +1321,10 @@ AC_SUBST(CONFDIR)
|
||||
|
||||
# Create LOCALEDIR #define for config.h
|
||||
LOCALEDIR=`eval echo "$datadir/locale"`
|
||||
while echo "$LOCALEDIR" | grep "\\$"
|
||||
do
|
||||
LOCALEDIR=`eval echo "$LOCALEDIR"`
|
||||
done > /dev/null 2> /dev/null
|
||||
AC_DEFINE_UNQUOTED(LOCALEDIR, "$LOCALEDIR", [Directory containing locales])
|
||||
AC_SUBST(LOCALEDIR)
|
||||
|
||||
|
@ -1,13 +1,8 @@
|
||||
If you want to use Python scripting with ELinks add
|
||||
--with-python to the configure invocation copy hooks.py to ~/.elinks
|
||||
When your Python installation is your own build, you could give prefix
|
||||
to the configure, eg.
|
||||
--with-python=/usr/local when Python binary is placed in /usr/local/bin, etc.
|
||||
If you want to use Python scripting with ELinks, add --with-python to the
|
||||
configure invocation and copy hooks.py to your ~/.elinks directory.
|
||||
|
||||
When 'configure' cannot find -lpython make symbolic link to the appropriate
|
||||
library, eg.
|
||||
# cd /usr/local/lib
|
||||
# ln -s libpython2.4.so.1.0 libpython.so
|
||||
If configure cannot find Python you can supply a path, e.g.
|
||||
--with-python=/usr/local/bin if your Python binary is in /usr/local/bin, etc.
|
||||
|
||||
For the present hooks.py is not very usable. You are welcome to make it better.
|
||||
Good Luck!
|
||||
|
@ -601,6 +601,27 @@ CONFIG_OWN_LIBC=no
|
||||
CONFIG_SMALL=no
|
||||
|
||||
|
||||
### Unicode UTF-8 support
|
||||
#
|
||||
# By enabling this option you get better Unicode support. At present only some
|
||||
# parts of ELinks are influenced with this. It includes DOM, plain, HTML
|
||||
# renderer and user interface. Beside normal Unicode characters there is
|
||||
# support for double-width characters (like Japanese, etc.).
|
||||
#
|
||||
# Some features of Unicode are not handled at all. Combining characters is
|
||||
# most visible absence.
|
||||
# Some features are partially supported. Like line breaking between
|
||||
# double-width characters. There is no other detection for determining when to
|
||||
# break or not.
|
||||
#
|
||||
# Note: This UTF-8 support is experimental.
|
||||
#
|
||||
# Default: disabled
|
||||
|
||||
CONFIG_UTF_8=no
|
||||
|
||||
|
||||
|
||||
### Back-trace Printing
|
||||
#
|
||||
# Once upon a time, a disaster happens and ELinks crashes. That is a very sad
|
||||
|
2
po/pl.po
2
po/pl.po
@ -2802,7 +2802,7 @@ msgstr "Rozr
|
||||
msgid ""
|
||||
"Whether the search should match the document text while maintaining\n"
|
||||
"case sensitivity."
|
||||
msgstr "Czy zaznaczać tekst różniący się wielkością liter od poszukiwanego?"
|
||||
msgstr "Czy rozróżniać wielkość liter przy szukaniu."
|
||||
|
||||
#: src/config/options.inc:393
|
||||
msgid "Regular expressions"
|
||||
|
121
src/bfu/button.c
121
src/bfu/button.c
@ -77,17 +77,34 @@ add_dlg_button_do(struct dialog *dlg, unsigned char *text, int flags,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
static void
|
||||
buttons_width(struct widget_data *widget_data, int n,
|
||||
int *minwidth, int *maxwidth, int utf8)
|
||||
#else
|
||||
static void
|
||||
buttons_width(struct widget_data *widget_data, int n,
|
||||
int *minwidth, int *maxwidth)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
int maxw = -BUTTON_HSPACING;
|
||||
#ifdef CONFIG_UTF_8
|
||||
int button_lr_len = utf8_ptr2cells(BUTTON_LEFT, NULL)
|
||||
+ utf8_ptr2cells(BUTTON_RIGHT, NULL);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
assert(n > 0);
|
||||
if_assert_failed return;
|
||||
|
||||
while (n--) {
|
||||
int minw = (widget_data++)->widget->info.button.textlen
|
||||
int minw;
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (utf8)
|
||||
minw = utf8_ptr2cells((widget_data++)->widget->text, NULL)
|
||||
+ BUTTON_HSPACING + button_lr_len;
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
minw = (widget_data++)->widget->info.button.textlen
|
||||
+ BUTTON_HSPACING + BUTTON_LR_LEN;
|
||||
|
||||
maxw += minw;
|
||||
@ -100,7 +117,7 @@ buttons_width(struct widget_data *widget_data, int n,
|
||||
void
|
||||
dlg_format_buttons(struct terminal *term,
|
||||
struct widget_data *widget_data, int n,
|
||||
int x, int *y, int w, int *rw, enum format_align align)
|
||||
int x, int *y, int w, int *rw, enum format_align align, int format_only)
|
||||
{
|
||||
int i1 = 0;
|
||||
|
||||
@ -111,20 +128,41 @@ dlg_format_buttons(struct terminal *term,
|
||||
|
||||
while (i2 < n) {
|
||||
mw = 0;
|
||||
#ifdef CONFIG_UTF_8
|
||||
buttons_width(widget_data1, i2 - i1 + 1, NULL, &mw,
|
||||
term->utf8);
|
||||
#else
|
||||
buttons_width(widget_data1, i2 - i1 + 1, NULL, &mw);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
if (mw <= w) i2++;
|
||||
else break;
|
||||
}
|
||||
|
||||
mw = 0;
|
||||
#ifdef CONFIG_UTF_8
|
||||
buttons_width(widget_data1, i2 - i1, NULL, &mw, term->utf8);
|
||||
#else
|
||||
buttons_width(widget_data1, i2 - i1, NULL, &mw);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
if (rw) int_bounds(rw, mw, w);
|
||||
|
||||
if (term) {
|
||||
if (!format_only) {
|
||||
int i;
|
||||
int p = x + (align == ALIGN_CENTER ? (w - mw) / 2 : 0);
|
||||
#ifdef CONFIG_UTF_8
|
||||
int button_lr_len = utf8_ptr2cells(BUTTON_LEFT, NULL)
|
||||
+ utf8_ptr2cells(BUTTON_RIGHT, NULL);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
for (i = i1; i < i2; i++) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
set_box(&widget_data[i].box,
|
||||
p, *y,
|
||||
utf8_ptr2cells(widget_data[i].widget->text, NULL)
|
||||
+ button_lr_len, BUTTON_HEIGHT);
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
set_box(&widget_data[i].box,
|
||||
p, *y,
|
||||
widget_data[i].widget->info.button.textlen
|
||||
@ -145,8 +183,7 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
|
||||
struct terminal *term = dlg_data->win->term;
|
||||
struct color_pair *color, *shortcut_color;
|
||||
struct box *pos = &widget_data->box;
|
||||
int len = widget_data->box.width - BUTTON_LR_LEN;
|
||||
int x = pos->x + BUTTON_LEFT_LEN;
|
||||
int len, x;
|
||||
int sel = is_selected_widget(dlg_data, widget_data);
|
||||
|
||||
if (sel) {
|
||||
@ -158,6 +195,23 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
|
||||
}
|
||||
if (!color || !shortcut_color) return EVENT_PROCESSED;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
int button_left_len = utf8_ptr2cells(BUTTON_LEFT, NULL);
|
||||
int button_right_len = utf8_ptr2cells(BUTTON_RIGHT, NULL);
|
||||
|
||||
x = pos->x + button_left_len;
|
||||
len = widget_data->box.width -
|
||||
(button_left_len + button_right_len);
|
||||
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
x = pos->x + BUTTON_LEFT_LEN;
|
||||
len = widget_data->box.width - BUTTON_LR_LEN;
|
||||
}
|
||||
|
||||
|
||||
draw_text(term, pos->x, pos->y, BUTTON_LEFT, BUTTON_LEFT_LEN, 0, color);
|
||||
if (len > 0) {
|
||||
unsigned char *text = widget_data->widget->text;
|
||||
@ -167,6 +221,52 @@ 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;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
if (hk_pos >= 0) {
|
||||
int hk_bytes = utf8charlen(&text[hk_pos+1]);
|
||||
int cells_to_hk = utf8_ptr2cells(text,
|
||||
&text[hk_pos]);
|
||||
int right = widget_data->widget->info.button.truetextlen
|
||||
- hk_pos
|
||||
- hk_bytes;
|
||||
|
||||
int hk_cells = utf8_char2cells(&text[hk_pos
|
||||
+ 1],
|
||||
NULL);
|
||||
|
||||
if (hk_pos)
|
||||
draw_text(term, x, pos->y,
|
||||
text, hk_pos, 0, color);
|
||||
|
||||
draw_text(term, x + cells_to_hk, pos->y,
|
||||
&text[hk_pos + 1], hk_bytes,
|
||||
attr, shortcut_color);
|
||||
|
||||
if (right > 1)
|
||||
draw_text(term, x+cells_to_hk+hk_cells,
|
||||
pos->y,
|
||||
&text[hk_pos + hk_bytes + 1],
|
||||
right - 1, 0, color);
|
||||
|
||||
} else {
|
||||
int hk_width = utf8_char2cells(text, NULL);
|
||||
int hk_len = utf8charlen(text);
|
||||
int len_to_display =
|
||||
utf8_cells2bytes(&text[hk_len],
|
||||
len - hk_width,
|
||||
NULL);
|
||||
|
||||
draw_text(term, x, pos->y,
|
||||
text, hk_len,
|
||||
attr, shortcut_color);
|
||||
|
||||
draw_text(term, x + hk_width, pos->y,
|
||||
&text[hk_len], len_to_display,
|
||||
0, color);
|
||||
}
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
if (hk_pos >= 0) {
|
||||
int right = widget_data->widget->info.button.truetextlen - hk_pos - 1;
|
||||
|
||||
@ -185,8 +285,17 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
|
||||
draw_text(term, x + 1, pos->y, &text[1], len - 1, 0, color);
|
||||
}
|
||||
}
|
||||
draw_text(term, x + len, pos->y, BUTTON_RIGHT, BUTTON_RIGHT_LEN, 0, color);
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
int text_cells = utf8_ptr2cells(widget_data->widget->text, NULL);
|
||||
int hk = (widget_data->widget->info.button.hotkey_pos >= 0);
|
||||
|
||||
draw_text(term, x + text_cells - hk, pos->y,
|
||||
BUTTON_RIGHT, BUTTON_RIGHT_LEN, 0, color);
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
draw_text(term, x + len, pos->y, BUTTON_RIGHT,
|
||||
BUTTON_RIGHT_LEN, 0, color);
|
||||
if (sel) {
|
||||
set_cursor(term, x, pos->y, 1);
|
||||
set_window_ptr(dlg_data->win, pos->x, pos->y);
|
||||
|
@ -48,6 +48,6 @@ void add_dlg_button_do(struct dialog *dlg, unsigned char *text, int flags, widge
|
||||
#endif
|
||||
|
||||
extern struct widget_ops button_ops;
|
||||
void dlg_format_buttons(struct terminal *, struct widget_data *, int, int, int *, int, int *, enum format_align);
|
||||
void dlg_format_buttons(struct terminal *, struct widget_data *, int, int, int *, int, int *, enum format_align, int);
|
||||
|
||||
#endif
|
||||
|
@ -39,7 +39,7 @@ void
|
||||
dlg_format_checkbox(struct terminal *term,
|
||||
struct widget_data *widget_data,
|
||||
int x, int *y, int w, int *rw,
|
||||
enum format_align align)
|
||||
enum format_align align, int format_only)
|
||||
{
|
||||
unsigned char *text = widget_data->widget->text;
|
||||
|
||||
@ -52,7 +52,7 @@ dlg_format_checkbox(struct terminal *term,
|
||||
dlg_format_text_do(term, text, x + CHECKBOX_LS, y,
|
||||
w - CHECKBOX_LS, rw,
|
||||
get_bfu_color(term, "dialog.checkbox-label"),
|
||||
align);
|
||||
align, format_only);
|
||||
if (rw) *rw += CHECKBOX_LS;
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ void
|
||||
dlg_format_checkbox(struct terminal *term,
|
||||
struct widget_data *widget_data,
|
||||
int x, int *y, int w, int *rw,
|
||||
enum format_align align);
|
||||
enum format_align align, int format_only);
|
||||
|
||||
#define widget_has_group(widget_data) ((widget_data)->widget->type == WIDGET_CHECKBOX \
|
||||
? (widget_data)->widget->info.checkbox.gid : -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,32 @@ 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;
|
||||
int y = box.y - 1;
|
||||
int titlelen = strlen(title);
|
||||
int titlecells = titlelen;
|
||||
int x, y;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
titlecells = utf8_ptr2cells(title,
|
||||
&title[titlelen]);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
titlecells = int_min(box.width - 2, titlecells);
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
titlelen = utf8_cells2bytes(title, titlecells,
|
||||
NULL);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
x = (box.width - titlecells) / 2 + box.x;
|
||||
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 + titlecells, y, " ", 1, 0,
|
||||
title_color);
|
||||
}
|
||||
}
|
||||
|
||||
@ -499,7 +519,7 @@ clear_dialog(struct dialog_data *dlg_data, struct widget_data *xxx)
|
||||
|
||||
static void
|
||||
format_widgets(struct terminal *term, struct dialog_data *dlg_data,
|
||||
int x, int *y, int w, int h, int *rw)
|
||||
int x, int *y, int w, int h, int *rw, int format_only)
|
||||
{
|
||||
struct widget_data *wdata = dlg_data->widgets_data;
|
||||
int widgets = dlg_data->number_of_widgets;
|
||||
@ -509,15 +529,18 @@ format_widgets(struct terminal *term, struct dialog_data *dlg_data,
|
||||
switch (wdata->widget->type) {
|
||||
case WIDGET_FIELD_PASS:
|
||||
case WIDGET_FIELD:
|
||||
dlg_format_field(term, wdata, x, y, w, rw, ALIGN_LEFT);
|
||||
dlg_format_field(term, wdata, x, y, w, rw, ALIGN_LEFT,
|
||||
format_only);
|
||||
break;
|
||||
|
||||
case WIDGET_LISTBOX:
|
||||
dlg_format_listbox(term, wdata, x, y, w, h, rw, ALIGN_LEFT);
|
||||
dlg_format_listbox(term, wdata, x, y, w, h, rw,
|
||||
ALIGN_LEFT, format_only);
|
||||
break;
|
||||
|
||||
case WIDGET_TEXT:
|
||||
dlg_format_text(term, wdata, x, y, w, rw, h);
|
||||
dlg_format_text(term, wdata, x, y, w, rw, h,
|
||||
format_only);
|
||||
break;
|
||||
|
||||
case WIDGET_CHECKBOX:
|
||||
@ -535,14 +558,16 @@ format_widgets(struct terminal *term, struct dialog_data *dlg_data,
|
||||
break;
|
||||
}
|
||||
|
||||
dlg_format_group(term, wdata, size, x, y, w, rw);
|
||||
dlg_format_group(term, wdata, size, x, y, w, rw,
|
||||
format_only);
|
||||
wdata += size - 1;
|
||||
|
||||
} else {
|
||||
|
||||
/* No horizontal space between checkboxes belonging to
|
||||
* the same group. */
|
||||
dlg_format_checkbox(term, wdata, x, y, w, rw, ALIGN_LEFT);
|
||||
dlg_format_checkbox(term, wdata, x, y, w, rw,
|
||||
ALIGN_LEFT, format_only);
|
||||
if (widgets > 1
|
||||
&& group == widget_has_group(&wdata[1]))
|
||||
(*y)--;
|
||||
@ -554,7 +579,7 @@ format_widgets(struct terminal *term, struct dialog_data *dlg_data,
|
||||
* of the dialog. */
|
||||
case WIDGET_BUTTON:
|
||||
dlg_format_buttons(term, wdata, widgets,
|
||||
x, y, w, rw, ALIGN_CENTER);
|
||||
x, y, w, rw, ALIGN_CENTER, format_only);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -566,11 +591,17 @@ generic_dialog_layouter(struct dialog_data *dlg_data)
|
||||
struct terminal *term = dlg_data->win->term;
|
||||
int w = dialog_max_width(term);
|
||||
int height = dialog_max_height(term);
|
||||
int rw = int_min(w, strlen(dlg_data->dlg->title));
|
||||
int y = dlg_data->dlg->layout.padding_top ? 0 : -1;
|
||||
int x = 0;
|
||||
int x = 0, y, rw;
|
||||
|
||||
format_widgets(NULL, dlg_data, x, &y, w, height, &rw);
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
rw = int_min(w, utf8_ptr2cells(dlg_data->dlg->title, NULL));
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
rw = int_min(w, strlen(dlg_data->dlg->title));
|
||||
y = dlg_data->dlg->layout.padding_top ? 0 : -1;
|
||||
|
||||
format_widgets(term, dlg_data, x, &y, w, height, &rw, 1);
|
||||
|
||||
/* Update the width to respond to the required minimum width */
|
||||
if (dlg_data->dlg->layout.fit_datalen) {
|
||||
@ -585,7 +616,7 @@ generic_dialog_layouter(struct dialog_data *dlg_data)
|
||||
y = dlg_data->box.y + DIALOG_TB + dlg_data->dlg->layout.padding_top;
|
||||
x = dlg_data->box.x + DIALOG_LB;
|
||||
|
||||
format_widgets(term, dlg_data, x, &y, w, height, NULL);
|
||||
format_widgets(term, dlg_data, x, &y, w, height, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -607,7 +638,15 @@ draw_dialog(struct dialog_data *dlg_data, int width, int height)
|
||||
/* Draw shadow */
|
||||
draw_shadow(term, &dlg_data->box,
|
||||
get_bfu_color(term, "dialog.shadow"), 2, 1);
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
fix_dwchar_around_box(term, &dlg_data->box, 0, 2, 1);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
}
|
||||
#ifdef CONFIG_UTF_8
|
||||
else if(term->utf8)
|
||||
fix_dwchar_around_box(term, &dlg_data->box, 0, 0, 0);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -16,10 +16,13 @@
|
||||
#include "terminal/terminal.h"
|
||||
#include "util/color.h"
|
||||
|
||||
/* Same as in src/bfu/checkbox.c */
|
||||
#define CHECKBOX_LEN 3 /* "[X]" or "(X)" */
|
||||
|
||||
void
|
||||
dlg_format_group(struct terminal *term,
|
||||
struct widget_data *widget_data,
|
||||
int n, int x, int *y, int w, int *rw)
|
||||
int n, int x, int *y, int w, int *rw, int format_only)
|
||||
{
|
||||
int space_between_widgets = 1;
|
||||
int line_width = 0;
|
||||
@ -33,12 +36,30 @@ dlg_format_group(struct terminal *term,
|
||||
int widget_width;
|
||||
int width;
|
||||
unsigned char *text = widget_data->widget->text;
|
||||
int label_length = (text && *text) ? strlen(text) : 0;
|
||||
int label_padding = (label_length > 0);
|
||||
int label_length;
|
||||
int label_padding;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
if (text && *text)
|
||||
label_length = utf8_ptr2cells(text, NULL);
|
||||
else
|
||||
label_length = 0;
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
label_length = (text && *text) ? strlen(text) : 0;
|
||||
|
||||
label_padding = (label_length > 0);
|
||||
|
||||
if (widget_data->widget->type == WIDGET_CHECKBOX) {
|
||||
width = 3;
|
||||
width = CHECKBOX_LEN;
|
||||
} else if (widget_is_textfield(widget_data)) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
width = utf8_ptr2cells(widget_data->widget->data,
|
||||
NULL);
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
width = widget_data->widget->datalen;
|
||||
} else {
|
||||
/* TODO: handle all widget types. */
|
||||
@ -56,22 +77,52 @@ dlg_format_group(struct terminal *term,
|
||||
|
||||
xpos = x + line_width;
|
||||
|
||||
if (term) {
|
||||
if (!format_only) {
|
||||
if (widget_data->widget->type == WIDGET_CHECKBOX) {
|
||||
/* Draw text at right of checkbox. */
|
||||
if (label_length)
|
||||
draw_text(term, xpos + width + label_padding, *y,
|
||||
text, label_length,
|
||||
0, color);
|
||||
if (label_length) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
int lb = utf8_cells2bytes(
|
||||
text,
|
||||
label_length,
|
||||
NULL);
|
||||
draw_text(term, xpos + width
|
||||
+ label_padding,
|
||||
*y, text, lb, 0,
|
||||
color);
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
draw_text(term, xpos + width
|
||||
+ label_padding,
|
||||
*y, text,
|
||||
label_length, 0,
|
||||
color);
|
||||
}
|
||||
}
|
||||
|
||||
set_box(&widget_data->box, xpos, *y, width, 1);
|
||||
|
||||
} else if (widget_is_textfield(widget_data)) {
|
||||
/* Draw label at left of widget. */
|
||||
if (label_length)
|
||||
if (label_length) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
int lb = utf8_cells2bytes(
|
||||
text,
|
||||
label_length,
|
||||
NULL);
|
||||
draw_text(term, xpos, *y,
|
||||
text, lb, 0, color);
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
draw_text(term, xpos, *y,
|
||||
text, label_length,
|
||||
0, color);
|
||||
}
|
||||
}
|
||||
|
||||
set_box(&widget_data->box,
|
||||
xpos + label_padding + label_length, *y,
|
||||
@ -93,16 +144,23 @@ group_layouter(struct dialog_data *dlg_data)
|
||||
{
|
||||
struct terminal *term = dlg_data->win->term;
|
||||
int w = dialog_max_width(term);
|
||||
int rw = int_min(w, strlen(dlg_data->dlg->title));
|
||||
int rw;
|
||||
int y = 0;
|
||||
int n = dlg_data->number_of_widgets - 2;
|
||||
|
||||
dlg_format_group(NULL, dlg_data->widgets_data, n,
|
||||
0, &y, w, &rw);
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
rw = int_min(w, utf8_ptr2cells(dlg_data->dlg->title, NULL));
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
rw = int_min(w, strlen(dlg_data->dlg->title));
|
||||
|
||||
dlg_format_group(term, dlg_data->widgets_data, n,
|
||||
0, &y, w, &rw, 1);
|
||||
|
||||
y++;
|
||||
dlg_format_buttons(NULL, dlg_data->widgets_data + n, 2, 0, &y, w,
|
||||
&rw, ALIGN_CENTER);
|
||||
dlg_format_buttons(term, dlg_data->widgets_data + n, 2, 0, &y, w,
|
||||
&rw, ALIGN_CENTER, 1);
|
||||
|
||||
w = rw;
|
||||
|
||||
@ -110,9 +168,9 @@ group_layouter(struct dialog_data *dlg_data)
|
||||
|
||||
y = dlg_data->box.y + DIALOG_TB + 1;
|
||||
dlg_format_group(term, dlg_data->widgets_data, n,
|
||||
dlg_data->box.x + DIALOG_LB, &y, w, NULL);
|
||||
dlg_data->box.x + DIALOG_LB, &y, w, NULL, 0);
|
||||
|
||||
y++;
|
||||
dlg_format_buttons(term, dlg_data->widgets_data + n, 2,
|
||||
dlg_data->box.x + DIALOG_LB, &y, w, &rw, ALIGN_CENTER);
|
||||
dlg_data->box.x + DIALOG_LB, &y, w, &rw, ALIGN_CENTER, 0);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ struct widget_data;
|
||||
|
||||
void dlg_format_group(struct terminal *term,
|
||||
struct widget_data *widget_data,
|
||||
int n, int x, int *y, int w, int *rw);
|
||||
int n, int x, int *y, int w, int *rw, int format_only);
|
||||
|
||||
void group_layouter(struct dialog_data *);
|
||||
|
||||
|
@ -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"
|
||||
@ -104,7 +105,7 @@ check_nonempty(struct dialog_data *dlg_data, struct widget_data *widget_data)
|
||||
void
|
||||
dlg_format_field(struct terminal *term,
|
||||
struct widget_data *widget_data,
|
||||
int x, int *y, int w, int *rw, enum format_align align)
|
||||
int x, int *y, int w, int *rw, enum format_align align, int format_only)
|
||||
{
|
||||
static int max_label_width;
|
||||
static int *prev_y; /* Assert the uniqueness of y */ /* TODO: get rid of this !! --Zas */
|
||||
@ -129,9 +130,9 @@ dlg_format_field(struct terminal *term,
|
||||
}
|
||||
|
||||
if (label && *label) {
|
||||
if (term) text_color = get_bfu_color(term, "dialog.text");
|
||||
if (!format_only) text_color = get_bfu_color(term, "dialog.text");
|
||||
|
||||
dlg_format_text_do(term, label, x, y, w, rw, text_color, ALIGN_LEFT);
|
||||
dlg_format_text_do(term, label, x, y, w, rw, text_color, ALIGN_LEFT, format_only);
|
||||
}
|
||||
|
||||
/* XXX: We want the field and label on the same line if the terminal
|
||||
@ -141,7 +142,7 @@ dlg_format_field(struct terminal *term,
|
||||
(*y) -= INPUTFIELD_HEIGHT;
|
||||
dlg_format_text_do(term, INPUTFIELD_FLOAT_SEPARATOR,
|
||||
x + label_width, y, w, rw,
|
||||
text_color, ALIGN_LEFT);
|
||||
text_color, ALIGN_LEFT, format_only);
|
||||
w -= INPUTFIELD_FLOAT_SEPARATOR_LEN + INPUTFIELD_FLOATLABEL_PADDING;
|
||||
x += INPUTFIELD_FLOAT_SEPARATOR_LEN + INPUTFIELD_FLOATLABEL_PADDING;
|
||||
}
|
||||
@ -265,11 +266,27 @@ 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);
|
||||
#ifdef CONFIG_UTF_8
|
||||
int len = 0, left = 0;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
unsigned char *t = widget_data->cdata;
|
||||
int p = widget_data->info.field.cpos;
|
||||
|
||||
len = utf8_ptr2cells(t, &t[p]);
|
||||
int_bounds(&left, len - widget_data->box.width + 1, len);
|
||||
int_lower_bound(&left, 0);
|
||||
widget_data->info.field.vpos = utf8_cells2bytes(t, left, NULL);
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
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,13 +294,26 @@ 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);
|
||||
int w = int_min(len, widget_data->box.width);
|
||||
unsigned char *text = widget_data->cdata + widget_data->info.field.vpos;
|
||||
int len, w;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8 && !hide)
|
||||
len = utf8_ptr2cells(text, NULL);
|
||||
else if (term->utf8)
|
||||
len = utf8_ptr2chars(text, NULL);
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
len = strlen(text);
|
||||
w = int_min(len, widget_data->box.width);
|
||||
|
||||
if (!hide) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
w = utf8_cells2bytes(text, w, NULL);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
draw_text(term, widget_data->box.x, widget_data->box.y,
|
||||
widget_data->cdata + widget_data->info.field.vpos, w,
|
||||
0, color);
|
||||
text, w, 0, color);
|
||||
} else {
|
||||
struct box box;
|
||||
|
||||
@ -295,7 +325,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;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
x = widget_data->box.x + len - left;
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
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 +472,39 @@ 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)) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
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
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
widget_data->info.field.cpos++;
|
||||
}
|
||||
}
|
||||
goto display_field;
|
||||
|
||||
case ACT_EDIT_LEFT:
|
||||
if (widget_data->info.field.cpos > 0)
|
||||
widget_data->info.field.cpos--;
|
||||
#ifdef CONFIG_UTF_8
|
||||
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);
|
||||
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
goto display_field;
|
||||
|
||||
case ACT_EDIT_HOME:
|
||||
@ -453,6 +516,34 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
|
||||
goto display_field;
|
||||
|
||||
case ACT_EDIT_BACKSPACE:
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (widget_data->info.field.cpos && term->utf8) {
|
||||
/* XXX: stolen from src/viewer/text/form.c */
|
||||
/* FIXME: This isn't nice. We remove last byte
|
||||
* from UTF-8 character to detect
|
||||
* character before it. */
|
||||
unsigned char *text = widget_data->cdata;
|
||||
unsigned char *end = widget_data->cdata + widget_data->info.field.cpos - 1;
|
||||
unicode_val_T data;
|
||||
int old = widget_data->info.field.cpos;
|
||||
|
||||
while(1) {
|
||||
data = utf_8_to_unicode(&text, end);
|
||||
if (data == UCS_NO_CHAR)
|
||||
break;
|
||||
}
|
||||
|
||||
widget_data->info.field.cpos = (int)(text - widget_data->cdata);
|
||||
if (old != widget_data->info.field.cpos) {
|
||||
int length;
|
||||
|
||||
text = widget_data->cdata;
|
||||
length = strlen(text + old) + 1;
|
||||
memmove(text + widget_data->info.field.cpos, text + old, length);
|
||||
}
|
||||
goto display_field;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
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 +558,20 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
|
||||
|
||||
if (widget_data->info.field.cpos >= cdata_len) goto display_field;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
unsigned char *end = widget_data->cdata + cdata_len;
|
||||
unsigned char *text = widget_data->cdata + widget_data->info.field.cpos;
|
||||
unsigned char *old = text;
|
||||
|
||||
utf_8_to_unicode(&text, end);
|
||||
if (old != text) {
|
||||
memmove(old, text,
|
||||
(int)(end - text) + 1);
|
||||
}
|
||||
goto display_field;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
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);
|
||||
@ -585,7 +690,22 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
|
||||
|
||||
memmove(text + 1, text, textlen + 1);
|
||||
*text = get_kbd_key(ev);
|
||||
#ifdef CONFIG_UTF_8
|
||||
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;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
goto display_field;
|
||||
}
|
||||
}
|
||||
@ -641,7 +761,7 @@ input_line_layouter(struct dialog_data *dlg_data)
|
||||
- ses->status.show_tabs_bar;
|
||||
|
||||
dlg_format_field(win->term, dlg_data->widgets_data, 0,
|
||||
&y, win->term->width, NULL, ALIGN_LEFT);
|
||||
&y, win->term->width, NULL, ALIGN_LEFT, 0);
|
||||
}
|
||||
|
||||
static widget_handler_status_T
|
||||
|
@ -62,7 +62,7 @@ extern struct widget_ops field_pass_ops;
|
||||
widget_handler_status_T check_number(struct dialog_data *, struct widget_data *);
|
||||
widget_handler_status_T check_nonempty(struct dialog_data *, struct widget_data *);
|
||||
|
||||
void dlg_format_field(struct terminal *, struct widget_data *, int, int *, int, int *, enum format_align);
|
||||
void dlg_format_field(struct terminal *, struct widget_data *, int, int *, int, int *, enum format_align, int format_only);
|
||||
|
||||
void input_field(struct terminal *, struct memory_list *, int, unsigned char *,
|
||||
unsigned char *, unsigned char *, unsigned char *, void *,
|
||||
|
@ -43,7 +43,7 @@ get_listbox_widget_data(struct widget_data *widget_data)
|
||||
void
|
||||
dlg_format_listbox(struct terminal *term, struct widget_data *widget_data,
|
||||
int x, int *y, int w, int max_height, int *rw,
|
||||
enum format_align align)
|
||||
enum format_align align, int format_only)
|
||||
{
|
||||
int min, optimal_h, height;
|
||||
|
||||
@ -453,6 +453,7 @@ display_listbox_item(struct listbox_item *item, void *data_, int *offset)
|
||||
} else {
|
||||
unsigned char *text;
|
||||
struct listbox_ops *ops = data->box->ops;
|
||||
int len_bytes;
|
||||
|
||||
assert(ops && ops->get_info);
|
||||
|
||||
@ -461,8 +462,14 @@ display_listbox_item(struct listbox_item *item, void *data_, int *offset)
|
||||
|
||||
len = strlen(text);
|
||||
int_upper_bound(&len, int_max(0, data->widget_data->box.width - depth * 5));
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (data->term->utf8)
|
||||
len_bytes = utf8_cells2bytes(text, len, NULL);
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
len_bytes = len;
|
||||
|
||||
draw_text(data->term, x, y, text, len, 0, text_color);
|
||||
draw_text(data->term, x, y, text, len_bytes, 0, text_color);
|
||||
|
||||
mem_free(text);
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ struct listbox_item {
|
||||
|
||||
extern struct widget_ops listbox_ops;
|
||||
|
||||
void dlg_format_listbox(struct terminal *, struct widget_data *, int, int *, int, int, int *, enum format_align);
|
||||
void dlg_format_listbox(struct terminal *, struct widget_data *, int, int *, int, int, int *, enum format_align, int format_only);
|
||||
|
||||
struct listbox_item *traverse_listbox_items_list(struct listbox_item *, struct listbox_data *, int, int, int (*)(struct listbox_item *, void *, int *), void *);
|
||||
|
||||
|
142
src/bfu/menu.c
142
src/bfu/menu.c
@ -200,7 +200,14 @@ get_menuitem_text_width(struct terminal *term, struct menu_item *mi)
|
||||
|
||||
if (!text[0]) return 0;
|
||||
|
||||
return L_TEXT_SPACE + strlen(text) - !!mi->hotkey_pos + R_TEXT_SPACE;
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
return L_TEXT_SPACE + utf8_ptr2cells(text, NULL)
|
||||
- !!mi->hotkey_pos + R_TEXT_SPACE;
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
return L_TEXT_SPACE + strlen(text)
|
||||
- !!mi->hotkey_pos + R_TEXT_SPACE;
|
||||
}
|
||||
|
||||
/* Get desired width for right text in menu item, accounting spacing. */
|
||||
@ -360,17 +367,31 @@ set_menu_selection(struct menu *menu, int pos)
|
||||
int_bounds(&menu->first, 0, menu->size - height);
|
||||
}
|
||||
|
||||
/* width - number of standard terminal cells to be displayed (text + whitespace
|
||||
* separators). For double-width glyph width == 2.
|
||||
* len - length of text in bytes */
|
||||
static inline void
|
||||
draw_menu_left_text(struct terminal *term, unsigned char *text, int len,
|
||||
int x, int y, int width, struct color_pair *color)
|
||||
{
|
||||
int w = width - (L_TEXT_SPACE + R_TEXT_SPACE);
|
||||
int max_len;
|
||||
|
||||
if (w <= 0) return;
|
||||
|
||||
if (len < 0) len = strlen(text);
|
||||
if (!len) return;
|
||||
if (len > w) len = w;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
max_len = utf8_cells2bytes(text, w, NULL);
|
||||
if (max_len <= 0)
|
||||
return;
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
max_len = w;
|
||||
|
||||
if (len > max_len) len = max_len;
|
||||
|
||||
draw_text(term, x + L_TEXT_SPACE, y, text, len, 0, color);
|
||||
}
|
||||
@ -389,6 +410,10 @@ draw_menu_left_text_hk(struct terminal *term, unsigned char *text,
|
||||
int xbase = x + L_TEXT_SPACE;
|
||||
int w = width - (L_TEXT_SPACE + R_TEXT_SPACE);
|
||||
int hk_state = 0;
|
||||
#ifdef CONFIG_UTF_8
|
||||
unsigned char *text2, *end;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG
|
||||
/* For redundant hotkeys highlighting. */
|
||||
int double_hk = 0;
|
||||
@ -405,6 +430,10 @@ draw_menu_left_text_hk(struct terminal *term, unsigned char *text,
|
||||
hk_color_sel = tmp;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) goto utf8;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
for (x = 0; x - !!hk_state < w && (c = text[x]); x++) {
|
||||
if (!hk_state && x == hotkey_pos - 1) {
|
||||
hk_state = 1;
|
||||
@ -417,12 +446,78 @@ draw_menu_left_text_hk(struct terminal *term, unsigned char *text,
|
||||
(double_hk ? hk_color_sel : hk_color));
|
||||
#else
|
||||
draw_char(term, xbase + x - 1, y, c, hk_attr, hk_color);
|
||||
#endif
|
||||
#endif /* CONFIG_DEBUG */
|
||||
hk_state = 2;
|
||||
} else {
|
||||
draw_char(term, xbase + x - !!hk_state, y, c, 0, color);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
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) {
|
||||
if (unicode_to_cell(data) == 2) {
|
||||
if (x < w && xbase + x < term->width) {
|
||||
#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 /* CONFIG_DEBUG */
|
||||
x++;
|
||||
draw_char(term, xbase + x - 1, y,
|
||||
UCS_NO_CHAR, 0, hk_color);
|
||||
} else {
|
||||
draw_char(term, xbase + x - 1, y,
|
||||
' ', 0, hk_color);
|
||||
}
|
||||
} else {
|
||||
#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 /* CONFIG_DEBUG */
|
||||
}
|
||||
hk_state = 2;
|
||||
} else {
|
||||
if (unicode_to_cell(data) == 2) {
|
||||
if (x - !!hk_state + 1 < w &&
|
||||
xbase + x - !!hk_state + 1 < term->width) {
|
||||
draw_char(term, xbase + x - !!hk_state,
|
||||
y, data, 0, color);
|
||||
x++;
|
||||
draw_char(term, xbase + x - !!hk_state,
|
||||
y, UCS_NO_CHAR, 0, color);
|
||||
} else {
|
||||
draw_char(term, xbase + x - !!hk_state,
|
||||
y, ' ', 0, color);
|
||||
}
|
||||
} else {
|
||||
draw_char(term, xbase + x - !!hk_state,
|
||||
y, data, 0, color);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -465,7 +560,15 @@ display_menu(struct terminal *term, struct menu *menu)
|
||||
/* Draw shadow */
|
||||
draw_shadow(term, &menu->box,
|
||||
get_bfu_color(term, "dialog.shadow"), 2, 1);
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
fix_dwchar_around_box(term, &box, 1, 2, 1);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
}
|
||||
#ifdef CONFIG_UTF_8
|
||||
else if(term->utf8)
|
||||
fix_dwchar_around_box(term, &box, 1, 0, 0);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
menu_height = box.height;
|
||||
box.height = 1;
|
||||
@ -1005,18 +1108,33 @@ display_mainmenu(struct terminal *term, struct menu *menu)
|
||||
int l = mi->hotkey_pos;
|
||||
int textlen;
|
||||
int selected = (i == menu->selected);
|
||||
int screencnt;
|
||||
|
||||
if (mi_text_translate(mi))
|
||||
text = _(text, term);
|
||||
|
||||
textlen = strlen(text) - !!l;
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
screencnt = utf8_ptr2cells(text, NULL) - !!l;
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
screencnt = textlen;
|
||||
|
||||
if (selected) {
|
||||
color = selected_color;
|
||||
box.x = p;
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
box.width = L_MAINTEXT_SPACE + L_TEXT_SPACE
|
||||
+ screencnt
|
||||
+ R_TEXT_SPACE + R_MAINTEXT_SPACE;
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
box.width = L_MAINTEXT_SPACE + L_TEXT_SPACE
|
||||
+ textlen
|
||||
+ R_TEXT_SPACE + R_MAINTEXT_SPACE;
|
||||
|
||||
draw_box(term, &box, ' ', 0, color);
|
||||
set_cursor(term, p, 0, 1);
|
||||
set_window_ptr(menu->win, p, 1);
|
||||
@ -1034,7 +1152,7 @@ display_mainmenu(struct terminal *term, struct menu *menu)
|
||||
color);
|
||||
}
|
||||
|
||||
p += textlen;
|
||||
p += screencnt;
|
||||
|
||||
if (p >= term->width - R_MAINMENU_SPACE)
|
||||
break;
|
||||
@ -1045,6 +1163,22 @@ display_mainmenu(struct terminal *term, struct menu *menu)
|
||||
menu->last = i - 1;
|
||||
int_lower_bound(&menu->last, menu->first);
|
||||
if (menu->last < menu->size - 1) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
struct screen_char *schar;
|
||||
|
||||
schar = get_char(term, term->width - R_MAINMENU_SPACE, 0);
|
||||
/* Is second cell of double-width char on the place where
|
||||
* first char of the R_MAINMENU_SPACE will be displayed? */
|
||||
if (schar->data == UCS_NO_CHAR) {
|
||||
/* Replace double-width char with ' '. */
|
||||
schar++;
|
||||
draw_char_data(term, term->width - R_MAINMENU_SPACE - 1,
|
||||
0, ' ');
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
set_box(&box,
|
||||
term->width - R_MAINMENU_SPACE, 0,
|
||||
R_MAINMENU_SPACE, 1);
|
||||
|
128
src/bfu/text.c
128
src/bfu/text.c
@ -19,6 +19,7 @@
|
||||
#include "terminal/terminal.h"
|
||||
#include "util/color.h"
|
||||
|
||||
/* FIXME: For UTF-8 strings we need better function than isspace. */
|
||||
#define is_unsplitable(pos) (*(pos) && *(pos) != '\n' && !isspace(*(pos)))
|
||||
|
||||
void
|
||||
@ -35,48 +36,107 @@ add_dlg_text(struct dialog *dlg, unsigned char *text,
|
||||
}
|
||||
|
||||
/* Returns length of substring (from start of @text) before a split. */
|
||||
#ifdef CONFIG_UTF_8
|
||||
static inline int
|
||||
split_line(unsigned char *text, int max_width)
|
||||
split_line(unsigned char *text, int max_width, int *cells, int utf8)
|
||||
#else
|
||||
static inline int
|
||||
split_line(unsigned char *text, int max_width, int *cells)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
unsigned char *split = text;
|
||||
int cells_save = *cells;
|
||||
|
||||
if (max_width <= 0) return 0;
|
||||
|
||||
while (*split && *split != '\n') {
|
||||
unsigned char *next_split = split + 1;
|
||||
unsigned char *next_split;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (utf8) {
|
||||
unsigned char *next_char_begin = split
|
||||
+ utf8charlen(split);
|
||||
|
||||
next_split = split;
|
||||
|
||||
*cells += utf8_char2cells(split, NULL);
|
||||
while (*next_split && next_split != next_char_begin)
|
||||
next_split++;
|
||||
|
||||
next_char_begin = next_split;
|
||||
while (is_unsplitable(next_split))
|
||||
{
|
||||
if (next_split < next_char_begin) {
|
||||
next_split++;
|
||||
continue;
|
||||
}
|
||||
*cells += utf8_char2cells(next_split, NULL);
|
||||
next_char_begin += utf8charlen(next_split);
|
||||
}
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
next_split = split + 1;
|
||||
|
||||
while (is_unsplitable(next_split))
|
||||
next_split++;
|
||||
*cells = next_split - text;
|
||||
}
|
||||
|
||||
if (next_split - text > max_width) {
|
||||
if (*cells > max_width) {
|
||||
/* Force a split if no position was found yet,
|
||||
* meaning there's no splittable substring under
|
||||
* requested width. */
|
||||
if (split == text) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (utf8) {
|
||||
int m_bytes = utf8_cells2bytes(text,
|
||||
max_width,
|
||||
NULL);
|
||||
split = &text[m_bytes];
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
split = &text[max_width];
|
||||
|
||||
/* Give preference to split on a punctuation
|
||||
* if any. Note that most of the time
|
||||
* punctuation char is followed by a space so
|
||||
* this rule will not match often.
|
||||
* We match dash and quotes too. */
|
||||
|
||||
/* FIXME: Function ispunct won't work correctly
|
||||
* with UTF-8 characters. We need some similar
|
||||
* function for UTF-8 characters. */
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (!utf8)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
/* Give preference to split on a
|
||||
* punctuation if any. Note that most
|
||||
* of the time punctuation char is
|
||||
* followed by a space so this rule
|
||||
* will not match often. We match dash
|
||||
* and quotes too. */
|
||||
cells_save--;
|
||||
while (--split != text) {
|
||||
cells_save--;
|
||||
if (!ispunct(*split)) continue;
|
||||
split++;
|
||||
cells_save++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no way to do a clean split, just return
|
||||
* requested maximal width. */
|
||||
if (split == text)
|
||||
if (split == text) {
|
||||
*cells = max_width;
|
||||
return max_width;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
cells_save = *cells;
|
||||
split = next_split;
|
||||
}
|
||||
|
||||
*cells = cells_save;
|
||||
return split - text;
|
||||
}
|
||||
|
||||
@ -86,8 +146,13 @@ split_line(unsigned char *text, int max_width)
|
||||
#define realloc_lines(x, o, n) mem_align_alloc(x, o, n, LINES_GRANULARITY)
|
||||
|
||||
/* Find the start of each line with the current max width */
|
||||
#ifdef CONFIG_UTF_8
|
||||
static unsigned char **
|
||||
split_lines(struct widget_data *widget_data, int max_width, int utf8)
|
||||
#else
|
||||
static unsigned char **
|
||||
split_lines(struct widget_data *widget_data, int max_width)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
unsigned char *text = widget_data->widget->text;
|
||||
unsigned char **lines = (unsigned char **) widget_data->cdata;
|
||||
@ -100,19 +165,27 @@ split_lines(struct widget_data *widget_data, int max_width)
|
||||
|
||||
while (*text) {
|
||||
int width;
|
||||
int cells = 0;
|
||||
|
||||
/* Skip first leading \n or space. */
|
||||
if (isspace(*text)) text++;
|
||||
if (!*text) break;
|
||||
|
||||
width = split_line(text, max_width);
|
||||
#ifdef CONFIG_UTF_8
|
||||
width = split_line(text, max_width, &cells, utf8);
|
||||
#else
|
||||
width = split_line(text, max_width, &cells);
|
||||
#endif
|
||||
|
||||
/* split_line() may return 0. */
|
||||
if (width < 1) {
|
||||
width = 1; /* Infinite loop prevention. */
|
||||
}
|
||||
if (cells < 1) {
|
||||
cells = 1; /* Infinite loop prevention. */
|
||||
}
|
||||
|
||||
int_lower_bound(&widget_data->box.width, width);
|
||||
int_lower_bound(&widget_data->box.width, cells);
|
||||
|
||||
if (!realloc_lines(&lines, line, line + 1))
|
||||
break;
|
||||
@ -134,13 +207,15 @@ split_lines(struct widget_data *widget_data, int max_width)
|
||||
void
|
||||
dlg_format_text_do(struct terminal *term, unsigned char *text,
|
||||
int x, int *y, int width, int *real_width,
|
||||
struct color_pair *color, enum format_align align)
|
||||
struct color_pair *color, enum format_align align,
|
||||
int format_only)
|
||||
{
|
||||
int line_width;
|
||||
int firstline = 1;
|
||||
|
||||
for (; *text; text += line_width, (*y)++) {
|
||||
int shift;
|
||||
int cells = 0;
|
||||
|
||||
/* Skip first leading \n or space. */
|
||||
if (!firstline && isspace(*text))
|
||||
@ -149,7 +224,11 @@ dlg_format_text_do(struct terminal *term, unsigned char *text,
|
||||
firstline = 0;
|
||||
if (!*text) break;
|
||||
|
||||
line_width = split_line(text, width);
|
||||
#ifdef CONFIG_UTF_8
|
||||
line_width = split_line(text, width, &cells, term->utf8);
|
||||
#else
|
||||
line_width = split_line(text, width, &cells);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
/* split_line() may return 0. */
|
||||
if (line_width < 1) {
|
||||
@ -157,18 +236,18 @@ dlg_format_text_do(struct terminal *term, unsigned char *text,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (real_width) int_lower_bound(real_width, line_width);
|
||||
if (!term || !line_width) continue;
|
||||
if (real_width) int_lower_bound(real_width, cells);
|
||||
if (format_only || !line_width) continue;
|
||||
|
||||
/* Calculate the number of chars to indent */
|
||||
if (align == ALIGN_CENTER)
|
||||
shift = (width - line_width) / 2;
|
||||
shift = (width - cells) / 2;
|
||||
else if (align == ALIGN_RIGHT)
|
||||
shift = width - line_width;
|
||||
shift = width - cells;
|
||||
else
|
||||
shift = 0;
|
||||
|
||||
assert(line_width <= width && shift < width);
|
||||
assert(cells <= width && shift < width);
|
||||
|
||||
draw_text(term, x + shift, *y, text, line_width, 0, color);
|
||||
}
|
||||
@ -176,7 +255,8 @@ dlg_format_text_do(struct terminal *term, unsigned char *text,
|
||||
|
||||
void
|
||||
dlg_format_text(struct terminal *term, struct widget_data *widget_data,
|
||||
int x, int *y, int width, int *real_width, int max_height)
|
||||
int x, int *y, int width, int *real_width, int max_height,
|
||||
int format_only)
|
||||
{
|
||||
unsigned char *text = widget_data->widget->text;
|
||||
unsigned char saved = 0;
|
||||
@ -202,9 +282,15 @@ dlg_format_text(struct terminal *term, struct widget_data *widget_data,
|
||||
|
||||
/* Ensure that the current split is valid but don't
|
||||
* split if we don't have to */
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (widget_data->box.width != width
|
||||
&& !split_lines(widget_data, width, term->utf8))
|
||||
return;
|
||||
#else
|
||||
if (widget_data->box.width != width
|
||||
&& !split_lines(widget_data, width))
|
||||
return;
|
||||
#endif
|
||||
|
||||
lines = (unsigned char **) widget_data->cdata;
|
||||
|
||||
@ -246,7 +332,7 @@ dlg_format_text(struct terminal *term, struct widget_data *widget_data,
|
||||
dlg_format_text_do(term, text,
|
||||
x, y, width, real_width,
|
||||
get_bfu_color(term, "dialog.text"),
|
||||
widget_data->widget->info.text.align);
|
||||
widget_data->widget->info.text.align, format_only);
|
||||
|
||||
if (widget_data->widget->info.text.is_label) (*y)--;
|
||||
|
||||
@ -333,7 +419,7 @@ format_and_display_text(struct widget_data *widget_data,
|
||||
|
||||
dlg_format_text(term, widget_data,
|
||||
widget_data->box.x, &y, widget_data->box.width, NULL,
|
||||
height);
|
||||
height, 0);
|
||||
|
||||
display_text(dlg_data, widget_data);
|
||||
redraw_from_window(dlg_data->win);
|
||||
|
@ -47,11 +47,11 @@ void add_dlg_text(struct dialog *dlg, unsigned char *text,
|
||||
extern struct widget_ops text_ops;
|
||||
void dlg_format_text_do(struct terminal *term,
|
||||
unsigned char *text, int x, int *y, int w, int *rw,
|
||||
struct color_pair *scolor, enum format_align align);
|
||||
struct color_pair *scolor, enum format_align align, int format_only);
|
||||
|
||||
void
|
||||
dlg_format_text(struct terminal *term, struct widget_data *widget_data,
|
||||
int x, int *y, int dlg_width, int *real_width, int height);
|
||||
int x, int *y, int dlg_width, int *real_width, int height, int format_only);
|
||||
|
||||
#define text_is_scrollable(widget_data) \
|
||||
((widget_data)->widget->info.text.is_scrollable \
|
||||
|
@ -145,6 +145,11 @@ download_dialog_layouter(struct dialog_data *dlg_data)
|
||||
mem_free(msg);
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
decode_uri(url);
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
decode_uri_for_display(url);
|
||||
url_len = strlen(url);
|
||||
|
||||
@ -152,8 +157,8 @@ download_dialog_layouter(struct dialog_data *dlg_data)
|
||||
int_lower_bound(&w, DOWN_DLG_MIN);
|
||||
}
|
||||
|
||||
dlg_format_text_do(NULL, url, 0, &y, w, &rw,
|
||||
dialog_text_color, ALIGN_LEFT);
|
||||
dlg_format_text_do(term, url, 0, &y, w, &rw,
|
||||
dialog_text_color, ALIGN_LEFT, 1);
|
||||
|
||||
y++;
|
||||
if (show_meter) y += 2;
|
||||
@ -161,13 +166,13 @@ download_dialog_layouter(struct dialog_data *dlg_data)
|
||||
#if CONFIG_BITTORRENT
|
||||
if (bittorrent) y += 2;
|
||||
#endif
|
||||
dlg_format_text_do(NULL, msg, 0, &y, w, &rw,
|
||||
dialog_text_color, ALIGN_LEFT);
|
||||
dlg_format_text_do(term, msg, 0, &y, w, &rw,
|
||||
dialog_text_color, ALIGN_LEFT, 1);
|
||||
|
||||
y++;
|
||||
dlg_format_buttons(NULL, dlg_data->widgets_data,
|
||||
dlg_format_buttons(term, dlg_data->widgets_data,
|
||||
dlg_data->number_of_widgets, 0, &y, w,
|
||||
&rw, ALIGN_CENTER);
|
||||
&rw, ALIGN_CENTER, 1);
|
||||
|
||||
draw_dialog(dlg_data, w, y);
|
||||
|
||||
@ -186,7 +191,7 @@ download_dialog_layouter(struct dialog_data *dlg_data)
|
||||
y = dlg_data->box.y + DIALOG_TB + 1;
|
||||
x = dlg_data->box.x + DIALOG_LB;
|
||||
dlg_format_text_do(term, url, x, &y, w, NULL,
|
||||
dialog_text_color, ALIGN_LEFT);
|
||||
dialog_text_color, ALIGN_LEFT, 0);
|
||||
|
||||
if (show_meter) {
|
||||
y++;
|
||||
@ -203,12 +208,12 @@ download_dialog_layouter(struct dialog_data *dlg_data)
|
||||
#endif
|
||||
y++;
|
||||
dlg_format_text_do(term, msg, x, &y, w, NULL,
|
||||
dialog_text_color, ALIGN_LEFT);
|
||||
dialog_text_color, ALIGN_LEFT, 0);
|
||||
|
||||
y++;
|
||||
dlg_format_buttons(term, dlg_data->widgets_data,
|
||||
dlg_data->number_of_widgets, x, &y, w,
|
||||
NULL, ALIGN_CENTER);
|
||||
NULL, ALIGN_CENTER, 0);
|
||||
|
||||
mem_free(url);
|
||||
mem_free(msg);
|
||||
@ -296,7 +301,14 @@ get_file_download_text(struct listbox_item *item, struct terminal *term)
|
||||
unsigned char *uristring;
|
||||
|
||||
uristring = get_uri_string(file_download->uri, URI_PUBLIC);
|
||||
if (uristring) decode_uri_for_display(uristring);
|
||||
if (uristring) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
decode_uri(uristring);
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
decode_uri_for_display(uristring);
|
||||
}
|
||||
|
||||
return uristring;
|
||||
}
|
||||
@ -369,7 +381,7 @@ draw_file_download(struct listbox_item *item, struct listbox_context *context,
|
||||
|
||||
color = get_bfu_color(context->term, stylename);
|
||||
|
||||
text = get_file_download_text(item, NULL);
|
||||
text = get_file_download_text(item, context->term);
|
||||
if (!text) return;
|
||||
|
||||
length = strlen(text);
|
||||
|
@ -581,6 +581,11 @@ query_file(struct session *ses, struct uri *uri, void *data,
|
||||
add_mime_filename_to_string(&def, uri);
|
||||
|
||||
/* Remove the %-ugliness for display */
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (ses->tab->term->utf8)
|
||||
decode_uri_string(&def);
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
decode_uri_string_for_display(&def);
|
||||
|
||||
if (interactive) {
|
||||
|
@ -59,8 +59,10 @@ 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;
|
||||
|
||||
#ifndef CONFIG_UTF_8
|
||||
if (is_cp_utf8(i)) continue;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
items++;
|
||||
add_to_menu(&mi, name, NULL, ACT_MAIN_NONE,
|
||||
|
@ -150,15 +150,8 @@ get_current_link_info_and_title(struct session *ses,
|
||||
|
||||
link_title = get_current_link_title(doc_view);
|
||||
if (link_title) {
|
||||
unsigned char *src;
|
||||
|
||||
assert(*link_title);
|
||||
|
||||
/* Remove illicit chars. */
|
||||
for (src = link_title; *src; src++)
|
||||
if (!isprint(*src) || iscntrl(*src))
|
||||
*src = '*';
|
||||
|
||||
ret = straconcat(link_info, " - ", link_title, NULL);
|
||||
mem_free(link_info);
|
||||
mem_free(link_title);
|
||||
@ -424,11 +417,25 @@ display_title_bar(struct session *ses, struct terminal *term)
|
||||
|
||||
if (document->title) {
|
||||
int maxlen = int_max(term->width - 4 - buflen, 0);
|
||||
int titlelen = int_min(strlen(document->title), maxlen);
|
||||
int titlelen, titlewidth;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
titlewidth = utf8_ptr2cells(document->title, NULL);
|
||||
titlewidth = int_min(titlewidth, maxlen);
|
||||
|
||||
titlelen = utf8_cells2bytes(document->title,
|
||||
titlewidth, NULL);
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
titlewidth = int_min(strlen(document->title), maxlen);
|
||||
titlelen = titlewidth;
|
||||
}
|
||||
|
||||
add_bytes_to_string(&title, document->title, titlelen);
|
||||
|
||||
if (titlelen == maxlen)
|
||||
if (titlewidth == maxlen)
|
||||
add_bytes_to_string(&title, "...", 3);
|
||||
}
|
||||
|
||||
@ -436,7 +443,16 @@ display_title_bar(struct session *ses, struct terminal *term)
|
||||
add_bytes_to_string(&title, buf, buflen);
|
||||
|
||||
if (title.length) {
|
||||
int x = int_max(term->width - 1 - title.length, 0);
|
||||
int x;
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
x = int_max(term->width - 1
|
||||
- utf8_ptr2cells(title.source,
|
||||
title.source
|
||||
+ title.length), 0);
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
x = int_max(term->width - 1 - title.length, 0);
|
||||
|
||||
draw_text(term, x, 0, title.source, title.length, 0,
|
||||
get_bfu_color(term, "title.title-text"));
|
||||
|
@ -119,8 +119,7 @@ static css_applier_T css_appliers[CSS_PT_LAST] = {
|
||||
static void
|
||||
examine_element(struct html_context *html_context, struct css_selector *base,
|
||||
enum css_selector_type seltype, enum css_selector_relation rel,
|
||||
struct list_head *selectors, struct html_element *element,
|
||||
struct list_head *html_stack)
|
||||
struct list_head *selectors, struct html_element *element)
|
||||
{
|
||||
struct css_selector *selector;
|
||||
unsigned char *code;
|
||||
@ -138,7 +137,8 @@ examine_element(struct html_context *html_context, struct css_selector *base,
|
||||
dbginfo(sel, type, base); \
|
||||
merge_css_selectors(base, sel); \
|
||||
/* Ancestor matches? */ \
|
||||
if ((struct list_head *) element->next != html_stack) { \
|
||||
if ((struct list_head *) element->next \
|
||||
!= &html_context->stack) { \
|
||||
struct html_element *ancestor; \
|
||||
/* This is less effective than doing reverse iterations,
|
||||
* first over sel->leaves and then over the HTML stack,
|
||||
@ -147,21 +147,20 @@ examine_element(struct html_context *html_context, struct css_selector *base,
|
||||
* have to duplicate the whole examine_element(), so if
|
||||
* profiles won't show it really costs... */ \
|
||||
for (ancestor = element->next; \
|
||||
(struct list_head *) ancestor != html_stack;\
|
||||
(struct list_head *) ancestor \
|
||||
!= &html_context->stack;\
|
||||
ancestor = ancestor->next) \
|
||||
examine_element(html_context, base, \
|
||||
CST_ELEMENT, CSR_ANCESTOR, \
|
||||
&sel->leaves, ancestor, \
|
||||
html_stack); \
|
||||
&sel->leaves, ancestor); \
|
||||
examine_element(html_context, base, \
|
||||
CST_ELEMENT, CSR_PARENT, \
|
||||
&sel->leaves, element->next, \
|
||||
html_stack); \
|
||||
&sel->leaves, element->next); \
|
||||
} \
|
||||
/* More specific matches? */ \
|
||||
examine_element(html_context, base, type + 1, \
|
||||
CSR_SPECIFITY, \
|
||||
&sel->leaves, element, html_stack); \
|
||||
&sel->leaves, element); \
|
||||
}
|
||||
|
||||
if (seltype <= CST_ELEMENT && element->namelen) {
|
||||
@ -235,7 +234,7 @@ get_css_selector_for_element(struct html_context *html_context,
|
||||
#endif
|
||||
|
||||
examine_element(html_context, selector, CST_ELEMENT, CSR_ROOT,
|
||||
&css->selectors, element, html_stack);
|
||||
&css->selectors, element);
|
||||
|
||||
#ifdef DEBUG_CSS
|
||||
DBG("Element %.*s applied.", element->namelen, element->name);
|
||||
|
@ -118,13 +118,19 @@ struct link {
|
||||
#define get_link_name(link) \
|
||||
(!link_is_form(link) ? (link)->data.name : NULL)
|
||||
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
struct search {
|
||||
int x, y;
|
||||
signed int n; /* RAM is cheap nowadays */
|
||||
unicode_val_T c;
|
||||
};
|
||||
#else
|
||||
struct search {
|
||||
int x, y;
|
||||
signed int n:24; /* This structure is size-critical */
|
||||
unsigned char c;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
struct document {
|
||||
OBJECT_HEAD(struct document);
|
||||
@ -176,6 +182,10 @@ struct document {
|
||||
struct search **slines1;
|
||||
struct search **slines2;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
unsigned char buf[7];
|
||||
unsigned char buf_length;
|
||||
#endif
|
||||
unsigned int id; /* Used to check cache entries. */
|
||||
|
||||
int cp;
|
||||
|
@ -260,7 +260,12 @@ 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 x;
|
||||
int x, charlen;
|
||||
#ifdef CONFIG_UTF_8
|
||||
int utf8 = document->options.utf8;
|
||||
unsigned char *end;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
|
||||
assert(renderer && template && string && length);
|
||||
|
||||
@ -275,12 +280,15 @@ render_dom_line(struct dom_renderer *renderer, struct screen_char *template,
|
||||
|
||||
add_search_node(renderer, length);
|
||||
|
||||
for (x = 0; x < length; x++, renderer->canvas_x++) {
|
||||
unsigned char data = string[x];
|
||||
#ifdef CONFIG_UTF_8
|
||||
end = string + length;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
for (x = 0, charlen = 1; x < length;x += charlen, renderer->canvas_x++) {
|
||||
unsigned char *text = &string[x];
|
||||
|
||||
/* This is mostly to be able to break out so the indentation
|
||||
* level won't get to high. */
|
||||
switch (data) {
|
||||
switch (*text) {
|
||||
case ASCII_TAB:
|
||||
{
|
||||
int tab_width = 7 - (X(renderer) & 7);
|
||||
@ -295,15 +303,33 @@ render_dom_line(struct dom_renderer *renderer, struct screen_char *template,
|
||||
* ``main loop'' add the actual tab char. */
|
||||
for (; tab_width-- > 0; renderer->canvas_x++)
|
||||
copy_screen_chars(POS(renderer), template, 1);
|
||||
charlen = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
template->data = isscreensafe(data) ? data : '.';
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (utf8) {
|
||||
unicode_val_T data;
|
||||
charlen = utf8charlen(text);
|
||||
data = utf_8_to_unicode(&text, end);
|
||||
|
||||
template->data = (unicode_val_T)data;
|
||||
|
||||
if (unicode_to_cell(data) == 2) {
|
||||
copy_screen_chars(POS(renderer),
|
||||
template, 1);
|
||||
|
||||
X(renderer)++;
|
||||
template->data = UCS_NO_CHAR;
|
||||
}
|
||||
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
template->data = isscreensafe(*text) ? *text:'.';
|
||||
}
|
||||
|
||||
copy_screen_chars(POS(renderer), template, 1);
|
||||
}
|
||||
|
||||
mem_free(string);
|
||||
}
|
||||
|
||||
@ -1024,6 +1050,9 @@ render_dom_document(struct cache_entry *cached, struct document *document,
|
||||
init_dom_renderer(&renderer, document, buffer, convert_table);
|
||||
|
||||
document->bgcolor = document->options.default_bg;
|
||||
#ifdef CONFIG_UTF_8
|
||||
document->options.utf8 = is_cp_utf8(document->options.cp);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
if (document->options.plain)
|
||||
parser_type = SGML_PARSER_STREAM;
|
||||
|
@ -495,6 +495,12 @@ end_parse:
|
||||
max_width = 0;
|
||||
for (i = 0; i < order; i++) {
|
||||
if (!labels[i]) continue;
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (html_context->options->utf8)
|
||||
int_lower_bound(&max_width,
|
||||
utf8_ptr2cells(labels[i], NULL));
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
int_lower_bound(&max_width, strlen(labels[i]));
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
@ -209,6 +210,10 @@ realloc_spaces(struct part *part, int length)
|
||||
|
||||
if (!ALIGN_SPACES(&part->spaces, part->spaces_len, length))
|
||||
return -1;
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (!ALIGN_SPACES(&part->char_width, part->spaces_len, length))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
part->spaces_len = length;
|
||||
|
||||
@ -374,6 +379,155 @@ get_format_screen_char(struct html_context *html_context,
|
||||
return &schar_cache;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
/* First possibly do the format change and then find out what coordinates
|
||||
* to use since sub- or superscript might change them */
|
||||
static inline int
|
||||
set_hline(struct html_context *html_context, unsigned char *chars, int charslen,
|
||||
enum link_state link_state)
|
||||
{
|
||||
struct part *part = html_context->part;
|
||||
struct screen_char *schar = get_format_screen_char(html_context,
|
||||
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 len;
|
||||
|
||||
assert(charslen >= 0);
|
||||
|
||||
if (realloc_spaces(part, x + charslen))
|
||||
return 0;
|
||||
|
||||
if (part->document) {
|
||||
if (realloc_line(html_context, part->document,
|
||||
Y(y), X(x) + charslen - 1))
|
||||
return 0;
|
||||
if (utf8) {
|
||||
unsigned char *end = chars + charslen;
|
||||
unicode_val_T data;
|
||||
|
||||
if (part->document->buf_length) {
|
||||
/* previous char was broken in the middle */
|
||||
int length = utf8charlen(part->document->buf);
|
||||
unsigned char i;
|
||||
unsigned char *buf_ptr = part->document->buf;
|
||||
|
||||
for (i = part->document->buf_length; i < length && chars < end;) {
|
||||
part->document->buf[i++] = *chars++;
|
||||
}
|
||||
part->document->buf_length = i;
|
||||
part->document->buf[i] = '\0';
|
||||
data = utf_8_to_unicode(&buf_ptr, buf_ptr + i);
|
||||
if (data != UCS_NO_CHAR) {
|
||||
part->document->buf_length = 0;
|
||||
goto good_char;
|
||||
} else {
|
||||
/* Still not full char */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (; chars < end; x++) {
|
||||
if (*chars == NBSP_CHAR) {
|
||||
schar->data = ' ';
|
||||
part->spaces[x] = html_context->options->wrap_nbsp;
|
||||
part->char_width[x] = 1;
|
||||
chars++;
|
||||
} else {
|
||||
part->spaces[x] = (*chars == ' ');
|
||||
data = utf_8_to_unicode(&chars, end);
|
||||
if (data == UCS_NO_CHAR) {
|
||||
if (charslen == 1) {
|
||||
/* 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;
|
||||
part->char_width[x] = 0;
|
||||
continue;
|
||||
} else {
|
||||
unsigned char i;
|
||||
broken_char: /* broken char */
|
||||
for (i = 0; chars < end;i++) {
|
||||
part->document->buf[i] = *chars++;
|
||||
}
|
||||
part->document->buf_length = i;
|
||||
return x - x2;
|
||||
}
|
||||
} else {
|
||||
good_char:
|
||||
if (unicode_to_cell(data) == 2) {
|
||||
schar->data = (unicode_val_T)data;
|
||||
part->char_width[x] = 2;
|
||||
copy_screen_chars(&POS(x++, y), schar, 1);
|
||||
data = utf_8_to_unicode(&chars, end);
|
||||
if (data == UCS_NO_CHAR) goto broken_char;
|
||||
schar->data = (unicode_val_T)data;
|
||||
part->spaces[x] = 0;
|
||||
part->char_width[x] = 0;
|
||||
} else {
|
||||
part->char_width[x] = unicode_to_cell(data);
|
||||
schar->data = (unicode_val_T)data;
|
||||
}
|
||||
}
|
||||
}
|
||||
copy_screen_chars(&POS(x, y), schar, 1);
|
||||
}
|
||||
} else {
|
||||
for (; charslen > 0; charslen--, x++, chars++) {
|
||||
part->char_width[x] = 1;
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
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);
|
||||
part->char_width[x] = unicode_to_cell(data);
|
||||
if (part->char_width[x] == 2) {
|
||||
x++;
|
||||
part->spaces[x] = 0;
|
||||
part->char_width[x] = 0;
|
||||
data = utf_8_to_unicode(&chars, end);
|
||||
}
|
||||
if (data == UCS_NO_CHAR) {
|
||||
/* this is at the end only */
|
||||
return x - x2;
|
||||
}
|
||||
}
|
||||
len = x - x2;
|
||||
} else {
|
||||
for (; charslen > 0; charslen--, x++, chars++) {
|
||||
part->spaces[x] = (*chars == ' ');
|
||||
part->char_width[x] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
#else
|
||||
|
||||
/* First possibly do the format change and then find out what coordinates
|
||||
* to use since sub- or superscript might change them */
|
||||
static inline void
|
||||
@ -405,7 +559,6 @@ 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);
|
||||
}
|
||||
} else {
|
||||
@ -414,6 +567,7 @@ set_hline(struct html_context *html_context, unsigned char *chars, int charslen,
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
static void
|
||||
move_links(struct html_context *html_context, int xf, int yf, int xt, int yt)
|
||||
@ -645,29 +799,53 @@ split_line_at(struct html_context *html_context, int width)
|
||||
if (part->document) {
|
||||
assert(part->document->data);
|
||||
if_assert_failed return 0;
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (html_context->options->utf8
|
||||
&& width < part->spaces_len && part->char_width[width] == 2) {
|
||||
move_chars(html_context, width, part->cy, par_format.leftmargin, part->cy + 1);
|
||||
del_chars(html_context, width, part->cy);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
assertm(POS(width, part->cy).data == ' ',
|
||||
"bad split: %c", POS(width, part->cy).data);
|
||||
move_chars(html_context, width + 1, part->cy, par_format.leftmargin, part->cy + 1);
|
||||
del_chars(html_context, width, part->cy);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (!(html_context->options->utf8
|
||||
&& width < part->spaces_len
|
||||
&& part->char_width[width] == 2))
|
||||
#endif
|
||||
width++; /* Since we were using (x + 1) only later... */
|
||||
|
||||
tmp = part->spaces_len - width;
|
||||
if (tmp > 0) {
|
||||
/* 0 is possible and I'm paranoid ... --Zas */
|
||||
memmove(part->spaces, part->spaces + width, tmp);
|
||||
#ifdef CONFIG_UTF_8
|
||||
memmove(part->char_width, part->char_width + width, tmp);
|
||||
#endif
|
||||
}
|
||||
|
||||
assert(tmp >= 0);
|
||||
if_assert_failed tmp = 0;
|
||||
memset(part->spaces + tmp, 0, width);
|
||||
#ifdef CONFIG_UTF_8
|
||||
memset(part->char_width + tmp, 0, width);
|
||||
#endif
|
||||
|
||||
if (par_format.leftmargin > 0) {
|
||||
tmp = part->spaces_len - par_format.leftmargin;
|
||||
assertm(tmp > 0, "part->spaces_len - par_format.leftmargin == %d", tmp);
|
||||
/* So tmp is zero, memmove() should survive that. Don't recover. */
|
||||
memmove(part->spaces + par_format.leftmargin, part->spaces, tmp);
|
||||
#ifdef CONFIG_UTF_8
|
||||
memmove(part->char_width + par_format.leftmargin, part->char_width, tmp);
|
||||
#endif
|
||||
}
|
||||
|
||||
part->cy++;
|
||||
@ -705,6 +883,30 @@ split_line(struct html_context *html_context)
|
||||
assert(part);
|
||||
if_assert_failed return 0;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (html_context->options->utf8) {
|
||||
for (x = overlap(par_format); x >= par_format.leftmargin; x--) {
|
||||
|
||||
if (x < part->spaces_len && (part->spaces[x]
|
||||
|| (part->char_width[x] == 2
|
||||
/* Ugly hack. If we haven't place for
|
||||
* double-width characters we print two
|
||||
* double-width characters. */
|
||||
&& x != par_format.leftmargin)))
|
||||
return split_line_at(html_context, x);
|
||||
}
|
||||
|
||||
for (x = par_format.leftmargin; x < part->cx ; x++) {
|
||||
if (x < part->spaces_len && (part->spaces[x]
|
||||
|| (part->char_width[x] == 2
|
||||
/* We want to break line after _second_
|
||||
* double-width character. */
|
||||
&& x > par_format.leftmargin)))
|
||||
return split_line_at(html_context, x);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
for (x = overlap(par_format); x >= par_format.leftmargin; x--)
|
||||
if (x < part->spaces_len && part->spaces[x])
|
||||
return split_line_at(html_context, x);
|
||||
@ -712,6 +914,7 @@ split_line(struct html_context *html_context)
|
||||
for (x = par_format.leftmargin; x < part->cx ; x++)
|
||||
if (x < part->spaces_len && part->spaces[x])
|
||||
return split_line_at(html_context, x);
|
||||
}
|
||||
|
||||
/* Make sure that we count the right margin to the total
|
||||
* actual box width. */
|
||||
@ -1140,9 +1343,15 @@ done_link_state_info(void)
|
||||
sizeof(renderer_context.link_state_info));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
static inline void
|
||||
process_link(struct html_context *html_context, enum link_state link_state,
|
||||
unsigned char *chars, int charslen, int cells)
|
||||
#else
|
||||
static inline void
|
||||
process_link(struct html_context *html_context, enum link_state link_state,
|
||||
unsigned char *chars, int charslen)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
struct part *part = html_context->part;
|
||||
struct link *link;
|
||||
@ -1194,6 +1403,9 @@ process_link(struct html_context *html_context, enum link_state link_state,
|
||||
if (x_offset) {
|
||||
charslen -= x_offset;
|
||||
chars += x_offset;
|
||||
#ifdef CONFIG_UTF_8
|
||||
cells -= x_offset;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
}
|
||||
|
||||
link = new_link(html_context, chars, charslen);
|
||||
@ -1208,14 +1420,26 @@ 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)) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (realloc_points(link, link->npoints + cells))
|
||||
#else
|
||||
if (realloc_points(link, link->npoints + charslen))
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
struct point *point = &link->points[link->npoints];
|
||||
int x = X(part->cx) + x_offset;
|
||||
int y = Y(part->cy);
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
link->npoints += cells;
|
||||
|
||||
for (; cells > 0; cells--, point++, x++)
|
||||
#else
|
||||
link->npoints += charslen;
|
||||
|
||||
for (; charslen > 0; charslen--, point++, x++) {
|
||||
for (; charslen > 0; charslen--, point++, x++)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
point->x = x;
|
||||
point->y = y;
|
||||
}
|
||||
@ -1266,6 +1490,9 @@ put_chars(struct html_context *html_context, unsigned char *chars, int charslen)
|
||||
{
|
||||
enum link_state link_state;
|
||||
struct part *part;
|
||||
#ifdef CONFIG_UTF_8
|
||||
int cells;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
assert(html_context);
|
||||
if_assert_failed return;
|
||||
@ -1324,18 +1551,55 @@ put_chars(struct html_context *html_context, unsigned char *chars, int charslen)
|
||||
else if (html_context->options->links_numbering)
|
||||
put_link_number(html_context);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
cells =
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
set_hline(html_context, chars, charslen, link_state);
|
||||
|
||||
if (link_state != LINK_STATE_NONE) {
|
||||
process_link(html_context, link_state, chars, charslen);
|
||||
#if 0
|
||||
/* This all code is from utf8 branch */
|
||||
#define is_drawing_subs_or_sups() \
|
||||
((format.style.attr & AT_SUBSCRIPT \
|
||||
&& html_context->options->display_subs) \
|
||||
|| (format.style.attr & AT_SUPERSCRIPT \
|
||||
&& html_context->options->display_sups))
|
||||
|
||||
/* We need to update the current @link_state because <sub> and
|
||||
* <sup> tags will output to the canvas using an inner
|
||||
* put_chars() call which results in their process_link() call
|
||||
* will ``update'' the @link_state. */
|
||||
if (link_state == LINK_STATE_NEW
|
||||
&& (is_drawing_subs_or_sups()
|
||||
|| update_after_subscript != renderer_context.subscript)) {
|
||||
link_state = get_link_state(html_context);
|
||||
}
|
||||
|
||||
#undef is_drawing_subs_or_sups
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
process_link(html_context, link_state, chars, charslen,
|
||||
cells);
|
||||
#else
|
||||
process_link(html_context, link_state, chars, charslen);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (renderer_context.nowrap
|
||||
&& part->cx + cells > overlap(par_format))
|
||||
return;
|
||||
|
||||
part->cx += cells;
|
||||
#else
|
||||
if (renderer_context.nowrap
|
||||
&& part->cx + charslen > overlap(par_format))
|
||||
return;
|
||||
|
||||
part->cx += charslen;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
renderer_context.nobreak = 0;
|
||||
|
||||
if (!(html_context->options->wrap || html_is_preformatted())) {
|
||||
@ -1351,7 +1615,11 @@ put_chars(struct html_context *html_context, unsigned char *chars, int charslen)
|
||||
}
|
||||
|
||||
assert(charslen > 0);
|
||||
#ifdef CONFIG_UTF_8
|
||||
part->xa += cells;
|
||||
#else
|
||||
part->xa += charslen;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
int_lower_bound(&part->max_width, part->xa
|
||||
+ par_format.leftmargin + par_format.rightmargin
|
||||
- (chars[charslen - 1] == ' '
|
||||
@ -1410,6 +1678,9 @@ end:
|
||||
part->cx = -1;
|
||||
part->xa = 0;
|
||||
memset(part->spaces, 0, part->spaces_len);
|
||||
#ifdef CONFIG_UTF_8
|
||||
memset(part->char_width, 0, part->spaces_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1829,6 +2100,9 @@ format_html_part(struct html_context *html_context,
|
||||
|
||||
done_link_state_info();
|
||||
mem_free_if(part->spaces);
|
||||
#ifdef CONFIG_UTF_8
|
||||
mem_free_if(part->char_width);
|
||||
#endif
|
||||
|
||||
if (document) {
|
||||
struct node *node = document->nodes.next;
|
||||
@ -1912,6 +2186,9 @@ render_html_document(struct cache_entry *cached, struct document *document,
|
||||
&document->cp,
|
||||
&document->cp_status,
|
||||
document->options.hard_assume);
|
||||
#ifdef CONFIG_UTF_8
|
||||
html_context->options->utf8 = is_cp_utf8(document->options.cp);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
if (title.length) {
|
||||
document->title = convert_string(renderer_context.convert_table,
|
||||
|
@ -23,6 +23,10 @@ struct part {
|
||||
|
||||
unsigned char *spaces;
|
||||
int spaces_len;
|
||||
#ifdef CONFIG_UTF_8
|
||||
unsigned char *char_width;
|
||||
#endif
|
||||
|
||||
|
||||
struct box box;
|
||||
|
||||
|
@ -101,6 +101,9 @@ struct document_options {
|
||||
unsigned int no_cache:1;
|
||||
unsigned int gradual_rerendering:1;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
unsigned int utf8:1;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
/* Active link coloring */
|
||||
/* This is mostly here to make use of this option cache so link
|
||||
* drawing is faster. --jonas */
|
||||
|
@ -175,12 +175,12 @@ get_uri_length(unsigned char *line, int length)
|
||||
static int
|
||||
print_document_link(struct plain_renderer *renderer, int lineno,
|
||||
unsigned char *line, int line_pos, int width,
|
||||
int expanded, struct screen_char *pos)
|
||||
int expanded, struct screen_char *pos, int cells)
|
||||
{
|
||||
struct document *document = renderer->document;
|
||||
unsigned char *start = &line[line_pos];
|
||||
int len = get_uri_length(start, width - line_pos);
|
||||
int screen_column = line_pos + expanded;
|
||||
int screen_column = cells + expanded;
|
||||
struct link *new_link;
|
||||
int link_end = line_pos + len;
|
||||
unsigned char saved_char;
|
||||
@ -226,209 +226,6 @@ print_document_link(struct plain_renderer *renderer, int lineno,
|
||||
return len;
|
||||
}
|
||||
|
||||
enum mode_16_256 {
|
||||
COLOR_NONE,
|
||||
COLOR_16_FOREGROUND,
|
||||
COLOR_16_BACKGROUND,
|
||||
COLOR_38,
|
||||
COLOR_48,
|
||||
COLOR_256_FOREGROUND,
|
||||
COLOR_256_BACKGROUND
|
||||
};
|
||||
|
||||
static int
|
||||
change_colors(struct screen_char *template, unsigned char *line, int line_pos, int width, struct document *document)
|
||||
{
|
||||
unsigned char fg, bg, bold;
|
||||
enum mode_16_256 color = COLOR_NONE;
|
||||
unsigned char value = 0;
|
||||
int start = 0;
|
||||
|
||||
#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS)
|
||||
fg = template->color[0];
|
||||
bg = template->color[1];
|
||||
#else
|
||||
fg = template->color[0] & 15;
|
||||
bg = template->color[0] >> 4;
|
||||
#endif
|
||||
bold = template->attr & SCREEN_ATTR_BOLD;
|
||||
for (; line_pos < width; line_pos++) {
|
||||
unsigned char ch = line[line_pos];
|
||||
|
||||
switch (color) {
|
||||
case COLOR_NONE:
|
||||
switch (ch) {
|
||||
case '0':
|
||||
bold = 0;
|
||||
break;
|
||||
case '1':
|
||||
bold = SCREEN_ATTR_BOLD;
|
||||
break;
|
||||
case '3':
|
||||
color = COLOR_16_FOREGROUND;
|
||||
break;
|
||||
case '4':
|
||||
color = COLOR_16_BACKGROUND;
|
||||
break;
|
||||
case 'm':
|
||||
goto end;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case COLOR_16_FOREGROUND:
|
||||
switch (ch) {
|
||||
case '9':
|
||||
fg = 7;
|
||||
color = COLOR_NONE;
|
||||
break;
|
||||
case '8':
|
||||
color = COLOR_38;
|
||||
break;
|
||||
case 'm':
|
||||
goto end;
|
||||
default:
|
||||
if (ch >= '0' && ch <= '7') fg = ch - '0';
|
||||
else goto end;
|
||||
color = COLOR_NONE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case COLOR_16_BACKGROUND:
|
||||
switch (ch) {
|
||||
case '9':
|
||||
bg = 0;
|
||||
color = COLOR_NONE;
|
||||
break;
|
||||
case '8':
|
||||
color = COLOR_48;
|
||||
break;
|
||||
case 'm':
|
||||
goto end;
|
||||
default:
|
||||
if (ch >= '0' && ch <= '7') bg = ch - '0';
|
||||
else goto end;
|
||||
color = COLOR_NONE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case COLOR_38:
|
||||
switch (ch) {
|
||||
case '5':
|
||||
start = 1;
|
||||
value = 0;
|
||||
color = COLOR_256_FOREGROUND;
|
||||
break;
|
||||
case 'm':
|
||||
goto end;
|
||||
case ';':
|
||||
break;
|
||||
default:
|
||||
color = COLOR_NONE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case COLOR_48:
|
||||
switch (ch) {
|
||||
case '5':
|
||||
start = 1;
|
||||
value = 0;
|
||||
color = COLOR_256_BACKGROUND;
|
||||
break;
|
||||
case 'm':
|
||||
goto end;
|
||||
case ';':
|
||||
break;
|
||||
default:
|
||||
color = COLOR_NONE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case COLOR_256_FOREGROUND:
|
||||
switch (ch) {
|
||||
case ';':
|
||||
case 'm':
|
||||
if (start) {
|
||||
start = 0;
|
||||
value = 0;
|
||||
} else {
|
||||
#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS)
|
||||
#ifdef CONFIG_88_COLORS
|
||||
if (document->options.color_mode == COLOR_MODE_88) fg = value;
|
||||
#endif
|
||||
#ifdef CONFIG_256_COLORS
|
||||
if (document->options.color_mode == COLOR_MODE_256) fg = value;
|
||||
#endif
|
||||
#endif
|
||||
color = COLOR_NONE;
|
||||
value = 0;
|
||||
}
|
||||
if (ch == 'm') goto end;
|
||||
break;
|
||||
default:
|
||||
if (ch >= '0' && ch <= '9') value *= 10 + ch - '0';
|
||||
else goto end;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case COLOR_256_BACKGROUND:
|
||||
switch (ch) {
|
||||
case ';':
|
||||
case 'm':
|
||||
if (start) {
|
||||
start = 0;
|
||||
value = 0;
|
||||
} else {
|
||||
#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS)
|
||||
#ifdef CONFIG_88_COLORS
|
||||
if (document->options.color_mode == COLOR_MODE_88) bg = value;
|
||||
#endif
|
||||
#ifdef CONFIG_256_COLORS
|
||||
if (document->options.color_mode == COLOR_MODE_256) bg = value;
|
||||
#endif
|
||||
#endif
|
||||
color = COLOR_NONE;
|
||||
value = 0;
|
||||
}
|
||||
if (ch == 'm') goto end;
|
||||
break;
|
||||
default:
|
||||
if (ch >= '0' && ch <= '9') value *= 10 + ch - '0';
|
||||
else goto end;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
end:
|
||||
#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS)
|
||||
#ifdef CONFIG_88_COLORS
|
||||
if (document->options.color_mode == COLOR_MODE_88) {
|
||||
TERM_COLOR_FOREGROUND(template->color) = fg;
|
||||
TERM_COLOR_BACKGROUND(template->color) = bg;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_256_COLORS
|
||||
if (document->options.color_mode == COLOR_MODE_256) {
|
||||
TERM_COLOR_FOREGROUND(template->color) = fg;
|
||||
TERM_COLOR_BACKGROUND(template->color) = bg;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (document->options.color_mode == COLOR_MODE_16) {
|
||||
fg |= bold;
|
||||
set_term_color16(template, document->options.color_flags, fg, bg);
|
||||
}
|
||||
return line_pos;
|
||||
}
|
||||
|
||||
static inline int
|
||||
add_document_line(struct plain_renderer *renderer,
|
||||
unsigned char *line, int line_width)
|
||||
@ -437,6 +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;
|
||||
#ifdef CONFIG_UTF_8
|
||||
int utf8 = document->options.utf8;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
int cells = 0;
|
||||
int lineno = renderer->lineno;
|
||||
int expanded = 0;
|
||||
int width = line_width;
|
||||
@ -448,13 +249,31 @@ add_document_line(struct plain_renderer *renderer,
|
||||
if (!line) return 0;
|
||||
|
||||
/* Now expand tabs */
|
||||
for (line_pos = 0; line_pos < width; line_pos++) {
|
||||
for (line_pos = 0; line_pos < width;) {
|
||||
unsigned char line_char = line[line_pos];
|
||||
int charlen = 1;
|
||||
int cell = 1;
|
||||
#ifdef CONFIG_UTF_8
|
||||
unicode_val_T data;
|
||||
|
||||
if (utf8) {
|
||||
unsigned char *line_char2 = &line[line_pos];
|
||||
charlen = utf8charlen(&line_char);
|
||||
data = utf_8_to_unicode(&line_char2, &line[width]);
|
||||
|
||||
if (data == UCS_NO_CHAR) {
|
||||
line_pos += charlen;
|
||||
continue;
|
||||
}
|
||||
|
||||
cell = unicode_to_cell(data);
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
if (line_char == ASCII_TAB
|
||||
&& (line_pos + 1 == width
|
||||
|| line[line_pos + 1] != ASCII_BS)) {
|
||||
int tab_width = 7 - ((line_pos + expanded) & 7);
|
||||
&& (line_pos + charlen == width
|
||||
|| line[line_pos + charlen] != ASCII_BS)) {
|
||||
int tab_width = 7 - ((cells + expanded) & 7);
|
||||
|
||||
expanded += tab_width;
|
||||
} else if (line_char == ASCII_BS) {
|
||||
@ -475,6 +294,8 @@ add_document_line(struct plain_renderer *renderer,
|
||||
expanded--;
|
||||
#endif
|
||||
}
|
||||
line_pos += charlen;
|
||||
cells += cell;
|
||||
}
|
||||
|
||||
assert(expanded >= 0);
|
||||
@ -485,28 +306,55 @@ add_document_line(struct plain_renderer *renderer,
|
||||
return 0;
|
||||
}
|
||||
|
||||
cells = 0;
|
||||
expanded = 0;
|
||||
for (line_pos = 0; line_pos < width; line_pos++) {
|
||||
for (line_pos = 0; line_pos < width;) {
|
||||
unsigned char line_char = line[line_pos];
|
||||
unsigned char next_char, prev_char;
|
||||
int charlen = 1;
|
||||
int cell = 1;
|
||||
#ifdef CONFIG_UTF_8
|
||||
unicode_val_T data;
|
||||
|
||||
prev_char = line_pos > 0 ? line[line_pos - 1] : '\0';
|
||||
next_char = (line_pos + 1 < width) ? line[line_pos + 1]
|
||||
: '\0';
|
||||
if (utf8) {
|
||||
unsigned char *line_char2 = &line[line_pos];
|
||||
charlen = utf8charlen(&line_char);
|
||||
data = utf_8_to_unicode(&line_char2, &line[width]);
|
||||
|
||||
switch (line_char) {
|
||||
case 27:
|
||||
if (next_char != '[') goto normal;
|
||||
line_pos += 2;
|
||||
line_pos = change_colors(&saved_renderer_template, line, line_pos, width, document);
|
||||
*template = saved_renderer_template;
|
||||
break;
|
||||
case ASCII_BS:
|
||||
if (!(expanded + line_pos)) {
|
||||
/* We've backspaced to the start of the line */
|
||||
if (data == UCS_NO_CHAR) {
|
||||
line_pos += charlen;
|
||||
continue;
|
||||
}
|
||||
|
||||
cell = unicode_to_cell(data);
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
prev_char = line_pos > 0 ? line[line_pos - 1] : '\0';
|
||||
next_char = (line_pos + charlen < width) ?
|
||||
line[line_pos + charlen] : '\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 - ((cells + expanded) & 7);
|
||||
|
||||
expanded += tab_width;
|
||||
|
||||
template->data = ' ';
|
||||
do
|
||||
copy_screen_chars(pos++, template, 1);
|
||||
while (tab_width--);
|
||||
|
||||
*template = saved_renderer_template;
|
||||
|
||||
} else if (line_char == ASCII_BS) {
|
||||
#if 0
|
||||
if (!(expanded + cells)) {
|
||||
/* We've backspaced to the start of the line */
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (pos > startpos)
|
||||
pos--; /* Backspace */
|
||||
|
||||
@ -516,8 +364,8 @@ add_document_line(struct plain_renderer *renderer,
|
||||
/* x^H_ becomes _^Hx */
|
||||
if (line_pos - 1 >= 0)
|
||||
line[line_pos - 1] = next_char;
|
||||
if (line_pos + 1 < width)
|
||||
line[line_pos + 1] = prev_char;
|
||||
if (line_pos + charlen < width)
|
||||
line[line_pos + charlen] = prev_char;
|
||||
|
||||
/* Go back and reparse the swapped characters */
|
||||
if (line_pos - 2 >= 0)
|
||||
@ -562,26 +410,7 @@ add_document_line(struct plain_renderer *renderer,
|
||||
/* Handle _^Hx^Hx as both bold and underlined */
|
||||
if (template->attr)
|
||||
template->attr |= pos->attr;
|
||||
break;
|
||||
case ASCII_TAB:
|
||||
/* Do not expand tabs that precede back-spaces; this saves the
|
||||
* back-space code some trouble. */
|
||||
if (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;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
normal:
|
||||
{
|
||||
} else {
|
||||
int added_chars = 0;
|
||||
|
||||
if (document->options.plain_display_links
|
||||
@ -596,28 +425,54 @@ normal:
|
||||
line_pos,
|
||||
width,
|
||||
expanded,
|
||||
pos);
|
||||
pos, cells);
|
||||
}
|
||||
|
||||
if (added_chars) {
|
||||
line_pos += added_chars - 1;
|
||||
pos += added_chars;
|
||||
} else {
|
||||
if (!isscreensafe(line_char) && line_char != 27)
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (utf8) {
|
||||
unsigned char *text = &line[line_pos];
|
||||
unicode_val_T data =
|
||||
utf_8_to_unicode(&text,
|
||||
&line[width]);
|
||||
|
||||
if (data == UCS_NO_CHAR) {
|
||||
line_pos += charlen;
|
||||
continue;
|
||||
}
|
||||
|
||||
template->data = (unicode_val_T)data;
|
||||
copy_screen_chars(pos++, template, 1);
|
||||
|
||||
if (unicode_to_cell(data) == 2) {
|
||||
template->data = UCS_NO_CHAR;
|
||||
copy_screen_chars(pos++,
|
||||
template, 1);
|
||||
cell++;
|
||||
}
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
if (!isscreensafe(line_char))
|
||||
line_char = '.';
|
||||
template->data = line_char;
|
||||
copy_screen_chars(pos++, template, 1);
|
||||
|
||||
/* Detect copy of nul chars to screen, this
|
||||
* should not occur. --Zas */
|
||||
/* Detect copy of nul chars to screen,
|
||||
* this should not occur. --Zas */
|
||||
assert(line_char);
|
||||
}
|
||||
}
|
||||
|
||||
*template = saved_renderer_template;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
line_pos += charlen;
|
||||
cells += cell;
|
||||
}
|
||||
mem_free(line);
|
||||
|
||||
realloc_line(document, pos - startpos, lineno);
|
||||
@ -664,19 +519,20 @@ add_document_lines(struct plain_renderer *renderer)
|
||||
int length = renderer->length;
|
||||
int was_empty_line = 0;
|
||||
int was_wrapped = 0;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
int utf8 = is_cp_utf8(renderer->document->cp);
|
||||
#endif
|
||||
for (; length > 0; renderer->lineno++) {
|
||||
unsigned char *xsource;
|
||||
int width, added, only_spaces = 1, spaces = 0, was_spaces = 0;
|
||||
int last_space = 0;
|
||||
int tab_spaces = 0;
|
||||
int step = 0;
|
||||
int cells = 0;
|
||||
|
||||
/* End of line detection: We handle \r, \r\n and \n types. */
|
||||
for (width = 0;
|
||||
width + tab_spaces < renderer->max_width
|
||||
&& width < length;
|
||||
width++) {
|
||||
for (width = 0; (width < length) &&
|
||||
(cells < renderer->max_width);) {
|
||||
if (source[width] == ASCII_CR)
|
||||
step++;
|
||||
if (source[width + step] == ASCII_LF)
|
||||
@ -695,6 +551,22 @@ add_document_lines(struct plain_renderer *renderer)
|
||||
only_spaces = 0;
|
||||
was_spaces = 0;
|
||||
}
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (utf8) {
|
||||
unsigned char *text = &source[width];
|
||||
unicode_val_T data = utf_8_to_unicode(&text,
|
||||
&source[length]);
|
||||
|
||||
if (data == UCS_NO_CHAR) return;
|
||||
|
||||
cells += unicode_to_cell(data);
|
||||
width += utf8charlen(&source[width]);
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
cells++;
|
||||
width++;
|
||||
}
|
||||
}
|
||||
|
||||
if (only_spaces && step) {
|
||||
@ -722,6 +594,7 @@ add_document_lines(struct plain_renderer *renderer)
|
||||
width -= was_spaces;
|
||||
step += was_spaces;
|
||||
}
|
||||
|
||||
if (!step && (width < length) && last_space) {
|
||||
width = last_space;
|
||||
step = 1;
|
||||
@ -777,6 +650,9 @@ render_plain_document(struct cache_entry *cached, struct document *document,
|
||||
|
||||
document->bgcolor = document->options.default_bg;
|
||||
document->width = 0;
|
||||
#ifdef CONFIG_UTF_8
|
||||
document->options.utf8 = is_cp_utf8(document->options.cp);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
/* Setup the style */
|
||||
init_template(&renderer.template, &document->options);
|
||||
|
@ -345,9 +345,15 @@ render_document(struct view_state *vs, struct document_view *doc_view,
|
||||
}
|
||||
|
||||
document->title = get_uri_string(document->uri, components);
|
||||
if (document->title)
|
||||
if (document->title) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (doc_view->document->options.utf8)
|
||||
decode_uri(document->title);
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
decode_uri_for_display(document->title);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CSS
|
||||
document->css_magic = get_document_css_magic(document);
|
||||
|
@ -140,6 +140,14 @@ u2cp_(unicode_val_T u, int to, int no_nbsp_hack)
|
||||
int s;
|
||||
|
||||
if (u < 128) return strings[u];
|
||||
|
||||
to &= ~SYSTEM_CHARSET_FLAG;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (codepages[to].table == table_utf_8)
|
||||
return encode_utf_8(u);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
/* 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 +159,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,8 +172,13 @@ u2cp_(unicode_val_T u, int to, int no_nbsp_hack)
|
||||
|
||||
static unsigned char utf_buffer[7];
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
inline unsigned char *
|
||||
encode_utf_8(unicode_val_T u)
|
||||
#else
|
||||
static unsigned char *
|
||||
encode_utf_8(unicode_val_T u)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
memset(utf_buffer, 0, 7);
|
||||
|
||||
@ -200,6 +212,252 @@ encode_utf_8(unicode_val_T u)
|
||||
return utf_buffer;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
/* Number of bytes utf8 character indexed by first byte. Illegal bytes are
|
||||
* equal ones and handled different. */
|
||||
static char utf8char_len_tab[256] = {
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
|
||||
3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4, 5,5,5,5,6,6,1,1,
|
||||
};
|
||||
|
||||
inline int utf8charlen(const unsigned char *p)
|
||||
{
|
||||
return p ? utf8char_len_tab[*p] : 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
len = utf8charlen(s);
|
||||
if (s + len > end) break;
|
||||
}
|
||||
*str = s;
|
||||
return x;
|
||||
}
|
||||
|
||||
#define utf8_issingle(p) (((p) & 0x80) == 0)
|
||||
#define utf8_islead(p) (utf8_issingle(p) || ((p) & 0xc0) == 0xc0)
|
||||
|
||||
/* Start from @current and move back to @pos char. This pointer return. The
|
||||
* most left pointer is @start. */
|
||||
inline unsigned char *
|
||||
utf8_prevchar(unsigned char *current, int pos, unsigned char *start)
|
||||
{
|
||||
if (current == NULL || start == NULL || pos < 0)
|
||||
return NULL;
|
||||
while (pos > 0 && current != start) {
|
||||
current--;
|
||||
if (utf8_islead(*current))
|
||||
pos--;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
/* Count number of standard terminal cells needed for displaying UTF-8
|
||||
* character. */
|
||||
int
|
||||
utf8_char2cells(unsigned char *utf8_char, unsigned char *end)
|
||||
{
|
||||
unicode_val_T u;
|
||||
|
||||
if (end == NULL)
|
||||
end = strchr(utf8_char, '\0');
|
||||
|
||||
if(!utf8_char || !end)
|
||||
return -1;
|
||||
|
||||
u = utf_8_to_unicode(&utf8_char, end);
|
||||
|
||||
return unicode_to_cell(u);
|
||||
}
|
||||
|
||||
/* Count number of standard terminal cells needed for displaying string
|
||||
* with UTF-8 characters. */
|
||||
int
|
||||
utf8_ptr2cells(unsigned char *string, unsigned char *end)
|
||||
{
|
||||
int charlen, cell, cells = 0;
|
||||
|
||||
if (end == NULL)
|
||||
end = strchr(string, '\0');
|
||||
|
||||
if(!string || !end)
|
||||
return -1;
|
||||
|
||||
do {
|
||||
charlen = utf8charlen(string);
|
||||
if (string + charlen > end)
|
||||
break;
|
||||
|
||||
cell = utf8_char2cells(string, end);
|
||||
if (cell < 0)
|
||||
return -1;
|
||||
|
||||
cells += cell;
|
||||
string += charlen;
|
||||
} while (1);
|
||||
|
||||
return cells;
|
||||
}
|
||||
|
||||
/* Count number of characters in string. */
|
||||
int
|
||||
utf8_ptr2chars(unsigned char *string, unsigned char *end)
|
||||
{
|
||||
int charlen, chars = 0;
|
||||
|
||||
if (end == NULL)
|
||||
end = strchr(string, '\0');
|
||||
|
||||
if(!string || !end)
|
||||
return -1;
|
||||
|
||||
do {
|
||||
charlen = utf8charlen(string);
|
||||
if (string + charlen > end)
|
||||
break;
|
||||
|
||||
chars++;
|
||||
string += charlen;
|
||||
} while (1);
|
||||
|
||||
return chars;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count number of bytes from begining of the string needed for displaying
|
||||
* specified number of cells.
|
||||
*/
|
||||
int
|
||||
utf8_cells2bytes(unsigned char *string, int max_cells, unsigned char *end)
|
||||
{
|
||||
unsigned int bytes = 0, cells = 0;
|
||||
|
||||
assert(max_cells>=0);
|
||||
|
||||
if (end == NULL)
|
||||
end = strchr(string, '\0');
|
||||
|
||||
if(!string || !end)
|
||||
return -1;
|
||||
|
||||
do {
|
||||
int cell = utf8_char2cells(&string[bytes], end);
|
||||
if (cell < 0)
|
||||
return -1;
|
||||
|
||||
cells += cell;
|
||||
if (cells > max_cells)
|
||||
break;
|
||||
|
||||
bytes += utf8charlen(&string[bytes]);
|
||||
|
||||
if (string + bytes > end) {
|
||||
bytes = end - string;
|
||||
break;
|
||||
}
|
||||
} while(1);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out number of standard terminal collumns needed for displaying symbol
|
||||
* (glyph) which represents Unicode character c.
|
||||
* TODO: Use wcwidth when it is available.
|
||||
*
|
||||
* @return 2 for double-width glyph, 1 for others.
|
||||
* TODO: May be extended to return 0 for zero-width glyphs
|
||||
* (like composing, maybe unprintable too).
|
||||
*/
|
||||
inline int
|
||||
unicode_to_cell(unicode_val_T c)
|
||||
{
|
||||
if (c >= 0x1100
|
||||
&& (c <= 0x115f /* Hangul Jamo */
|
||||
|| c == 0x2329
|
||||
|| c == 0x232a
|
||||
|| (c >= 0x2e80 && c <= 0xa4cf
|
||||
&& c != 0x303f) /* CJK ... Yi */
|
||||
|| (c >= 0xac00 && c <= 0xd7a3) /* Hangul Syllables */
|
||||
|| (c >= 0xf900 && c <= 0xfaff) /* CJK Compatibility
|
||||
Ideographs */
|
||||
|| (c >= 0xfe30 && c <= 0xfe6f) /* CJK Compatibility Forms */
|
||||
|| (c >= 0xff00 && c <= 0xff60) /* Fullwidth Forms */
|
||||
|| (c >= 0xffe0 && c <= 0xffe6)
|
||||
|| (c >= 0x20000 && c <= 0x2fffd)
|
||||
|| (c >= 0x30000 && c <= 0x3fffd)))
|
||||
return 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline unicode_val_T
|
||||
utf_8_to_unicode(unsigned char **string, unsigned char *end)
|
||||
{
|
||||
unsigned char *str = *string;
|
||||
unicode_val_T u;
|
||||
int length;
|
||||
|
||||
length = utf8char_len_tab[str[0]];
|
||||
|
||||
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;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
/* This slow and ugly code is used by the terminal utf_8_io */
|
||||
unsigned char *
|
||||
cp2utf_8(int from, int c)
|
||||
@ -430,11 +688,18 @@ 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;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
/* TODO: caching UTF-8 */
|
||||
encoding &= ~SYSTEM_CHARSET_FLAG;
|
||||
if (codepages[encoding].table == table_utf_8)
|
||||
goto skip;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
if (first_time) {
|
||||
memset(&nb_entity_cache, 0, ENTITY_CACHE_MAXLEN * sizeof(unsigned int));
|
||||
first_time = 0;
|
||||
@ -488,7 +753,9 @@ get_entity_string(const unsigned char *str, const int strlen, int encoding)
|
||||
fprintf(stderr, "miss\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
skip:
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
if (*str == '#') { /* Numeric entity. */
|
||||
int l = (int) strlen;
|
||||
unsigned char *st = (unsigned char *) str;
|
||||
@ -540,6 +807,11 @@ get_entity_string(const unsigned char *str, const int strlen, int encoding)
|
||||
if (element) result = u2cp(element->c, encoding);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (codepages[encoding].table == table_utf_8) {
|
||||
return result;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
end:
|
||||
/* Take care of potential buffer overflow. */
|
||||
if (strlen < sizeof(entity_cache[slen][0].str)) {
|
||||
@ -865,7 +1137,7 @@ get_cp_mime_name(int cp_index)
|
||||
}
|
||||
|
||||
int
|
||||
is_cp_special(int cp_index)
|
||||
is_cp_utf8(int cp_index)
|
||||
{
|
||||
cp_index &= ~SYSTEM_CHARSET_FLAG;
|
||||
return codepages[cp_index].table == table_utf_8;
|
||||
|
@ -51,8 +51,21 @@ unsigned char *convert_string(struct conv_table *convert_table,
|
||||
int get_cp_index(unsigned char *);
|
||||
unsigned char *get_cp_name(int);
|
||||
unsigned char *get_cp_mime_name(int);
|
||||
int is_cp_special(int);
|
||||
int is_cp_utf8(int);
|
||||
void free_conv_table(void);
|
||||
#ifdef CONFIG_UTF_8
|
||||
inline unsigned char *encode_utf_8(unicode_val_T);
|
||||
inline unsigned char *utf8_prevchar(unsigned char *, int, unsigned char *);
|
||||
inline int utf8charlen(const unsigned char *);
|
||||
int utf8_char2cells(unsigned char *, unsigned char *);
|
||||
int utf8_ptr2cells(unsigned char *, unsigned char *);
|
||||
int utf8_ptr2chars(unsigned char *, unsigned char *);
|
||||
int utf8_cells2bytes(unsigned char *, int, unsigned char *);
|
||||
inline int unicode_to_cell(unicode_val_T);
|
||||
inline int strlen_utf8(unsigned char **);
|
||||
inline unicode_val_T utf_8_to_unicode(unsigned char **, unsigned char *);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
unsigned char *cp2utf_8(int, int);
|
||||
|
||||
unsigned char *u2cp_(unicode_val_T, int, int no_nbsp_hack);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -118,6 +118,9 @@ get_dyn_full_version(struct terminal *term, int more)
|
||||
#endif
|
||||
#ifndef CONFIG_MOUSE
|
||||
comma, _("No mouse", term),
|
||||
#endif
|
||||
#ifdef CONFIG_UTF_8
|
||||
comma, "UTF-8",
|
||||
#endif
|
||||
comma,
|
||||
NULL
|
||||
|
@ -574,6 +574,11 @@ bittorrent_message_dialog(struct session *ses, void *data)
|
||||
|
||||
uristring = get_uri_string(message->uri, URI_PUBLIC);
|
||||
if (uristring) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (ses->tab->term->utf8)
|
||||
decode_uri(uristring);
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
decode_uri_for_display(uristring);
|
||||
add_format_to_string(&string,
|
||||
_("Unable to retrieve %s", ses->tab->term),
|
||||
@ -719,6 +724,11 @@ bittorrent_query_callback(void *data, enum connection_state state,
|
||||
|
||||
/* Let's make the filename pretty for display & save */
|
||||
/* TODO: The filename can be the empty string here. See bug 396. */
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
decode_uri_string(&filename);
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
decode_uri_string_for_display(&filename);
|
||||
}
|
||||
|
||||
|
@ -649,6 +649,10 @@ init_gopher_index_cache_entry(struct connection *conn)
|
||||
return S_OUT_OF_MEM;
|
||||
|
||||
where = get_uri_string(conn->uri, URI_PUBLIC);
|
||||
|
||||
/* TODO: Use different function when using UTF-8
|
||||
* in terminal (decode_uri_for_display replaces
|
||||
* bytes of UTF-8 characters width '*'). */
|
||||
if (where) decode_uri_for_display(where);
|
||||
|
||||
add_format_to_string(&buffer,
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "scripting/python/core.h"
|
||||
#include <Python.h>
|
||||
|
||||
#include <stdio.h>
|
||||
@ -14,24 +13,91 @@
|
||||
|
||||
#include "config/home.h"
|
||||
#include "main/module.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "scripting/python/core.h"
|
||||
#include "scripting/python/python.h"
|
||||
#include "util/env.h"
|
||||
#include "util/file.h"
|
||||
#include "util/string.h"
|
||||
|
||||
|
||||
PyObject *pDict, *pModule;
|
||||
PyObject *pDict = NULL, *pModule = NULL;
|
||||
|
||||
/* Error reporting. */
|
||||
|
||||
void
|
||||
alert_python_error(struct session *ses)
|
||||
{
|
||||
unsigned char *msg = "(no traceback available)";
|
||||
PyObject *err_type = NULL, *err_value = NULL, *err_traceback = NULL;
|
||||
PyObject *tb_module = NULL;
|
||||
PyObject *tb_dict;
|
||||
PyObject *format_function;
|
||||
PyObject *msg_list = NULL;
|
||||
PyObject *empty_string = NULL;
|
||||
PyObject *join_method = NULL;
|
||||
PyObject *msg_string = NULL;
|
||||
unsigned char *temp;
|
||||
|
||||
/*
|
||||
* Retrieve the current error indicator and use the format_exception()
|
||||
* function in Python's traceback module to produce an informative
|
||||
* error message. It returns a list of Python string objects.
|
||||
*/
|
||||
PyErr_Fetch(&err_type, &err_value, &err_traceback);
|
||||
PyErr_NormalizeException(&err_type, &err_value, &err_traceback);
|
||||
if (!err_traceback) goto end;
|
||||
|
||||
tb_module = PyImport_ImportModule("traceback");
|
||||
if (!tb_module) goto end;
|
||||
|
||||
tb_dict = PyModule_GetDict(tb_module);
|
||||
format_function = PyDict_GetItemString(tb_dict, "format_exception");
|
||||
if (!format_function || !PyCallable_Check(format_function)) goto end;
|
||||
|
||||
msg_list = PyObject_CallFunction(format_function, "OOO",
|
||||
err_type, err_value, err_traceback);
|
||||
if (!msg_list) goto end;
|
||||
|
||||
/*
|
||||
* Use the join() method of an empty Python string to join the list
|
||||
* of strings into one Python string containing the entire error
|
||||
* message. Then get the contents of the Python string.
|
||||
*/
|
||||
empty_string = PyString_FromString("");
|
||||
if (!empty_string) goto end;
|
||||
|
||||
join_method = PyObject_GetAttrString(empty_string, "join");
|
||||
if (!join_method || !PyCallable_Check(join_method)) goto end;
|
||||
|
||||
msg_string = PyObject_CallFunction(join_method, "O", msg_list);
|
||||
if (!msg_string) goto end;
|
||||
|
||||
temp = (unsigned char *)PyString_AsString(msg_string);
|
||||
if (temp) msg = temp;
|
||||
|
||||
end:
|
||||
report_scripting_error(&python_scripting_module, ses, msg);
|
||||
|
||||
Py_XDECREF(err_type);
|
||||
Py_XDECREF(err_value);
|
||||
Py_XDECREF(err_traceback);
|
||||
Py_XDECREF(tb_module);
|
||||
Py_XDECREF(msg_list);
|
||||
Py_XDECREF(empty_string);
|
||||
Py_XDECREF(join_method);
|
||||
Py_XDECREF(msg_string);
|
||||
|
||||
/* In case another error occurred while reporting the original error: */
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
void
|
||||
cleanup_python(struct module *module)
|
||||
{
|
||||
if (Py_IsInitialized()) {
|
||||
if (pModule) {
|
||||
Py_DECREF(pModule);
|
||||
}
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
Py_XDECREF(pDict);
|
||||
Py_XDECREF(pModule);
|
||||
Py_Finalize();
|
||||
}
|
||||
}
|
||||
@ -44,15 +110,25 @@ init_python(struct module *module)
|
||||
if (!python_path) return;
|
||||
env_set("PYTHONPATH", python_path, -1);
|
||||
mem_free(python_path);
|
||||
|
||||
/* Treat warnings as errors so they can be caught and handled;
|
||||
* otherwise they would be printed to stderr.
|
||||
*
|
||||
* NOTE: PySys_ResetWarnOptions() and PySys_AddWarnOption() have been
|
||||
* available and stable for many years but they're not officially
|
||||
* documented as part of Python's public API, so in theory these two
|
||||
* functions might no longer be available in some hypothetical future
|
||||
* version of Python. */
|
||||
PySys_ResetWarnOptions();
|
||||
PySys_AddWarnOption("error");
|
||||
|
||||
Py_Initialize();
|
||||
pModule = PyImport_ImportModule("hooks");
|
||||
|
||||
if (pModule) {
|
||||
pDict = PyModule_GetDict(pModule);
|
||||
Py_INCREF(pDict);
|
||||
} else {
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
alert_python_error(NULL);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,9 @@
|
||||
#define EL__SCRIPTING_PYTHON_CORE_H
|
||||
|
||||
struct module;
|
||||
struct session;
|
||||
|
||||
void alert_python_error(struct session *ses);
|
||||
void init_python(struct module *module);
|
||||
void cleanup_python(struct module *module);
|
||||
|
||||
|
@ -32,29 +32,29 @@ do_script_hook_goto_url(struct session *ses, unsigned char **url)
|
||||
|
||||
if (pFunc && PyCallable_Check(pFunc)) {
|
||||
PyObject *pValue;
|
||||
unsigned char *str;
|
||||
unsigned char *current_url;
|
||||
|
||||
if (!ses || !have_location(ses)) {
|
||||
str = NULL;
|
||||
current_url = NULL;
|
||||
} else {
|
||||
str = struri(cur_loc(ses)->vs.uri);
|
||||
current_url = struri(cur_loc(ses)->vs.uri);
|
||||
}
|
||||
|
||||
pValue = PyObject_CallFunction(pFunc, "ss", *url, str);
|
||||
if (pValue && (pValue != Py_None)) {
|
||||
const unsigned char *res = PyString_AsString(pValue);
|
||||
|
||||
if (res) {
|
||||
unsigned char *new_url = stracpy((unsigned char *)res);
|
||||
pValue = PyObject_CallFunction(pFunc, "ss", *url, current_url);
|
||||
if (pValue) {
|
||||
if (pValue != Py_None) {
|
||||
const unsigned char *str;
|
||||
unsigned char *new_url;
|
||||
|
||||
str = PyString_AsString(pValue);
|
||||
if (str) {
|
||||
new_url = stracpy((unsigned char *)str);
|
||||
if (new_url) mem_free_set(url, new_url);
|
||||
}
|
||||
}
|
||||
Py_DECREF(pValue);
|
||||
} else {
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
alert_python_error(ses);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -72,26 +72,26 @@ script_hook_goto_url(va_list ap, void *data)
|
||||
}
|
||||
|
||||
static void
|
||||
do_script_hook_follow_url(unsigned char **url)
|
||||
do_script_hook_follow_url(struct session *ses, unsigned char **url)
|
||||
{
|
||||
PyObject *pFunc = PyDict_GetItemString(pDict, "follow_url_hook");
|
||||
|
||||
if (pFunc && PyCallable_Check(pFunc)) {
|
||||
PyObject *pValue = PyObject_CallFunction(pFunc, "s", *url);
|
||||
if (pValue && (pValue != Py_None)) {
|
||||
const unsigned char *str = PyString_AsString(pValue);
|
||||
if (pValue) {
|
||||
if (pValue != Py_None) {
|
||||
const unsigned char *str;
|
||||
unsigned char *new_url;
|
||||
|
||||
str = PyString_AsString(pValue);
|
||||
if (str) {
|
||||
new_url = stracpy((unsigned char *)str);
|
||||
if (new_url) mem_free_set(url, new_url);
|
||||
}
|
||||
}
|
||||
Py_DECREF(pValue);
|
||||
} else {
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
alert_python_error(ses);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -100,15 +100,17 @@ static enum evhook_status
|
||||
script_hook_follow_url(va_list ap, void *data)
|
||||
{
|
||||
unsigned char **url = va_arg(ap, unsigned char **);
|
||||
struct session *ses = va_arg(ap, struct session *);
|
||||
|
||||
if (pDict && *url)
|
||||
do_script_hook_follow_url(url);
|
||||
do_script_hook_follow_url(ses, url);
|
||||
|
||||
return EVENT_HOOK_STATUS_NEXT;
|
||||
}
|
||||
|
||||
static void
|
||||
do_script_hook_pre_format_html(unsigned char *url, struct cache_entry *cached,
|
||||
do_script_hook_pre_format_html(struct session *ses, unsigned char *url,
|
||||
struct cache_entry *cached,
|
||||
struct fragment *fragment)
|
||||
{
|
||||
PyObject *pFunc = PyDict_GetItemString(pDict, "pre_format_html_hook");
|
||||
@ -118,21 +120,21 @@ do_script_hook_pre_format_html(unsigned char *url, struct cache_entry *cached,
|
||||
fragment->data,
|
||||
fragment->length);
|
||||
|
||||
if (pValue && (pValue != Py_None)) {
|
||||
const unsigned char *str = PyString_AsString(pValue);
|
||||
if (pValue) {
|
||||
if (pValue != Py_None) {
|
||||
const unsigned char *str;
|
||||
int len;
|
||||
|
||||
str = PyString_AsString(pValue);
|
||||
if (str) {
|
||||
int len = PyString_Size(pValue); /* strlen(str); */
|
||||
|
||||
len = PyString_Size(pValue);
|
||||
add_fragment(cached, 0, str, len);
|
||||
normalize_cache_entry(cached, len);
|
||||
}
|
||||
}
|
||||
Py_DECREF(pValue);
|
||||
} else {
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
alert_python_error(ses);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -146,7 +148,7 @@ script_hook_pre_format_html(va_list ap, void *data)
|
||||
unsigned char *url = struri(cached->uri);
|
||||
|
||||
if (pDict && ses && url && cached->length && *fragment->data)
|
||||
do_script_hook_pre_format_html(url, cached, fragment);
|
||||
do_script_hook_pre_format_html(ses, url, cached, fragment);
|
||||
|
||||
return EVENT_HOOK_STATUS_NEXT;
|
||||
}
|
||||
@ -159,20 +161,21 @@ do_script_hook_get_proxy(unsigned char **new_proxy_url, unsigned char *url)
|
||||
if (pFunc && PyCallable_Check(pFunc)) {
|
||||
PyObject *pValue = PyObject_CallFunction(pFunc, "s", url);
|
||||
|
||||
if (pValue && (pValue != Py_None)) {
|
||||
const unsigned char *str = PyString_AsString(pValue);
|
||||
if (pValue) {
|
||||
if (pValue != Py_None) {
|
||||
const unsigned char *str;
|
||||
unsigned char *new_url;
|
||||
|
||||
str = PyString_AsString(pValue);
|
||||
if (str) {
|
||||
unsigned char *new_url = stracpy((unsigned char *)str);
|
||||
|
||||
if (new_url) mem_free_set(new_proxy_url, new_url);
|
||||
new_url = stracpy((unsigned char *)str);
|
||||
if (new_url) mem_free_set(new_proxy_url,
|
||||
new_url);
|
||||
}
|
||||
}
|
||||
Py_DECREF(pValue);
|
||||
} else {
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
alert_python_error(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,14 +201,9 @@ do_script_hook_quit(void)
|
||||
PyObject *pValue = PyObject_CallFunction(pFunc, NULL);
|
||||
|
||||
if (pValue) {
|
||||
if (pValue != Py_None) {
|
||||
Py_DECREF(pValue);
|
||||
}
|
||||
} else {
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
alert_python_error(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,10 +24,14 @@
|
||||
#include "scripting/ruby/ruby.h"
|
||||
#include "scripting/smjs/smjs.h"
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* Error reporting. */
|
||||
|
||||
#if defined(CONFIG_SCRIPTING_RUBY) || defined(CONFIG_SCRIPTING_SPIDERMONKEY)
|
||||
#if defined(CONFIG_SCRIPTING_RUBY) || defined(CONFIG_SCRIPTING_SPIDERMONKEY) || defined(CONFIG_SCRIPTING_PYTHON)
|
||||
void
|
||||
report_scripting_error(struct module *module, struct session *ses,
|
||||
unsigned char *msg)
|
||||
@ -38,6 +42,7 @@ report_scripting_error(struct module *module, struct session *ses,
|
||||
if (!ses) {
|
||||
if (list_empty(terminals)) {
|
||||
usrerror("[%s error] %s", module->name, msg);
|
||||
sleep(3);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1134,6 +1134,11 @@ do_type_query(struct type_query *type_query, unsigned char *ct, struct mime_hand
|
||||
|
||||
/* Let's make the filename pretty for display & save */
|
||||
/* TODO: The filename can be the empty string here. See bug 396. */
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
decode_uri_string(&filename);
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
decode_uri_string_for_display(&filename);
|
||||
}
|
||||
|
||||
|
@ -268,6 +268,11 @@ print_error_dialog(struct session *ses, enum connection_state state,
|
||||
|
||||
uristring = uri ? get_uri_string(uri, URI_PUBLIC) : NULL;
|
||||
if (uristring) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (ses->tab->term->utf8)
|
||||
decode_uri(uristring);
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
decode_uri_for_display(uristring);
|
||||
add_format_to_string(&msg,
|
||||
_("Unable to retrieve %s", ses->tab->term),
|
||||
|
@ -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,13 +103,30 @@ draw_char_color(struct terminal *term, int x, int y, struct color_pair *color)
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef CONFIG_UTF_8
|
||||
draw_char_data(struct terminal *term, int x, int y, unicode_val_T data)
|
||||
#else
|
||||
draw_char_data(struct terminal *term, int x, int y, unsigned char data)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
struct screen_char *screen_char = get_char(term, x, y);
|
||||
|
||||
if (!screen_char) return;
|
||||
|
||||
screen_char->data = data;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
#ifdef CONFIG_DEBUG
|
||||
/* Detect attempt to draw double-width char on the last
|
||||
* column of terminal. */
|
||||
if (unicode_to_cell(data) == 2 && x + 1 > term->width)
|
||||
INTERNAL("Attempt to draw double-width glyph on last column!");
|
||||
#endif /* CONFIG_DEBUG */
|
||||
|
||||
if (data == UCS_NO_CHAR)
|
||||
screen_char->attr = 0;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
set_screen_dirty(term->screen, y, y);
|
||||
}
|
||||
|
||||
@ -127,6 +145,38 @@ draw_line(struct terminal *term, int x, int y, int l, struct screen_char *line)
|
||||
size = int_min(l, term->width - x);
|
||||
if (size == 0) return;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
struct screen_char *sc;
|
||||
|
||||
if (line->data == UCS_NO_CHAR && x == 0) {
|
||||
unicode_val_T data_save;
|
||||
|
||||
sc = line;
|
||||
data_save = sc->data;
|
||||
sc->data = ' ';
|
||||
copy_screen_chars(screen_char, line, 1);
|
||||
sc->data = data_save;
|
||||
size--;
|
||||
line++;
|
||||
screen_char++;
|
||||
|
||||
}
|
||||
/* Instead of displaying double-width character at last column
|
||||
* display only space. */
|
||||
if (size - 1 > 0 && unicode_to_cell(line[size - 1].data) == 2) {
|
||||
unicode_val_T data_save;
|
||||
|
||||
sc = &line[size - 1];
|
||||
data_save = sc->data;
|
||||
sc->data = ' ';
|
||||
copy_screen_chars(screen_char, line, size);
|
||||
sc->data = data_save;
|
||||
} else {
|
||||
copy_screen_chars(screen_char, line, size);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
copy_screen_chars(screen_char, line, size);
|
||||
set_screen_dirty(term->screen, y, y);
|
||||
}
|
||||
@ -198,10 +248,88 @@ draw_border(struct terminal *term, struct box *box,
|
||||
set_screen_dirty(term->screen, borderbox.y, borderbox.y + borderbox.height);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
/* Checks cells left and right to the box for broken double-width chars.
|
||||
* Replace it with ' '.
|
||||
* 1+---+3
|
||||
* 1|box|##4
|
||||
* 1| |##4
|
||||
* 1| |##4
|
||||
* 1+---+##4
|
||||
* 2#####4
|
||||
* 1,2,3,4 - needs to be checked, # - shadow , +,-,| - border
|
||||
*/
|
||||
void
|
||||
fix_dwchar_around_box(struct terminal *term, struct box *box, int border,
|
||||
int shadow_width, int shadow_height)
|
||||
{
|
||||
struct screen_char *schar;
|
||||
int height, x, y;
|
||||
|
||||
if (!term->utf8)
|
||||
return;
|
||||
|
||||
/* 1 */
|
||||
x = box->x - border - 1;
|
||||
if (x > 0) {
|
||||
y = box->y - border;
|
||||
height = box->height + 2 * border;
|
||||
|
||||
schar = get_char(term, x, y);
|
||||
for (;height--; schar += term->width)
|
||||
if (unicode_to_cell(schar->data) == 2)
|
||||
schar->data = ' ';
|
||||
}
|
||||
|
||||
/* 2 */
|
||||
x = box->x - border + shadow_width - 1;
|
||||
if (x > 0 && x < term->width) {
|
||||
y = box->y + border + box->height;
|
||||
height = shadow_height;
|
||||
|
||||
schar = get_char(term, x, y);
|
||||
for (;height--; schar += term->width)
|
||||
if (unicode_to_cell(schar->data) == 2)
|
||||
schar->data = ' ';
|
||||
}
|
||||
|
||||
/* 3 */
|
||||
x = box->x + box->width + border;
|
||||
if (x < term->width) {
|
||||
y = box->y - border;
|
||||
height = shadow_height;
|
||||
|
||||
schar = get_char(term, x, y);
|
||||
for (;height--; schar += term->width)
|
||||
if (schar->data == UCS_NO_CHAR)
|
||||
schar->data = ' ';
|
||||
}
|
||||
|
||||
/* 4 */
|
||||
x = box->x + box->width + border + shadow_width;
|
||||
if (x < term->width) {
|
||||
y = box->y - border + shadow_height;
|
||||
height = box->height + 2 * border;
|
||||
|
||||
schar = get_char(term, x, y);
|
||||
for (;height--; schar += term->width)
|
||||
if (schar->data == UCS_NO_CHAR)
|
||||
schar->data = ' ';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
void
|
||||
draw_char(struct terminal *term, int x, int y,
|
||||
unicode_val_T data, enum screen_char_attr attr,
|
||||
struct color_pair *color)
|
||||
#else
|
||||
void
|
||||
draw_char(struct terminal *term, int x, int y,
|
||||
unsigned char data, enum screen_char_attr attr,
|
||||
struct color_pair *color)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
struct screen_char *screen_char = get_char(term, x, y);
|
||||
|
||||
@ -277,6 +405,80 @@ draw_shadow(struct terminal *term, struct box *box,
|
||||
draw_box(term, &dbox, ' ', 0, color);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
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);
|
||||
if (color) {
|
||||
start->attr = attr;
|
||||
set_term_color(start, color, 0,
|
||||
get_opt_int_tree(term->spec, "colors"));
|
||||
}
|
||||
|
||||
if (start->data == UCS_NO_CHAR && x - 1 > 0)
|
||||
draw_char_data(term, x - 1, y, ' ');
|
||||
|
||||
pos = start;
|
||||
|
||||
if (unicode_to_cell(data) == 2) {
|
||||
/* Is there enough room for whole double-width char? */
|
||||
if (x + 1 < term->width) {
|
||||
pos->data = data;
|
||||
pos++;
|
||||
x++;
|
||||
|
||||
pos->data = UCS_NO_CHAR;
|
||||
pos->attr = 0;
|
||||
} else {
|
||||
pos->data = (unicode_val_T)' ';
|
||||
}
|
||||
} else {
|
||||
pos->data = data;
|
||||
}
|
||||
pos++;
|
||||
x++;
|
||||
|
||||
for (; 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);
|
||||
|
||||
if (unicode_to_cell(data) == 2) {
|
||||
/* Is there enough room for whole double-width char? */
|
||||
if (x + 1 < term->width) {
|
||||
pos->data = data;
|
||||
|
||||
x++;
|
||||
pos++;
|
||||
pos->data = UCS_NO_CHAR;
|
||||
pos->attr = 0;
|
||||
} else {
|
||||
pos->data = (unicode_val_T)' ';
|
||||
}
|
||||
} else {
|
||||
pos->data = data;
|
||||
}
|
||||
}
|
||||
set_screen_dirty(term->screen, y, y);
|
||||
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
void
|
||||
draw_text(struct terminal *term, int x, int y,
|
||||
unsigned char *text, int length,
|
||||
@ -288,6 +490,13 @@ draw_text(struct terminal *term, int x, int y,
|
||||
assert(text && length >= 0);
|
||||
if_assert_failed return;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
draw_text_utf8(term, x, y, text, length, attr, color);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
if (length <= 0) return;
|
||||
pos = get_char(term, x, y);
|
||||
if (!pos) return;
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef EL__TERMINAL_DRAW_H
|
||||
#define EL__TERMINAL_DRAW_H
|
||||
|
||||
#include "intl/charsets.h" /* unicode_val_T */
|
||||
|
||||
struct color_pair;
|
||||
struct box;
|
||||
struct terminal;
|
||||
@ -19,7 +21,11 @@ enum screen_char_attr {
|
||||
/* One position in the terminal screen's image. */
|
||||
struct screen_char {
|
||||
/* Contains either character value or frame data. */
|
||||
#ifdef CONFIG_UTF_8
|
||||
unicode_val_T data;
|
||||
#else
|
||||
unsigned char data;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
/* Attributes are screen_char_attr bits. */
|
||||
unsigned char attr;
|
||||
@ -202,7 +208,11 @@ void draw_char_color(struct terminal *term, int x, int y,
|
||||
struct color_pair *color);
|
||||
|
||||
/* Sets the data of a screen position. */
|
||||
#ifdef CONFIG_UTF_8
|
||||
void draw_char_data(struct terminal *term, int x, int y, unicode_val_T data);
|
||||
#else
|
||||
void draw_char_data(struct terminal *term, int x, int y, unsigned char data);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
/* Sets the data to @border and of a screen position. */
|
||||
void draw_border_char(struct terminal *term, int x, int y,
|
||||
@ -213,9 +223,15 @@ void draw_border_cross(struct terminal *, int x, int y,
|
||||
enum border_cross_direction, struct color_pair *color);
|
||||
|
||||
/* Draws a char. */
|
||||
#ifdef CONFIG_UTF_8
|
||||
void draw_char(struct terminal *term, int x, int y,
|
||||
unicode_val_T data, enum screen_char_attr attr,
|
||||
struct color_pair *color);
|
||||
#else
|
||||
void draw_char(struct terminal *term, int x, int y,
|
||||
unsigned char data, enum screen_char_attr attr,
|
||||
struct color_pair *color);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
/* Draws area defined by @box using the same colors and attributes. */
|
||||
void draw_box(struct terminal *term, struct box *box,
|
||||
@ -230,6 +246,11 @@ void draw_shadow(struct terminal *term, struct box *box,
|
||||
void draw_border(struct terminal *term, struct box *box,
|
||||
struct color_pair *color, int width);
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
void fix_dwchar_around_box(struct terminal *term, struct box *box, int border,
|
||||
int shadow_width, int shadow_height);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
/* Draws @length chars from @text. */
|
||||
void draw_text(struct terminal *term, int x, int y,
|
||||
unsigned char *text, int length,
|
||||
|
@ -162,6 +162,12 @@ check_terminal_name(struct terminal *term, struct terminal_info *info)
|
||||
object_unlock(term->spec);
|
||||
term->spec = get_opt_rec(config_options, name);
|
||||
object_lock(term->spec);
|
||||
#ifdef CONFIG_UTF_8
|
||||
/* Probably not best place for set this. But now we finally have
|
||||
* term->spec and term->utf8 should be set before decode session info.
|
||||
* --Scrool */
|
||||
term->utf8 = get_opt_bool_tree(term->spec, "utf_8_io");
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MOUSE
|
||||
@ -259,9 +265,13 @@ handle_interlink_event(struct terminal *term, struct term_event *ev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (interlink->utf_8.len) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
utf8_io = !!term->utf8;
|
||||
#else
|
||||
utf8_io = get_opt_bool_tree(term->spec, "utf_8_io");
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
if (interlink->utf_8.len) {
|
||||
if ((key & 0xC0) == 0x80 && utf8_io) {
|
||||
interlink->utf_8.ucs <<= 6;
|
||||
interlink->utf_8.ucs |= key & 0x3F;
|
||||
@ -280,11 +290,7 @@ 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 || !utf8_io) {
|
||||
term_send_event(term, ev);
|
||||
break;
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
unsigned char frame_dumb[48] = " ||||++||++++++--|-+||++--|-+----++++++++ ";
|
||||
static unsigned char frame_vt100[48] = "aaaxuuukkuxkjjjkmvwtqnttmlvwtqnvvwwmmllnnjla ";
|
||||
|
||||
#ifndef CONFIG_UTF_8
|
||||
/* For UTF8 I/O */
|
||||
static unsigned char frame_vt100_u[48] = {
|
||||
177, 177, 177, 179, 180, 180, 180, 191,
|
||||
@ -40,6 +41,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 /* CONFIG_UTF_8 */
|
||||
|
||||
static unsigned char frame_freebsd[48] = {
|
||||
130, 138, 128, 153, 150, 150, 150, 140,
|
||||
@ -79,6 +81,13 @@ static struct string m11_hack_frame_seqs[] = {
|
||||
/* begin border: */ TERM_STRING("\033[11m"),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
static struct string utf8_linux_frame_seqs[] = {
|
||||
/* end border: */ TERM_STRING("\033[10m\033%G"),
|
||||
/* begin border: */ TERM_STRING("\033%@\033[11m"),
|
||||
};
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
static struct string vt100_frame_seqs[] = {
|
||||
/* end border: */ TERM_STRING("\x0f"),
|
||||
/* begin border: */ TERM_STRING("\x0e"),
|
||||
@ -100,10 +109,12 @@ struct screen_driver {
|
||||
* uniquely identify the screen_driver. */
|
||||
enum term_mode_type type;
|
||||
|
||||
#ifndef CONFIG_UTF_8
|
||||
/* 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];
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
/* The frame translation table. May be NULL. */
|
||||
unsigned char *frame;
|
||||
@ -120,6 +131,11 @@ struct screen_driver {
|
||||
/* These are directly derived from the terminal options. */
|
||||
unsigned int transparent:1;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
/* UTF-8 I/O */
|
||||
unsigned int utf8:1;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
/* The terminal._template_ name. */
|
||||
unsigned char name[1]; /* XXX: Keep last! */
|
||||
};
|
||||
@ -127,56 +143,81 @@ struct screen_driver {
|
||||
static struct screen_driver dumb_screen_driver = {
|
||||
NULL_LIST_HEAD,
|
||||
/* type: */ TERM_DUMB,
|
||||
#ifndef CONFIG_UTF_8
|
||||
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
/* frame: */ frame_dumb,
|
||||
/* frame_seqs: */ NULL,
|
||||
/* underline: */ underline_seqs,
|
||||
/* color_mode: */ COLOR_MODE_16,
|
||||
/* transparent: */ 1,
|
||||
#ifdef CONFIG_UTF_8
|
||||
/* utf-8: */ 0,
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
};
|
||||
|
||||
static struct screen_driver vt100_screen_driver = {
|
||||
NULL_LIST_HEAD,
|
||||
/* type: */ TERM_VT100,
|
||||
#ifndef CONFIG_UTF_8
|
||||
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
/* frame: */ frame_vt100,
|
||||
/* frame_seqs: */ vt100_frame_seqs,
|
||||
/* underline: */ underline_seqs,
|
||||
/* color_mode: */ COLOR_MODE_16,
|
||||
/* transparent: */ 1,
|
||||
#ifdef CONFIG_UTF_8
|
||||
/* utf-8: */ 0,
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
};
|
||||
|
||||
static struct screen_driver linux_screen_driver = {
|
||||
NULL_LIST_HEAD,
|
||||
/* type: */ TERM_LINUX,
|
||||
#ifndef CONFIG_UTF_8
|
||||
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
/* frame: */ NULL, /* No restrict_852 */
|
||||
/* frame_seqs: */ NULL, /* No m11_hack */
|
||||
/* underline: */ underline_seqs,
|
||||
/* color_mode: */ COLOR_MODE_16,
|
||||
/* transparent: */ 1,
|
||||
#ifdef CONFIG_UTF_8
|
||||
/* utf-8: */ 0,
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
};
|
||||
|
||||
static struct screen_driver koi8_screen_driver = {
|
||||
NULL_LIST_HEAD,
|
||||
/* type: */ TERM_KOI8,
|
||||
#ifndef CONFIG_UTF_8
|
||||
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
/* frame: */ frame_koi,
|
||||
/* frame_seqs: */ NULL,
|
||||
/* underline: */ underline_seqs,
|
||||
/* color_mode: */ COLOR_MODE_16,
|
||||
/* transparent: */ 1,
|
||||
#ifdef CONFIG_UTF_8
|
||||
/* utf-8: */ 0,
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
};
|
||||
|
||||
static struct screen_driver freebsd_screen_driver = {
|
||||
NULL_LIST_HEAD,
|
||||
/* type: */ TERM_FREEBSD,
|
||||
#ifndef CONFIG_UTF_8
|
||||
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
/* frame: */ frame_freebsd,
|
||||
/* frame_seqs: */ NULL, /* No m11_hack */
|
||||
/* underline: */ underline_seqs,
|
||||
/* color_mode: */ COLOR_MODE_16,
|
||||
/* transparent: */ 1,
|
||||
#ifdef CONFIG_UTF_8
|
||||
/* utf-8: */ 0,
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
};
|
||||
|
||||
/* XXX: Keep in sync with enum term_mode_type. */
|
||||
@ -188,13 +229,22 @@ static struct screen_driver *screen_drivers[] = {
|
||||
/* TERM_FREEBSD: */ &freebsd_screen_driver,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
#define use_utf8_io(driver) ((driver)->utf8)
|
||||
#else
|
||||
#define use_utf8_io(driver) ((driver)->charsets[0] != -1)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
static INIT_LIST_HEAD(active_screen_drivers);
|
||||
|
||||
static void
|
||||
update_screen_driver(struct screen_driver *driver, struct option *term_spec)
|
||||
{
|
||||
#ifdef CONFIG_UTF_8
|
||||
driver->utf8 = get_opt_bool_tree(term_spec, "utf_8_io");
|
||||
#else
|
||||
int utf8_io = get_opt_bool_tree(term_spec, "utf_8_io");
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
driver->color_mode = get_opt_int_tree(term_spec, "colors");
|
||||
driver->transparent = get_opt_bool_tree(term_spec, "transparency");
|
||||
@ -205,6 +255,25 @@ update_screen_driver(struct screen_driver *driver, struct option *term_spec)
|
||||
driver->underline = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
} else if (driver->type == TERM_VT100) {
|
||||
driver->frame = frame_vt100;
|
||||
}
|
||||
#else
|
||||
if (utf8_io) {
|
||||
driver->charsets[0] = get_opt_codepage_tree(term_spec, "charset");
|
||||
if (driver->type == TERM_LINUX) {
|
||||
@ -239,11 +308,11 @@ update_screen_driver(struct screen_driver *driver, struct option *term_spec)
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
}
|
||||
|
||||
static int
|
||||
@ -282,6 +351,10 @@ add_screen_driver(enum term_mode_type type, struct terminal *term, int env_len)
|
||||
|
||||
term->spec->change_hook = screen_driver_change_hook;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
term->utf8 = use_utf8_io(driver);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
return driver;
|
||||
}
|
||||
|
||||
@ -300,6 +373,9 @@ get_screen_driver(struct terminal *term)
|
||||
/* Some simple probably useless MRU ;) */
|
||||
move_to_top_of_list(active_screen_drivers, driver);
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
term->utf8 = use_utf8_io(driver);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
return driver;
|
||||
}
|
||||
|
||||
@ -366,11 +442,15 @@ 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)
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
static inline void
|
||||
add_char_data(struct string *screen, struct screen_driver *driver,
|
||||
unicode_val_T data, unsigned char border)
|
||||
#else
|
||||
static inline void
|
||||
add_char_data(struct string *screen, struct screen_driver *driver,
|
||||
unsigned char data, unsigned char border)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
if (!isscreensafe(data)) {
|
||||
add_char_to_string(screen, ' ');
|
||||
@ -381,13 +461,21 @@ add_char_data(struct string *screen, struct screen_driver *driver,
|
||||
data = driver->frame[data - 176];
|
||||
|
||||
if (use_utf8_io(driver)) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (border)
|
||||
add_char_to_string(screen, (unsigned char)data);
|
||||
else
|
||||
if (data != UCS_NO_CHAR)
|
||||
add_to_string(screen, encode_utf_8(data));
|
||||
#else
|
||||
int charset = driver->charsets[!!border];
|
||||
|
||||
add_to_string(screen, cp2utf_8(charset, data));
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
return;
|
||||
}
|
||||
|
||||
add_char_to_string(screen, data);
|
||||
add_char_to_string(screen, (unsigned char)data);
|
||||
}
|
||||
|
||||
/* Time critical section. */
|
||||
@ -399,17 +487,32 @@ add_char16(struct string *screen, struct screen_driver *driver,
|
||||
unsigned char underline = (ch->attr & SCREEN_ATTR_UNDERLINE);
|
||||
unsigned char bold = (ch->attr & SCREEN_ATTR_BOLD);
|
||||
|
||||
if (border != state->border && driver->frame_seqs) {
|
||||
if (
|
||||
#ifdef CONFIG_UTF_8
|
||||
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
border != state->border && driver->frame_seqs
|
||||
) {
|
||||
state->border = border;
|
||||
add_term_string(screen, driver->frame_seqs[!!border]);
|
||||
}
|
||||
|
||||
if (underline != state->underline && driver->underline) {
|
||||
if (
|
||||
#ifdef CONFIG_UTF_8
|
||||
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
underline != state->underline && driver->underline
|
||||
) {
|
||||
state->underline = underline;
|
||||
add_term_string(screen, driver->underline[!!underline]);
|
||||
}
|
||||
|
||||
if (bold != state->bold) {
|
||||
if (
|
||||
#ifdef CONFIG_UTF_8
|
||||
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
bold != state->bold
|
||||
) {
|
||||
state->bold = bold;
|
||||
if (bold) {
|
||||
add_bytes_to_string(screen, "\033[1m", 4);
|
||||
@ -419,7 +522,12 @@ add_char16(struct string *screen, struct screen_driver *driver,
|
||||
}
|
||||
}
|
||||
|
||||
if (!compare_color(ch->color, state->color)) {
|
||||
if (
|
||||
#ifdef CONFIG_UTF_8
|
||||
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
!compare_color(ch->color, state->color)
|
||||
) {
|
||||
copy_color(state->color, ch->color);
|
||||
|
||||
add_bytes_to_string(screen, "\033[0", 3);
|
||||
@ -521,7 +629,12 @@ add_char256(struct string *screen, struct screen_driver *driver,
|
||||
{
|
||||
unsigned char attr_delta = (ch->attr ^ state->attr);
|
||||
|
||||
if (attr_delta) {
|
||||
if (
|
||||
#ifdef CONFIG_UTF_8
|
||||
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
attr_delta
|
||||
) {
|
||||
if ((attr_delta & SCREEN_ATTR_FRAME) && driver->frame_seqs) {
|
||||
state->border = !!(ch->attr & SCREEN_ATTR_FRAME);
|
||||
add_term_string(screen, driver->frame_seqs[state->border]);
|
||||
@ -544,7 +657,12 @@ add_char256(struct string *screen, struct screen_driver *driver,
|
||||
state->attr = ch->attr;
|
||||
}
|
||||
|
||||
if (!compare_color(ch->color, state->color)) {
|
||||
if (
|
||||
#ifdef CONFIG_UTF_8
|
||||
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
!compare_color(ch->color, state->color)
|
||||
) {
|
||||
copy_color(state->color, ch->color);
|
||||
|
||||
add_foreground_color(screen, color256_seqs, ch);
|
||||
|
@ -126,6 +126,11 @@ struct terminal {
|
||||
* work and even maintaining these structures ;-). */
|
||||
unsigned int master:1;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
/* Indicates whether UTF-8 I/O is used */
|
||||
unsigned int utf8:1;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
/* 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"
|
||||
@ -346,6 +347,11 @@ add_document_to_string(struct string *string, struct document *document)
|
||||
assert(string && document);
|
||||
if_assert_failed return NULL;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (is_cp_utf8(document->options.cp))
|
||||
goto utf_8;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
for (y = 0; y < document->height; y++) {
|
||||
int white = 0;
|
||||
int x;
|
||||
@ -378,7 +384,45 @@ add_document_to_string(struct string *string, struct document *document)
|
||||
|
||||
add_char_to_string(string, '\n');
|
||||
}
|
||||
#ifdef CONFIG_UTF_8
|
||||
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++) {
|
||||
unicode_val_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:
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
return string;
|
||||
}
|
||||
|
||||
@ -666,6 +710,11 @@ dump_to_file(struct document *document, int fd)
|
||||
|
||||
if (!buf) return -1;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (is_cp_utf8(document->options.cp))
|
||||
goto utf_8;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
for (y = 0; y < document->height; y++) {
|
||||
int white = 0;
|
||||
int x;
|
||||
@ -702,13 +751,64 @@ dump_to_file(struct document *document, int fd)
|
||||
if (write_char('\n', fd, buf, &bptr))
|
||||
goto fail;
|
||||
}
|
||||
#ifdef CONFIG_UTF_8
|
||||
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++) {
|
||||
unicode_val_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;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
if (hard_write(fd, buf, bptr) != bptr) {
|
||||
fail:
|
||||
mem_free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
ref:
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
if (document->nlinks && get_opt_bool("document.dump.references")) {
|
||||
int x;
|
||||
unsigned char *header = "\nReferences\n\n Visible links\n";
|
||||
|
@ -163,11 +163,22 @@ init_form_state(struct form_control *fc, struct form_state *fs)
|
||||
case FC_TEXTAREA:
|
||||
fs->value = stracpy(fc->default_value);
|
||||
fs->state = strlen(fc->default_value);
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (fc->type == FC_TEXT)
|
||||
fs->state_cell = utf8_ptr2cells(fs->value, NULL);
|
||||
if (fc->type == FC_PASSWORD)
|
||||
fs->state_cell = utf8_ptr2chars(fs->value, NULL);
|
||||
if (fc->type == FC_TEXTAREA)
|
||||
fs->state_cell = 0;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
fs->vpos = 0;
|
||||
break;
|
||||
case FC_FILE:
|
||||
fs->value = stracpy("");
|
||||
fs->state = 0;
|
||||
#ifdef CONFIG_UTF_8
|
||||
fs->state_cell = 0;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
fs->vpos = 0;
|
||||
break;
|
||||
case FC_SELECT:
|
||||
@ -330,21 +341,27 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
|
||||
dy = box->y - vs->y;
|
||||
switch (fc->type) {
|
||||
unsigned char *s;
|
||||
#ifdef CONFIG_UTF_8
|
||||
unsigned char *text, *end;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
int len;
|
||||
int i, x, y;
|
||||
|
||||
case FC_TEXT:
|
||||
case FC_PASSWORD:
|
||||
case FC_FILE:
|
||||
int_bounds(&fs->vpos, fs->state - fc->size + 1, fs->state);
|
||||
if (!link->npoints) break;
|
||||
|
||||
y = link->points[0].y + dy;
|
||||
if (!row_is_in_box(box, y))
|
||||
break;
|
||||
|
||||
len = strlen(fs->value) - fs->vpos;
|
||||
x = link->points[0].x + dx;
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) goto utf_8;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
int_bounds(&fs->vpos, fs->state - fc->size + 1, fs->state);
|
||||
len = strlen(fs->value) - fs->vpos;
|
||||
|
||||
for (i = 0; i < fc->size; i++, x++) {
|
||||
unsigned char data;
|
||||
@ -360,6 +377,43 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
|
||||
draw_char_data(term, x, y, data);
|
||||
}
|
||||
break;
|
||||
#ifdef CONFIG_UTF_8
|
||||
utf_8:
|
||||
end = NULL; /* Shut up the compiler. */
|
||||
int_bounds(&fs->vpos, fs->state_cell - fc->size + 1, fs->state_cell);
|
||||
if (fc->type == FC_PASSWORD)
|
||||
len = utf8_ptr2chars(fs->value + fs->vpos, NULL);
|
||||
else
|
||||
len = utf8_ptr2cells(fs->value + fs->vpos, NULL);
|
||||
text = fs->value;
|
||||
end = strchr(text, '\0');
|
||||
|
||||
|
||||
for (i = 0; i < fc->size; i++, x++) {
|
||||
unicode_val_T data;
|
||||
|
||||
if (!col_is_in_box(box, x)) continue;
|
||||
|
||||
if (fs->value && i >= -fs->vpos && i < len) {
|
||||
if (fc->type != FC_PASSWORD)
|
||||
data = utf_8_to_unicode(&text, end);
|
||||
else
|
||||
data = '*';
|
||||
} else
|
||||
data = '_';
|
||||
|
||||
if (unicode_to_cell(data) == 2) {
|
||||
if (i + 1 < fc->size) {
|
||||
draw_char_data(term, x++, y, data);
|
||||
data = UCS_NO_CHAR;
|
||||
i++;
|
||||
} else
|
||||
data = ' ';
|
||||
}
|
||||
draw_char_data(term, x, y, data);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
case FC_TEXTAREA:
|
||||
draw_textarea(term, fs, doc_view, link);
|
||||
break;
|
||||
@ -378,6 +432,9 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
|
||||
else
|
||||
/* XXX: when can this happen? --pasky */
|
||||
s = "";
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) goto utf_8_select;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
len = s ? strlen(s) : 0;
|
||||
for (i = 0; i < link->npoints; i++) {
|
||||
x = link->points[i].x + dx;
|
||||
@ -386,6 +443,36 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
|
||||
draw_char_data(term, x, y, i < len ? s[i] : '_');
|
||||
}
|
||||
break;
|
||||
#ifdef CONFIG_UTF_8
|
||||
utf_8_select:
|
||||
text = s;
|
||||
end = strchr(s, '\0');
|
||||
len = utf8_ptr2cells(text, end);
|
||||
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)) {
|
||||
unicode_val_T data;
|
||||
if (i < len) {
|
||||
int cell;
|
||||
|
||||
data = utf_8_to_unicode(&s, end);
|
||||
cell = unicode_to_cell(data);
|
||||
if (i + 1 < len && cell == 2) {
|
||||
draw_char_data(term, x++, y, data);
|
||||
|
||||
data = UCS_NO_CHAR;
|
||||
i++;
|
||||
} else if (cell == 2) {
|
||||
data = ' ';
|
||||
}
|
||||
} else
|
||||
data = '_';
|
||||
draw_char_data(term, x, y, data);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
case FC_SUBMIT:
|
||||
case FC_IMAGE:
|
||||
case FC_RESET:
|
||||
@ -1195,6 +1282,9 @@ field_op(struct session *ses, struct document_view *doc_view,
|
||||
unsigned char *text;
|
||||
int length;
|
||||
enum frame_event_status status = FRAME_EVENT_REFRESH;
|
||||
#ifdef CONFIG_UTF_8
|
||||
int utf8 = ses->tab->term->utf8;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
assert(ses && doc_view && link && ev);
|
||||
if_assert_failed return FRAME_EVENT_OK;
|
||||
@ -1214,49 +1304,140 @@ field_op(struct session *ses, struct document_view *doc_view,
|
||||
|
||||
switch (action_id) {
|
||||
case ACT_EDIT_LEFT:
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (fc->type == FC_TEXTAREA) {
|
||||
status = textarea_op_left(fs, fc, utf8);
|
||||
break;
|
||||
}
|
||||
if (utf8) {
|
||||
int old_state = fs->state;
|
||||
unsigned char *new_value;
|
||||
|
||||
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
|
||||
fs->state = new_value - fs->value;
|
||||
|
||||
if (old_state != fs->state) {
|
||||
if (fc->type == FC_PASSWORD)
|
||||
fs->state_cell = int_max(fs->state_cell - 1, 0);
|
||||
else
|
||||
fs->state_cell = int_max(utf8_char2cells(new_value, NULL) - 1, 0);
|
||||
}
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
fs->state = int_max(fs->state - 1, 0);
|
||||
break;
|
||||
case ACT_EDIT_RIGHT:
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (fc->type == FC_TEXTAREA) {
|
||||
status = textarea_op_right(fs, fc, utf8);
|
||||
break;
|
||||
}
|
||||
if (utf8) {
|
||||
unsigned char *text = fs->value + fs->state;
|
||||
unsigned char *end = strchr(text, '\0');
|
||||
int old_state = fs->state;
|
||||
unicode_val_T data = utf_8_to_unicode(&text, end);
|
||||
|
||||
fs->state = (int)(text - fs->value);
|
||||
if (old_state != fs->state) {
|
||||
if (fc->type == FC_PASSWORD)
|
||||
fs->state_cell = int_min(fs->state_cell + 1,
|
||||
utf8_ptr2cells(fs->value, NULL));
|
||||
else
|
||||
fs->state_cell += unicode_to_cell(data);
|
||||
}
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
fs->state = int_min(fs->state + 1, strlen(fs->value));
|
||||
break;
|
||||
case ACT_EDIT_HOME:
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (fc->type == FC_TEXTAREA) {
|
||||
status = textarea_op_home(fs, fc, utf8);
|
||||
} else {
|
||||
fs->state = 0;
|
||||
fs->state_cell = 0;
|
||||
}
|
||||
#else
|
||||
if (fc->type == FC_TEXTAREA) {
|
||||
status = textarea_op_home(fs, fc);
|
||||
} else {
|
||||
fs->state = 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
break;
|
||||
case ACT_EDIT_UP:
|
||||
if (fc->type != FC_TEXTAREA)
|
||||
status = FRAME_EVENT_IGNORED;
|
||||
else
|
||||
#ifdef CONFIG_UTF_8
|
||||
status = textarea_op_up(fs, fc, utf8);
|
||||
#else
|
||||
status = textarea_op_up(fs, fc);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
break;
|
||||
case ACT_EDIT_DOWN:
|
||||
if (fc->type != FC_TEXTAREA)
|
||||
status = FRAME_EVENT_IGNORED;
|
||||
else
|
||||
#ifdef CONFIG_UTF_8
|
||||
status = textarea_op_down(fs, fc, utf8);
|
||||
#else
|
||||
status = textarea_op_down(fs, fc);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
break;
|
||||
case ACT_EDIT_END:
|
||||
if (fc->type == FC_TEXTAREA) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
status = textarea_op_end(fs, fc, utf8);
|
||||
#else
|
||||
status = textarea_op_end(fs, fc);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
} else {
|
||||
fs->state = strlen(fs->value);
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (utf8 && fc->type != FC_PASSWORD)
|
||||
fs->state_cell = utf8_ptr2cells(fs->value,
|
||||
fs->value + fs->state);
|
||||
else if(utf8)
|
||||
fs->state_cell = utf8_ptr2chars(fs->value,
|
||||
fs->value + fs->state);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
}
|
||||
break;
|
||||
case ACT_EDIT_BEGINNING_OF_BUFFER:
|
||||
if (fc->type == FC_TEXTAREA) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
status = textarea_op_bob(fs, fc, utf8);
|
||||
#else
|
||||
status = textarea_op_bob(fs, fc);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
} else {
|
||||
fs->state = 0;
|
||||
}
|
||||
#ifdef CONFIG_UTF_8
|
||||
fs->state_cell = 0;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
break;
|
||||
case ACT_EDIT_END_OF_BUFFER:
|
||||
if (fc->type == FC_TEXTAREA) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
status = textarea_op_eob(fs, fc, utf8);
|
||||
#else
|
||||
status = textarea_op_eob(fs, fc);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
} else {
|
||||
fs->state = strlen(fs->value);
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (utf8 && fc->type != FC_PASSWORD)
|
||||
fs->state_cell = utf8_ptr2cells(fs->value,
|
||||
fs->value + fs->state);
|
||||
else if(utf8)
|
||||
fs->state_cell = utf8_ptr2chars(fs->value,
|
||||
fs->value + fs->state);
|
||||
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
}
|
||||
break;
|
||||
case ACT_EDIT_OPEN_EXTERNAL:
|
||||
@ -1274,6 +1455,9 @@ field_op(struct session *ses, struct document_view *doc_view,
|
||||
if (!form_field_is_readonly(fc))
|
||||
fs->value[0] = 0;
|
||||
fs->state = 0;
|
||||
#ifdef CONFIG_UTF_8
|
||||
fs->state_cell = 0;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
break;
|
||||
case ACT_EDIT_PASTE_CLIPBOARD:
|
||||
if (form_field_is_readonly(fc)) break;
|
||||
@ -1289,13 +1473,27 @@ field_op(struct session *ses, struct document_view *doc_view,
|
||||
fs->value = v;
|
||||
memmove(v, text, length + 1);
|
||||
fs->state = strlen(fs->value);
|
||||
#ifdef CONFIG_UTF_8
|
||||
if(utf8 && fc->type == FC_PASSWORD)
|
||||
fs->state_cell = utf8_ptr2chars(fs->value,
|
||||
fs->value + fs->state);
|
||||
else if (utf8 && fc->type == FC_TEXTAREA)
|
||||
fs->state_cell = 0;
|
||||
else if (utf8)
|
||||
fs->state_cell = utf8_ptr2cells(fs->value,
|
||||
fs->value + fs->state);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
}
|
||||
}
|
||||
mem_free(text);
|
||||
break;
|
||||
case ACT_EDIT_ENTER:
|
||||
if (fc->type == FC_TEXTAREA) {
|
||||
#ifdef CONFIG_UTF_8
|
||||
status = textarea_op_enter(fs, fc, utf8);
|
||||
#else
|
||||
status = textarea_op_enter(fs, fc);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1320,12 +1518,33 @@ field_op(struct session *ses, struct document_view *doc_view,
|
||||
status = FRAME_EVENT_OK;
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (utf8) {
|
||||
int old_state = fs->state;
|
||||
unsigned char *new_value;
|
||||
|
||||
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
|
||||
fs->state = new_value - fs->value;
|
||||
|
||||
if (old_state != fs->state) {
|
||||
if (fc->type == FC_TEXTAREA)
|
||||
fs->state_cell = 0;
|
||||
else if (fc->type == FC_PASSWORD)
|
||||
fs->state_cell = int_max(fs->state_cell - 1, 0);
|
||||
else
|
||||
fs->state_cell -= utf8_char2cells(new_value, NULL);
|
||||
length = strlen(fs->value + old_state) + 1;
|
||||
memmove(new_value, fs->value + old_state, length);
|
||||
}
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
length = strlen(fs->value + fs->state) + 1;
|
||||
text = fs->value + fs->state;
|
||||
|
||||
memmove(text - 1, text, length);
|
||||
fs->state--;
|
||||
}
|
||||
break;
|
||||
case ACT_EDIT_DELETE:
|
||||
if (form_field_is_readonly(fc)) {
|
||||
@ -1338,7 +1557,20 @@ field_op(struct session *ses, struct document_view *doc_view,
|
||||
status = FRAME_EVENT_OK;
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_UTF_8
|
||||
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;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
text = fs->value + fs->state;
|
||||
|
||||
memmove(text, text + 1, length - fs->state);
|
||||
@ -1368,6 +1600,18 @@ field_op(struct session *ses, struct document_view *doc_view,
|
||||
memmove(text, fs->value + fs->state, length);
|
||||
|
||||
fs->state = (int) (text - fs->value);
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (utf8) {
|
||||
if(fc->type == FC_PASSWORD)
|
||||
fs->state_cell = utf8_ptr2cells(fs->value,
|
||||
fs->value + fs->state);
|
||||
else if (fc->type == FC_TEXTAREA)
|
||||
fs->state_cell = 0;
|
||||
else
|
||||
fs->state_cell = utf8_ptr2cells(fs->value,
|
||||
fs->value + fs->state);
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
break;
|
||||
case ACT_EDIT_KILL_TO_EOL:
|
||||
if (form_field_is_readonly(fc)) {
|
||||
@ -1467,12 +1711,54 @@ 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)) {
|
||||
#ifndef CONFIG_UTF_8
|
||||
|| !insert_in_string(&fs->value, fs->state, "?", 1)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
)
|
||||
{
|
||||
status = FRAME_EVENT_OK;
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_UTF_8
|
||||
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;
|
||||
if (fc->type == FC_PASSWORD)
|
||||
fs->state_cell++;
|
||||
else if (fc->type == FC_TEXTAREA)
|
||||
fs->state_cell = 0;
|
||||
else
|
||||
fs->state_cell += unicode_to_cell(data);
|
||||
i = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 6) {
|
||||
i = 0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
#else
|
||||
fs->value[fs->state++] = get_kbd_key(ev);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,9 @@ struct form_state {
|
||||
|
||||
unsigned char *value;
|
||||
int state;
|
||||
#ifdef CONFIG_UTF_8
|
||||
int state_cell;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
int vpos;
|
||||
int vypos;
|
||||
|
||||
|
@ -114,6 +114,9 @@ get_link_cursor_offset(struct document_view *doc_view, struct link *link)
|
||||
{
|
||||
struct form_control *fc;
|
||||
struct form_state *fs;
|
||||
#ifdef CONFIG_UTF_8
|
||||
int utf8 = doc_view->document->options.utf8;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
switch (link->type) {
|
||||
case LINK_CHECKBOX:
|
||||
@ -125,12 +128,21 @@ 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);
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (utf8) {
|
||||
return fs ? fs->state_cell - fs->vpos : 0;
|
||||
} else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
return fs ? fs->state - fs->vpos : 0;
|
||||
|
||||
case LINK_AREA:
|
||||
fc = get_link_form_control(link);
|
||||
fs = find_form_state(doc_view, fc);
|
||||
#ifdef CONFIG_UTF_8
|
||||
return fs ? area_cursor(fc, fs, utf8) : 0;
|
||||
#else
|
||||
return fs ? area_cursor(fc, fs) : 0;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
case LINK_HYPERTEXT:
|
||||
case LINK_MAP:
|
||||
@ -1342,7 +1354,7 @@ end:
|
||||
do_menu(term, mi, ses, 1);
|
||||
}
|
||||
|
||||
/* Return current link's title. Pretty trivial. */
|
||||
/* Return current link's title. */
|
||||
unsigned char *
|
||||
get_current_link_title(struct document_view *doc_view)
|
||||
{
|
||||
@ -1356,7 +1368,29 @@ get_current_link_title(struct document_view *doc_view)
|
||||
|
||||
link = get_current_link(doc_view);
|
||||
|
||||
return (link && link->title && *link->title) ? stracpy(link->title) : NULL;
|
||||
if (link && link->title && *link->title) {
|
||||
unsigned char *link_title, *src;
|
||||
struct conv_table *convert_table;
|
||||
|
||||
convert_table = get_translation_table(doc_view->document->cp,
|
||||
doc_view->document->options.cp);
|
||||
|
||||
link_title = convert_string(convert_table, link->title,
|
||||
strlen(link->title),
|
||||
doc_view->document->options.cp,
|
||||
CSM_DEFAULT, NULL, NULL, NULL);
|
||||
/* Remove illicit chars. */
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (link_title && !doc_view->document->options.utf8)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
for (src = link_title; *src; src++)
|
||||
if (!isprint(*src) || iscntrl(*src))
|
||||
*src = '*';
|
||||
|
||||
return link_title;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
@ -1401,6 +1435,11 @@ get_current_link_info(struct session *ses, struct document_view *doc_view)
|
||||
add_char_to_string(&str, ')');
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8)
|
||||
decode_uri_string(&str);
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
decode_uri_string_for_display(&str);
|
||||
return str.source;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ struct session;
|
||||
struct term_event;
|
||||
struct terminal;
|
||||
struct uri;
|
||||
struct conv_table;
|
||||
|
||||
void set_link(struct document_view *doc_view);
|
||||
void clear_link(struct terminal *term, struct document_view *doc_view);
|
||||
|
@ -9,6 +9,11 @@
|
||||
#endif
|
||||
|
||||
#include <ctype.h> /* tolower(), isprint() */
|
||||
|
||||
#if defined(CONFIG_UTF_8) && defined(HAVE_WCTYPE_H)
|
||||
#include <wctype.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h> /* FreeBSD needs this before regex.h */
|
||||
#ifdef HAVE_REGEX_H
|
||||
#include <regex.h>
|
||||
@ -22,6 +27,7 @@
|
||||
#include "config/kbdbind.h"
|
||||
#include "document/document.h"
|
||||
#include "document/view.h"
|
||||
#include "intl/charsets.h"
|
||||
#include "intl/gettext/libintl.h"
|
||||
#include "main/event.h"
|
||||
#include "main/module.h"
|
||||
@ -44,9 +50,15 @@
|
||||
|
||||
static INIT_INPUT_HISTORY(search_history);
|
||||
|
||||
#undef UCHAR
|
||||
#ifdef CONFIG_UTF_8
|
||||
#define UCHAR unicode_val_T
|
||||
#else
|
||||
#define UCHAR unsigned char
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
add_srch_chr(struct document *document, unsigned char c, int x, int y, int nn)
|
||||
add_srch_chr(struct document *document, UCHAR c, int x, int y, int nn)
|
||||
{
|
||||
assert(document);
|
||||
if_assert_failed return;
|
||||
@ -146,7 +158,7 @@ get_srch(struct document *document)
|
||||
x++);
|
||||
|
||||
for (; x < width; x++) {
|
||||
unsigned char c = document->data[y].chars[x].data;
|
||||
UCHAR c = document->data[y].chars[x].data;
|
||||
int count = 0;
|
||||
int xx;
|
||||
|
||||
@ -441,18 +453,58 @@ is_in_range_regex(struct document *document, int y, int height,
|
||||
}
|
||||
#endif /* HAVE_REGEX_H */
|
||||
|
||||
/* Returns an allocated string which is a lowered copy of passed one. */
|
||||
static unsigned char *
|
||||
lowered_string(unsigned char *text, int textlen)
|
||||
static UCHAR *
|
||||
memacpy_u(unsigned char *text, int textlen, int utf8)
|
||||
{
|
||||
unsigned char *ret;
|
||||
#ifdef CONFIG_UTF_8
|
||||
UCHAR *mem = mem_alloc((textlen + 1) * sizeof(UCHAR));
|
||||
|
||||
if (textlen < 0) textlen = strlen(text);
|
||||
if (!mem) return NULL;
|
||||
if (utf8) {
|
||||
int i;
|
||||
|
||||
ret = mem_calloc(1, textlen + 1);
|
||||
for (i = 0; i < textlen; i++)
|
||||
mem[i] = utf_8_to_unicode(&text, text + 7);
|
||||
} else {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < textlen; i++)
|
||||
mem[i] = text[i];
|
||||
}
|
||||
mem[textlen] = 0;
|
||||
return mem;
|
||||
#else
|
||||
return memacpy(text, textlen);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
strlen_u(unsigned char *text, int utf8)
|
||||
{
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (utf8)
|
||||
return strlen_utf8(&text);
|
||||
#endif
|
||||
return strlen(text);
|
||||
|
||||
}
|
||||
|
||||
/* Returns an allocated string which is a lowered copy of passed one. */
|
||||
static UCHAR *
|
||||
lowered_string(unsigned char *text, int textlen, int utf8)
|
||||
{
|
||||
UCHAR *ret;
|
||||
|
||||
if (textlen < 0) textlen = strlen_u(text, utf8);
|
||||
|
||||
ret = memacpy_u(text, textlen, utf8);
|
||||
if (ret && textlen) {
|
||||
do {
|
||||
ret[textlen] = tolower(text[textlen]);
|
||||
#if defined(CONFIG_UTF_8) && defined(HAVE_WCTYPE_H)
|
||||
ret[textlen] = utf8 ? towlower(ret[textlen]) : tolower(ret[textlen]);
|
||||
#else
|
||||
ret[textlen] = tolower(ret[textlen]);
|
||||
#endif
|
||||
} while (textlen--);
|
||||
}
|
||||
|
||||
@ -463,14 +515,14 @@ static int
|
||||
is_in_range_plain(struct document *document, int y, int height,
|
||||
unsigned char *text, int textlen,
|
||||
int *min, int *max,
|
||||
struct search *s1, struct search *s2)
|
||||
struct search *s1, struct search *s2, int utf8)
|
||||
{
|
||||
int yy = y + height;
|
||||
unsigned char *txt;
|
||||
UCHAR *txt;
|
||||
int found = 0;
|
||||
int case_sensitive = get_opt_bool("document.browse.search.case");
|
||||
|
||||
txt = case_sensitive ? stracpy(text) : lowered_string(text, textlen);
|
||||
txt = case_sensitive ? memacpy_u(text, textlen, utf8) : lowered_string(text, textlen, utf8);
|
||||
if (!txt) return -1;
|
||||
|
||||
/* TODO: This is a great candidate for nice optimizations. Fresh CS
|
||||
@ -478,9 +530,11 @@ is_in_range_plain(struct document *document, int y, int height,
|
||||
* trivial, probably a starter; very fast as well) or Turbo-BM (or
|
||||
* maybe some other Boyer-Moore variant, I don't feel that strong in
|
||||
* this area), hmm? >:) --pasky */
|
||||
|
||||
#if defined(CONFIG_UTF_8) && defined(HAVE_WCTYPE_H)
|
||||
#define maybe_tolower(c) (case_sensitive ? (c) : utf8 ? towlower(c) : tolower(c))
|
||||
#else
|
||||
#define maybe_tolower(c) (case_sensitive ? (c) : tolower(c))
|
||||
|
||||
#endif
|
||||
for (; s1 <= s2; s1++) {
|
||||
int i;
|
||||
|
||||
@ -513,18 +567,23 @@ srch_failed:
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
is_in_range(struct document *document, int y, int height,
|
||||
unsigned char *text, int *min, int *max)
|
||||
{
|
||||
struct search *s1, *s2;
|
||||
int textlen;
|
||||
int utf8 = 0;
|
||||
|
||||
assert(document && text && min && max);
|
||||
if_assert_failed return -1;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
utf8 = document->options.utf8;
|
||||
#endif
|
||||
*min = INT_MAX, *max = 0;
|
||||
textlen = strlen(text);
|
||||
textlen = strlen_u(text, utf8);
|
||||
|
||||
if (get_range(document, y, height, textlen, &s1, &s2))
|
||||
return 0;
|
||||
@ -535,7 +594,7 @@ is_in_range(struct document *document, int y, int height,
|
||||
min, max, s1, s2);
|
||||
#endif
|
||||
return is_in_range_plain(document, y, height, text, textlen,
|
||||
min, max, s1, s2);
|
||||
min, max, s1, s2, utf8);
|
||||
}
|
||||
|
||||
#define realloc_points(pts, size) \
|
||||
@ -543,24 +602,28 @@ is_in_range(struct document *document, int y, int height,
|
||||
|
||||
static void
|
||||
get_searched_plain(struct document_view *doc_view, struct point **pt, int *pl,
|
||||
int l, struct search *s1, struct search *s2)
|
||||
int l, struct search *s1, struct search *s2, int utf8)
|
||||
{
|
||||
unsigned char *txt;
|
||||
UCHAR *txt;
|
||||
struct point *points = NULL;
|
||||
struct box *box;
|
||||
int xoffset, yoffset;
|
||||
int len = 0;
|
||||
int case_sensitive = get_opt_bool("document.browse.search.case");
|
||||
|
||||
txt = case_sensitive ? stracpy(*doc_view->search_word)
|
||||
: lowered_string(*doc_view->search_word, l);
|
||||
txt = case_sensitive ? memacpy_u(*doc_view->search_word, l, utf8)
|
||||
: lowered_string(*doc_view->search_word, l, utf8);
|
||||
if (!txt) return;
|
||||
|
||||
box = &doc_view->box;
|
||||
xoffset = box->x - doc_view->vs->x;
|
||||
yoffset = box->y - doc_view->vs->y;
|
||||
|
||||
#if defined(CONFIG_UTF_8) && defined(HAVE_WCTYPE_H)
|
||||
#define maybe_tolower(c) (case_sensitive ? (c) : utf8 ? towlower(c) : tolower(c))
|
||||
#else
|
||||
#define maybe_tolower(c) (case_sensitive ? (c) : tolower(c))
|
||||
#endif
|
||||
|
||||
for (; s1 <= s2; s1++) {
|
||||
int i;
|
||||
@ -671,7 +734,7 @@ get_searched_regex(struct document_view *doc_view, struct point **pt, int *pl,
|
||||
#endif /* HAVE_REGEX_H */
|
||||
|
||||
static void
|
||||
get_searched(struct document_view *doc_view, struct point **pt, int *pl)
|
||||
get_searched(struct document_view *doc_view, struct point **pt, int *pl, int utf8)
|
||||
{
|
||||
struct search *s1, *s2;
|
||||
int l;
|
||||
@ -683,7 +746,7 @@ get_searched(struct document_view *doc_view, struct point **pt, int *pl)
|
||||
return;
|
||||
|
||||
get_search_data(doc_view->document);
|
||||
l = strlen(*doc_view->search_word);
|
||||
l = strlen_u(*doc_view->search_word, utf8);
|
||||
if (get_range(doc_view->document, doc_view->vs->y,
|
||||
doc_view->box.height, l, &s1, &s2)) {
|
||||
*pt = NULL;
|
||||
@ -697,7 +760,7 @@ get_searched(struct document_view *doc_view, struct point **pt, int *pl)
|
||||
get_searched_regex(doc_view, pt, pl, l, s1, s2);
|
||||
else
|
||||
#endif
|
||||
get_searched_plain(doc_view, pt, pl, l, s1, s2);
|
||||
get_searched_plain(doc_view, pt, pl, l, s1, s2, utf8);
|
||||
}
|
||||
|
||||
/* Highlighting of searched strings. */
|
||||
@ -706,6 +769,7 @@ draw_searched(struct terminal *term, struct document_view *doc_view)
|
||||
{
|
||||
struct point *pt = NULL;
|
||||
int len = 0;
|
||||
int utf8 = 0;
|
||||
|
||||
assert(term && doc_view);
|
||||
if_assert_failed return;
|
||||
@ -713,7 +777,10 @@ draw_searched(struct terminal *term, struct document_view *doc_view)
|
||||
if (!has_search_word(doc_view))
|
||||
return;
|
||||
|
||||
get_searched(doc_view, &pt, &len);
|
||||
#ifdef CONFIG_UTF_8
|
||||
utf8 = doc_view->document->options.utf8;
|
||||
#endif
|
||||
get_searched(doc_view, &pt, &len, utf8);
|
||||
if (len) {
|
||||
int i;
|
||||
struct color_pair *color = get_bfu_color(term, "searched");
|
||||
@ -856,6 +923,11 @@ point_intersect(struct point *p1, int l1, struct point *p2, int l2)
|
||||
static int
|
||||
find_next_link_in_search(struct document_view *doc_view, int direction)
|
||||
{
|
||||
int utf8 = 0;
|
||||
#ifdef CONFIG_UTF_8
|
||||
utf8 = doc_view->document->options.utf8;
|
||||
#endif
|
||||
|
||||
assert(doc_view && doc_view->vs);
|
||||
if_assert_failed return 0;
|
||||
|
||||
@ -879,7 +951,7 @@ find_next_link_in_search(struct document_view *doc_view, int direction)
|
||||
|
||||
nt:
|
||||
link = &doc_view->document->links[doc_view->vs->current_link];
|
||||
get_searched(doc_view, &pt, &len);
|
||||
get_searched(doc_view, &pt, &len, utf8);
|
||||
if (point_intersect(pt, len, link->points, link->npoints)) {
|
||||
mem_free(pt);
|
||||
return 0;
|
||||
@ -1174,7 +1246,7 @@ fixup_typeahead_match(struct session *ses, struct document_view *doc_view)
|
||||
doc_view->box.height += 1;
|
||||
}
|
||||
|
||||
static inline unsigned char
|
||||
static inline UCHAR
|
||||
get_document_char(struct document *document, int x, int y)
|
||||
{
|
||||
return (document->height > y && document->data[y].length > x)
|
||||
@ -1196,7 +1268,7 @@ draw_typeahead_match(struct terminal *term, struct document_view *doc_view,
|
||||
for (i = 0, j = 0; text[j] && i < end; i++, j++) {
|
||||
int x = link->points[i].x;
|
||||
int y = link->points[i].y;
|
||||
unsigned char data = get_document_char(doc_view->document, x, y);
|
||||
UCHAR data = get_document_char(doc_view->document, x, y);
|
||||
|
||||
/* Text wrapping might remove space chars from the link
|
||||
* position array so try to align the matched typeahead text
|
||||
@ -1311,7 +1383,6 @@ text_typeahead_handler(struct input_line *line, int action_id)
|
||||
* clears the last search. */
|
||||
search_for_do(ses, buffer, direction, 0);
|
||||
}
|
||||
goto_current_link(ses, doc_view, 0);
|
||||
return INPUT_LINE_CANCEL;
|
||||
|
||||
case ACT_EDIT_PREVIOUS_ITEM:
|
||||
|
@ -40,6 +40,11 @@
|
||||
struct line_info {
|
||||
int start;
|
||||
int end;
|
||||
#ifdef CONFIG_UTF_8
|
||||
int last_char_width;
|
||||
int split_prev:1;
|
||||
int split_next:1;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
};
|
||||
|
||||
/* We add two extra entries to the table so the ending info can be added
|
||||
@ -47,6 +52,90 @@ struct line_info {
|
||||
#define realloc_line_info(info, size) \
|
||||
mem_align_alloc(info, size, (size) + 3, 0xFF)
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
/* Allocates a line_info table describing the layout of the textarea buffer.
|
||||
*
|
||||
* @width is max width and the offset at which text will be wrapped
|
||||
* @wrap controls how the wrapping of text is performed
|
||||
* @format is non zero the @text will be modified to make it suitable for
|
||||
* encoding it for form posting
|
||||
*/
|
||||
static struct line_info *
|
||||
format_textutf8(unsigned char *text, int width, enum form_wrap wrap, int format)
|
||||
{
|
||||
struct line_info *line = NULL;
|
||||
int line_number = 0;
|
||||
int begin = 0;
|
||||
int pos = 0;
|
||||
int skip;
|
||||
unsigned char *wrappos=NULL;
|
||||
int chars_cells=0; /* Number of console chars on line */
|
||||
|
||||
assert(text);
|
||||
if_assert_failed return NULL;
|
||||
|
||||
/* Allocate the ending entries */
|
||||
if (!realloc_line_info(&line, 0))
|
||||
return NULL;
|
||||
|
||||
while (text[pos]) {
|
||||
int char_cells = utf8_char2cells(&text[pos], NULL);
|
||||
|
||||
if (text[pos] == ' ')
|
||||
wrappos = &text[pos];
|
||||
|
||||
if (text[pos] == '\n') {
|
||||
skip = 1;
|
||||
|
||||
} else if (wrap == FORM_WRAP_NONE || chars_cells + char_cells < width) {
|
||||
pos += utf8charlen(&text[pos]);
|
||||
chars_cells += char_cells;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
if (wrappos) {
|
||||
/* When formatting text for form submitting we
|
||||
* have to apply the wrapping mode. */
|
||||
if (wrap == FORM_WRAP_HARD && format)
|
||||
*wrappos = '\n';
|
||||
pos = wrappos - text;
|
||||
}
|
||||
skip = !!wrappos;
|
||||
}
|
||||
|
||||
if (!realloc_line_info(&line, line_number)) {
|
||||
mem_free_if(line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
line[line_number].last_char_width = char_cells;
|
||||
line[line_number].split_next = !skip;
|
||||
line[line_number].start = begin;
|
||||
line[line_number++].end = pos;
|
||||
line[line_number].split_prev = !skip;
|
||||
|
||||
begin = pos += skip;
|
||||
|
||||
chars_cells = 0;
|
||||
wrappos = NULL;
|
||||
}
|
||||
|
||||
line[line_number].split_next = 0;
|
||||
|
||||
/* Flush the last text before the loop ended */
|
||||
line[line_number].start = begin;
|
||||
line[line_number++].end = pos;
|
||||
|
||||
/* Add end marker */
|
||||
line[line_number].start = line[line_number].end = -1;
|
||||
|
||||
line[line_number].split_next = line[line_number].split_prev = 0;
|
||||
line[0].split_prev = 0;
|
||||
|
||||
return line;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
/* Allocates a line_info table describing the layout of the textarea buffer.
|
||||
*
|
||||
* @width is max width and the offset at which text will be wrapped
|
||||
@ -137,6 +226,59 @@ 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. */
|
||||
#ifdef CONFIG_UTF_8
|
||||
int
|
||||
area_cursor(struct form_control *fc, struct form_state *fs, int utf8)
|
||||
{
|
||||
struct line_info *line;
|
||||
int x, y;
|
||||
|
||||
assert(fc && fs);
|
||||
if_assert_failed return 0;
|
||||
|
||||
if (utf8)
|
||||
line = format_textutf8(fs->value, fc->cols, fc->wrap, 0);
|
||||
else
|
||||
line = format_text(fs->value, fc->cols, fc->wrap, 0);
|
||||
|
||||
if (!line) return 0;
|
||||
|
||||
if (fs->state_cell)
|
||||
y = get_textarea_line_number(line, fs->state_cell);
|
||||
else
|
||||
y = get_textarea_line_number(line, fs->state);
|
||||
|
||||
if (y == -1) {
|
||||
mem_free(line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (utf8) {
|
||||
if (fs->state_cell) {
|
||||
x = utf8_ptr2cells(fs->value + line[y].start,
|
||||
fs->value + fs->state_cell);
|
||||
x += line[y].last_char_width;
|
||||
} else
|
||||
x = utf8_ptr2cells(fs->value + line[y].start,
|
||||
fs->value + fs->state);
|
||||
} else {
|
||||
x = fs->state - line[y].start;
|
||||
if (fc->wrap && x == fc->cols) x--;
|
||||
}
|
||||
|
||||
mem_free(line);
|
||||
|
||||
int_bounds(&fs->vpos, x - fc->cols + 1, x);
|
||||
int_bounds(&fs->vypos, y - fc->rows + 1, y);
|
||||
|
||||
x -= fs->vpos;
|
||||
y -= fs->vypos;
|
||||
|
||||
return y * fc->cols + x;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
area_cursor(struct form_control *fc, struct form_state *fs)
|
||||
{
|
||||
@ -169,6 +311,91 @@ area_cursor(struct form_control *fc, struct form_state *fs)
|
||||
|
||||
return y * fc->cols + x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
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;
|
||||
struct form_control *fc;
|
||||
struct box *box;
|
||||
int vx, vy;
|
||||
int sl, ye;
|
||||
int x, xbase, y;
|
||||
|
||||
assert(term && doc_view && doc_view->document && doc_view->vs && link);
|
||||
if_assert_failed 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, 1);
|
||||
linex = format_textutf8(fs->value, fc->cols, fc->wrap, 0);
|
||||
if (!linex) return;
|
||||
line = linex;
|
||||
sl = fs->vypos;
|
||||
while (line->start != -1 && sl) sl--, line++;
|
||||
|
||||
xbase = 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;
|
||||
|
||||
text += utf8_cells2bytes(text, fs->vpos, end);
|
||||
|
||||
if (!row_is_in_box(box, y)) continue;
|
||||
|
||||
for (i = 0, x = xbase; i < fc->cols; i++, x++) {
|
||||
unicode_val_T data;
|
||||
|
||||
if (!col_is_in_box(box, x))
|
||||
continue;
|
||||
|
||||
if (i >= -fs->vpos && text < end) {
|
||||
int cell;
|
||||
|
||||
data = utf_8_to_unicode(&text, end);
|
||||
cell = unicode_to_cell(data);
|
||||
if (cell == 2) {
|
||||
draw_char_data(term, x++, y, data);
|
||||
i++;
|
||||
data = UCS_NO_CHAR;
|
||||
}
|
||||
|
||||
} else
|
||||
data = '_';
|
||||
|
||||
draw_char_data(term, x, y, data);
|
||||
}
|
||||
}
|
||||
|
||||
for (; y < ye; y++) {
|
||||
int i;
|
||||
|
||||
if (!row_is_in_box(box, y)) continue;
|
||||
|
||||
for (i = 0, x = xbase; i < fc->cols; i++, x++) {
|
||||
if (col_is_in_box(box, x))
|
||||
draw_char_data(term, x, y, '_');
|
||||
}
|
||||
}
|
||||
|
||||
mem_free(linex);
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
void
|
||||
draw_textarea(struct terminal *term, struct form_state *fs,
|
||||
@ -183,6 +410,13 @@ draw_textarea(struct terminal *term, struct form_state *fs,
|
||||
|
||||
assert(term && doc_view && doc_view->document && doc_view->vs && link);
|
||||
if_assert_failed return;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (term->utf8) {
|
||||
draw_textarea_utf8(term, fs, doc_view, link);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
fc = get_link_form_control(link);
|
||||
assertm(fc, "link %d has no form control", (int) (link - doc_view->document->links));
|
||||
if_assert_failed return;
|
||||
@ -192,7 +426,11 @@ draw_textarea(struct terminal *term, struct form_state *fs,
|
||||
vy = doc_view->vs->y;
|
||||
|
||||
if (!link->npoints) return;
|
||||
#ifdef CONFIG_UTF_8
|
||||
area_cursor(fc, fs, 0);
|
||||
#else
|
||||
area_cursor(fc, fs);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
linex = format_text(fs->value, fc->cols, fc->wrap, 0);
|
||||
if (!linex) return;
|
||||
line = linex;
|
||||
@ -257,6 +495,7 @@ encode_textarea(struct submitted_value *sv)
|
||||
|
||||
/* We need to reformat text now if it has to be wrapped hard, just
|
||||
* before encoding it. */
|
||||
/* TODO: Do we need here UTF-8 format or not? --scrool */
|
||||
blabla = format_text(sv->value, fc->cols, fc->wrap, 1);
|
||||
mem_free_if(blabla);
|
||||
|
||||
@ -447,6 +686,39 @@ menu_textarea_edit(struct terminal *term, void *xxx, void *ses_)
|
||||
textarea_edit(0, term, fs, doc_view, link);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
static enum frame_event_status
|
||||
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;
|
||||
int state_cell;
|
||||
|
||||
assert(fs && fs->value && fc);
|
||||
if_assert_failed return FRAME_EVENT_OK;
|
||||
|
||||
if (utf8)
|
||||
line = format_textutf8(fs->value, fc->cols, fc->wrap, 0);
|
||||
else
|
||||
line = format_text(fs->value, fc->cols, fc->wrap, 0);
|
||||
if (!line) return FRAME_EVENT_OK;
|
||||
|
||||
current = get_textarea_line_number(line, fs->state);
|
||||
state = fs->state;
|
||||
state_cell = fs->state_cell;
|
||||
if (do_op(fs, line, current, utf8)) {
|
||||
mem_free(line);
|
||||
return FRAME_EVENT_IGNORED;
|
||||
}
|
||||
|
||||
mem_free(line);
|
||||
return (fs->state == state && fs->state_cell == state_cell)
|
||||
? FRAME_EVENT_OK : FRAME_EVENT_REFRESH;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
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))
|
||||
@ -471,14 +743,88 @@ textarea_op(struct form_state *fs, struct form_control *fc,
|
||||
|
||||
return fs->state == state ? FRAME_EVENT_OK : FRAME_EVENT_REFRESH;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
void
|
||||
new_pos(struct form_state *fs, struct line_info *line, int current, int max_cells)
|
||||
{
|
||||
unsigned char *text = fs->value + line[current].start;
|
||||
unsigned char *end = fs->value + line[current].end;
|
||||
int cells = 0;
|
||||
|
||||
while(cells < max_cells) {
|
||||
unicode_val_T data = utf_8_to_unicode(&text, end);
|
||||
|
||||
if (data == UCS_NO_CHAR) break;
|
||||
cells += unicode_to_cell(data);
|
||||
}
|
||||
fs->state = (int)(text - fs->value);
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
static int
|
||||
#ifdef CONFIG_UTF_8
|
||||
do_op_home(struct form_state *fs, struct line_info *line, int current, int utf8)
|
||||
#else
|
||||
do_op_home(struct form_state *fs, struct line_info *line, int current)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
if (current != -1) fs->state = line[current].start;
|
||||
if (current == -1)
|
||||
return 0;
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (utf8)
|
||||
fs->state = line[current - !!fs->state_cell].start;
|
||||
else
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
fs->state = line[current].start;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
static int
|
||||
do_op_up(struct form_state *fs, struct line_info *line, int current, int utf8)
|
||||
{
|
||||
int old_state;
|
||||
|
||||
if (current == -1) return 0;
|
||||
|
||||
if (!(current - !!fs->state_cell)) return 1;
|
||||
|
||||
if (!utf8) {
|
||||
fs->state -= line[current].start - line[current-1].start;
|
||||
int_upper_bound(&fs->state, line[current-1].end);
|
||||
return 0;
|
||||
}
|
||||
|
||||
old_state = fs->state;
|
||||
if (fs->state_cell) {
|
||||
int len = utf8_ptr2cells(fs->value + line[current - 1].start,
|
||||
fs->value + fs->state_cell);
|
||||
|
||||
new_pos(fs, line, current - 2, len + line[current - 1].last_char_width);
|
||||
} else {
|
||||
int len = utf8_ptr2cells(fs->value + line[current].start,
|
||||
fs->value + fs->state);
|
||||
|
||||
new_pos(fs, line, current - 1, len);
|
||||
}
|
||||
|
||||
if (old_state != fs->state ) {
|
||||
if (fs->state_cell && fs->state == line[current - 1].start) {
|
||||
unsigned char *new_value;
|
||||
|
||||
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
|
||||
fs->state_cell = new_value - fs->value;
|
||||
} else
|
||||
fs->state_cell = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int
|
||||
do_op_up(struct form_state *fs, struct line_info *line, int current)
|
||||
{
|
||||
@ -489,6 +835,49 @@ do_op_up(struct form_state *fs, struct line_info *line, int current)
|
||||
int_upper_bound(&fs->state, line[current-1].end);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
static int
|
||||
do_op_down(struct form_state *fs, struct line_info *line, int current, int utf8)
|
||||
{
|
||||
int old_state;
|
||||
|
||||
if (current == -1) return 0;
|
||||
|
||||
if (line[current + 1 - !!fs->state_cell].start == -1) return 1;
|
||||
|
||||
if (!utf8) {
|
||||
fs->state += line[current+1].start - line[current].start;
|
||||
int_upper_bound(&fs->state, line[current+1].end);
|
||||
return 0;
|
||||
}
|
||||
|
||||
old_state = fs->state;
|
||||
if (fs->state_cell) {
|
||||
int len = utf8_ptr2cells(fs->value + line[current - 1].start,
|
||||
fs->value + fs->state_cell);
|
||||
|
||||
new_pos(fs, line, current, len + line[current - 1].last_char_width);
|
||||
} else {
|
||||
int len = utf8_ptr2cells(fs->value + line[current].start,
|
||||
fs->value + fs->state);
|
||||
|
||||
new_pos(fs, line, current + 1, len);
|
||||
}
|
||||
if (old_state != fs->state ) {
|
||||
if (fs->state_cell && fs->state == line[current+1].start) {
|
||||
unsigned char *new_value;
|
||||
|
||||
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
|
||||
fs->state_cell = new_value - fs->value;
|
||||
} else
|
||||
fs->state_cell = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int
|
||||
do_op_down(struct form_state *fs, struct line_info *line, int current)
|
||||
@ -500,6 +889,39 @@ do_op_down(struct form_state *fs, struct line_info *line, int current)
|
||||
int_upper_bound(&fs->state, line[current+1].end);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
static int
|
||||
do_op_end(struct form_state *fs, struct line_info *line, int current, int utf8)
|
||||
{
|
||||
if (current == -1) {
|
||||
fs->state = strlen(fs->value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!utf8) {
|
||||
int wrap = line[current + 1].start == line[current].end;
|
||||
|
||||
/* Don't jump to next line when wrapping. */
|
||||
fs->state = int_max(0, line[current].end - wrap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
current -= !!fs->state_cell;
|
||||
fs->state = line[current].end;
|
||||
if (line[current].split_next) {
|
||||
unsigned char *new_value;
|
||||
|
||||
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
|
||||
fs->state_cell = new_value - fs->value;
|
||||
} else {
|
||||
fs->state_cell = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int
|
||||
do_op_end(struct form_state *fs, struct line_info *line, int current)
|
||||
@ -515,9 +937,14 @@ do_op_end(struct form_state *fs, struct line_info *line, int current)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
static int
|
||||
#ifdef CONFIG_UTF_8
|
||||
do_op_bob(struct form_state *fs, struct line_info *line, int current, int utf8)
|
||||
#else
|
||||
do_op_bob(struct form_state *fs, struct line_info *line, int current)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
if (current == -1) return 0;
|
||||
|
||||
@ -527,7 +954,11 @@ do_op_bob(struct form_state *fs, struct line_info *line, int current)
|
||||
}
|
||||
|
||||
static int
|
||||
#ifdef CONFIG_UTF_8
|
||||
do_op_eob(struct form_state *fs, struct line_info *line, int current, int utf8)
|
||||
#else
|
||||
do_op_eob(struct form_state *fs, struct line_info *line, int current)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
if (current == -1) {
|
||||
fs->state = strlen(fs->value);
|
||||
@ -543,50 +974,102 @@ do_op_eob(struct form_state *fs, struct line_info *line, int current)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
enum frame_event_status
|
||||
textarea_op_home(struct form_state *fs, struct form_control *fc, int utf8)
|
||||
{
|
||||
return textarea_op(fs, fc, utf8, do_op_home);
|
||||
}
|
||||
#else
|
||||
enum frame_event_status
|
||||
textarea_op_home(struct form_state *fs, struct form_control *fc)
|
||||
{
|
||||
return textarea_op(fs, fc, do_op_home);
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
enum frame_event_status
|
||||
textarea_op_up(struct form_state *fs, struct form_control *fc, int utf8)
|
||||
{
|
||||
return textarea_op(fs, fc, utf8, do_op_up);
|
||||
}
|
||||
#else
|
||||
enum frame_event_status
|
||||
textarea_op_up(struct form_state *fs, struct form_control *fc)
|
||||
{
|
||||
return textarea_op(fs, fc, do_op_up);
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
enum frame_event_status
|
||||
textarea_op_down(struct form_state *fs, struct form_control *fc, int utf8)
|
||||
{
|
||||
return textarea_op(fs, fc, utf8, do_op_down);
|
||||
}
|
||||
#else
|
||||
enum frame_event_status
|
||||
textarea_op_down(struct form_state *fs, struct form_control *fc)
|
||||
{
|
||||
return textarea_op(fs, fc, do_op_down);
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
enum frame_event_status
|
||||
textarea_op_end(struct form_state *fs, struct form_control *fc, int utf8)
|
||||
{
|
||||
return textarea_op(fs, fc, utf8, do_op_end);
|
||||
}
|
||||
#else
|
||||
enum frame_event_status
|
||||
textarea_op_end(struct form_state *fs, struct form_control *fc)
|
||||
{
|
||||
return textarea_op(fs, fc, do_op_end);
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
/* Set the form state so the cursor is on the first line of the buffer.
|
||||
* Preserve the column if possible. */
|
||||
#ifdef CONFIG_UTF_8
|
||||
enum frame_event_status
|
||||
textarea_op_bob(struct form_state *fs, struct form_control *fc, int utf8)
|
||||
{
|
||||
return textarea_op(fs, fc, utf8, do_op_bob);
|
||||
}
|
||||
#else
|
||||
enum frame_event_status
|
||||
textarea_op_bob(struct form_state *fs, struct form_control *fc)
|
||||
{
|
||||
return textarea_op(fs, fc, do_op_bob);
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
/* Set the form state so the cursor is on the last line of the buffer. Preserve
|
||||
* the column if possible. This is done by getting current and last line and
|
||||
* then shifting the state by the delta of both lines start position bounding
|
||||
* the whole thing to the end of the last line. */
|
||||
#ifdef CONFIG_UTF_8
|
||||
enum frame_event_status
|
||||
textarea_op_eob(struct form_state *fs, struct form_control *fc, int utf8)
|
||||
{
|
||||
return textarea_op(fs, fc, utf8, do_op_eob);
|
||||
}
|
||||
#else
|
||||
enum frame_event_status
|
||||
textarea_op_eob(struct form_state *fs, struct form_control *fc)
|
||||
{
|
||||
return textarea_op(fs, fc, do_op_eob);
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
enum frame_event_status
|
||||
#ifdef CONFIG_UTF_8
|
||||
textarea_op_enter(struct form_state *fs, struct form_control *fc, int utf8)
|
||||
#else
|
||||
textarea_op_enter(struct form_state *fs, struct form_control *fc)
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
{
|
||||
assert(fs && fs->value && fc);
|
||||
if_assert_failed return FRAME_EVENT_OK;
|
||||
@ -600,6 +1083,85 @@ textarea_op_enter(struct form_state *fs, struct form_control *fc)
|
||||
return FRAME_EVENT_REFRESH;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
static int
|
||||
do_op_left(struct form_state *fs, struct line_info *line, int current, int utf8)
|
||||
{
|
||||
int old_state;
|
||||
int new_state;
|
||||
unsigned char *new_value;
|
||||
|
||||
if (!utf8) {
|
||||
fs->state = int_max(fs->state - 1, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fs->state_cell) {
|
||||
fs->state = fs->state_cell;
|
||||
fs->state_cell = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
old_state = fs->state;
|
||||
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
|
||||
new_state = new_value - fs->value;
|
||||
|
||||
if (old_state != new_state) {
|
||||
if (old_state == line[current].start && line[current].split_prev)
|
||||
fs->state_cell = new_state;
|
||||
else
|
||||
fs->state = new_state;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_op_right(struct form_state *fs, struct line_info *line, int current, int utf8)
|
||||
{
|
||||
unsigned char *text, *end;
|
||||
int old_state;
|
||||
|
||||
if (!utf8) {
|
||||
/* TODO: zle */
|
||||
fs->state = int_min(fs->state + 1, strlen(fs->value));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fs->state_cell) {
|
||||
fs->state_cell = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
text = fs->value + fs->state;
|
||||
end = strchr(text, '\0');
|
||||
old_state = fs->state;
|
||||
utf_8_to_unicode(&text, end);
|
||||
|
||||
fs->state = text - fs->value;
|
||||
|
||||
if (old_state != fs->state && line[current].split_next) {
|
||||
fs->state_cell = (fs->state == line[current].end) ? old_state:0;
|
||||
} else if (!line[current].split_next) {
|
||||
fs->state_cell = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
enum frame_event_status
|
||||
textarea_op_left(struct form_state *fs, struct form_control *fc, int utf8)
|
||||
{
|
||||
return textarea_op(fs, fc, utf8, do_op_left);
|
||||
}
|
||||
|
||||
enum frame_event_status
|
||||
textarea_op_right(struct form_state *fs, struct form_control *fc, int utf8)
|
||||
{
|
||||
return textarea_op(fs, fc, utf8, do_op_right);
|
||||
}
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
void
|
||||
set_textarea(struct document_view *doc_view, int direction)
|
||||
@ -607,6 +1169,9 @@ set_textarea(struct document_view *doc_view, int direction)
|
||||
struct form_control *fc;
|
||||
struct form_state *fs;
|
||||
struct link *link;
|
||||
#ifdef CONFIG_UTF_8
|
||||
int utf8 = doc_view->document->options.utf8;
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
assert(doc_view && doc_view->vs && doc_view->document);
|
||||
assert(direction == 1 || direction == -1);
|
||||
@ -627,8 +1192,15 @@ 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. */
|
||||
#ifdef CONFIG_UTF_8
|
||||
if (direction == 1)
|
||||
textarea_op_eob(fs, fc, utf8);
|
||||
else
|
||||
textarea_op_bob(fs, fc, utf8);
|
||||
#else
|
||||
if (direction == 1)
|
||||
textarea_op_eob(fs, fc);
|
||||
else
|
||||
textarea_op_bob(fs, fc);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
}
|
||||
|
@ -13,7 +13,11 @@ struct link;
|
||||
struct session;
|
||||
struct terminal;
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
int area_cursor(struct form_control *fc, struct form_state *fs, int utf8);
|
||||
#else
|
||||
int area_cursor(struct form_control *fc, struct form_state *fs);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
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,6 +25,17 @@ 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_);
|
||||
|
||||
#ifdef CONFIG_UTF_8
|
||||
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);
|
||||
enum frame_event_status textarea_op_left(struct form_state *fs, struct form_control *fc, int utf8);
|
||||
enum frame_event_status textarea_op_right(struct form_state *fs, struct form_control *fc, int utf8);
|
||||
#else
|
||||
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);
|
||||
@ -28,6 +43,7 @@ enum frame_event_status textarea_op_end(struct form_state *fs, struct form_contr
|
||||
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);
|
||||
#endif /* CONFIG_UTF_8 */
|
||||
|
||||
void set_textarea(struct document_view *doc_view, int direction);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user