improvements to wide/multibyte character input and output, using wide
curses functions where applicable git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@2182 35c25a1d-7b9e-4130-9fde-d3aeb78583b8master
parent
164bf36ea8
commit
78ea5e4a8a
22
ChangeLog
22
ChangeLog
|
@ -35,20 +35,21 @@ CVS code -
|
||||||
encodings such as KOI8-R can type properly again. (DLR, found
|
encodings such as KOI8-R can type properly again. (DLR, found
|
||||||
by Arthur Ivanov)
|
by Arthur Ivanov)
|
||||||
- Massively overhaul the input and output routines to support
|
- Massively overhaul the input and output routines to support
|
||||||
buffered input and output, the first steps toward wide
|
buffered input and output, the first steps toward
|
||||||
character input and output, and double-Escape/verbatim input
|
wide/multibyte character input and output, and
|
||||||
of double-byte Unicode characters instead of single-byte ASCII
|
double-Escape/verbatim input of double-byte Unicode characters
|
||||||
characters. New functions do_input(), do_mouse(),
|
instead of single-byte ASCII characters. New functions
|
||||||
do_output(), is_byte_char(), get_buffer(), get_buffer_len(),
|
is_byte_char(), get_buffer(), get_buffer_len(),
|
||||||
buffer_to_keys(), unget_input(), get_input(), parse_kbinput(),
|
buffer_to_keys(), unget_input(), get_input(), parse_kbinput(),
|
||||||
and parse_verbatim_kbinput(); new macro charcpy(); changes to
|
and parse_verbatim_kbinput(); new macro charcpy(); changes to
|
||||||
do_char() (renamed to do_output()), get_edit_input() (renamed
|
do_char() (renamed to do_output()), get_edit_input() (renamed
|
||||||
to do_input() and moved to nano.c), get_edit_mouse() (renamed
|
to do_input() and moved to nano.c), get_edit_mouse() (renamed
|
||||||
do_mouse() and moved to nano.c), do_verbatim_input(),
|
do_mouse() and moved to nano.c), do_verbatim_input(),
|
||||||
do_tab(), main(), and get_ascii_kbinput() (renamed to
|
do_tab(), main(), and get_ascii_kbinput() (renamed to
|
||||||
get_word_kbinput()). (DLR; buffered input/output based on
|
get_word_kbinput()). The wide version of ncurses is required
|
||||||
ideas from mutt 1.4.2.1; double-Escape input of Unicode
|
in order for output to work properly. (DLR; buffered
|
||||||
characters suggested by Michael Piefel)
|
input/output based on ideas from mutt 1.4.2.1; double-Escape
|
||||||
|
input of Unicode characters suggested by Michael Piefel)
|
||||||
- cut.c:
|
- cut.c:
|
||||||
do_cut_text()
|
do_cut_text()
|
||||||
- If keep_cutbuffer is FALSE, only blow away the text in the
|
- If keep_cutbuffer is FALSE, only blow away the text in the
|
||||||
|
@ -132,6 +133,11 @@ CVS code -
|
||||||
- Add a debug message. (DLR)
|
- Add a debug message. (DLR)
|
||||||
- configure.ac:
|
- configure.ac:
|
||||||
- Remove specific references to control key shortcuts. (DLR)
|
- Remove specific references to control key shortcuts. (DLR)
|
||||||
|
- Check for the wide version of ncurses, without which multibyte
|
||||||
|
strings don't seem to be displayed properly. (DLR; check for
|
||||||
|
addwstr() in curses to determine whether it has wide character
|
||||||
|
support inspired by mutt 1.4.2.1i's checking for waddnwstr()
|
||||||
|
for the same reason)
|
||||||
- doc/nanorc.sample:
|
- doc/nanorc.sample:
|
||||||
- Add return to the "c-file" regexes. (DLR)
|
- Add return to the "c-file" regexes. (DLR)
|
||||||
|
|
||||||
|
|
31
configure.ac
31
configure.ac
|
@ -312,28 +312,32 @@ AC_CHECK_FUNCS(getopt_long)
|
||||||
dnl Checks for libraries.
|
dnl Checks for libraries.
|
||||||
if eval "test x$CURSES_LIB_NAME = x"
|
if eval "test x$CURSES_LIB_NAME = x"
|
||||||
then
|
then
|
||||||
AC_CHECK_HEADERS(curses.h ncurses.h)
|
AC_CHECK_HEADERS(ncurses.h)
|
||||||
AC_CHECK_LIB(ncurses, initscr, [CURSES_LIB="-lncurses" CURSES_LIB_NAME=ncurses])
|
AC_CHECK_LIB(ncursesw, addwstr, [CURSES_LIB="-lncursesw" CURSES_LIB_NAME=ncursesw CURSES_LIB_WIDE="yes"])
|
||||||
|
if eval "test x$CURSES_LIB_NAME = x"
|
||||||
|
then
|
||||||
|
AC_CHECK_LIB(ncurses, initscr, [CURSES_LIB="-lncurses" CURSES_LIB_NAME=ncurses])
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if eval "test x$CURSES_LIB_NAME = x"
|
if eval "test x$CURSES_LIB_NAME = x"
|
||||||
then
|
then
|
||||||
AC_CHECK_LIB(curses, initscr, [CURSES_LIB="-lcurses" CURSES_LIB_NAME=curses])
|
AC_CHECK_HEADERS(curses.h)
|
||||||
fi
|
AC_CHECK_LIB(curses, addwstr, [CURSES_LIB="-lcurses" CURSES_LIB_NAME=curses CURSES_LIB_WIDE="yes"])
|
||||||
|
if eval "test x$CURSES_LIB_NAME = x"
|
||||||
if eval "test x$CURSES_LIB_NAME = x"
|
then
|
||||||
then
|
AC_CHECK_LIB(curses, initscr, [CURSES_LIB="-lcurses" CURSES_LIB_NAME=curses])
|
||||||
AC_CHECK_LIB(termcap, tgetent, [CURSES_LIB="-ltermcap" CURSES_LIB_NAME=termcap])
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if eval "test x$CURSES_LIB_NAME = x"
|
if eval "test x$CURSES_LIB_NAME = x"
|
||||||
then
|
then
|
||||||
AC_MSG_WARN([
|
AC_MSG_WARN([
|
||||||
*** No termcap lib available, consider getting the official ncurses
|
*** No curses lib available. Consider getting the official ncurses
|
||||||
*** distribution from ftp://ftp.gnu.org/pub/gnu/ncurses if you get
|
*** distribution from ftp://ftp.gnu.org/pub/gnu/ncurses if you get
|
||||||
*** errors compiling nano.])
|
*** errors compiling nano.])
|
||||||
else
|
else
|
||||||
AC_MSG_RESULT([Using $CURSES_LIB_NAME as the termcap library])
|
AC_MSG_RESULT([Using $CURSES_LIB_NAME as the curses library])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_CHECK_LIB([$CURSES_LIB_NAME], use_default_colors, AC_DEFINE(HAVE_USE_DEFAULT_COLORS, 1, [Define this if your curses library has the use_default_colors command.]))
|
AC_CHECK_LIB([$CURSES_LIB_NAME], use_default_colors, AC_DEFINE(HAVE_USE_DEFAULT_COLORS, 1, [Define this if your curses library has the use_default_colors command.]))
|
||||||
|
@ -353,6 +357,13 @@ then
|
||||||
LDFLAGS="$LDFLAGS $GLIB_LIBS"
|
LDFLAGS="$LDFLAGS $GLIB_LIBS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "x$CURSES_LIB_WIDE" == "xyes"
|
||||||
|
then
|
||||||
|
AC_DEFINE(NANO_WIDE, 1, [Define this if your system has wide character support.])
|
||||||
|
else
|
||||||
|
AC_MSG_WARN([No wide character support found. nano will not be able to support UTF-8.])
|
||||||
|
fi
|
||||||
|
|
||||||
AC_CONFIG_FILES([
|
AC_CONFIG_FILES([
|
||||||
Makefile
|
Makefile
|
||||||
doc/Makefile
|
doc/Makefile
|
||||||
|
|
24
src/nano.c
24
src/nano.c
|
@ -3567,26 +3567,22 @@ void do_output(int *kbinput, size_t kbinput_len)
|
||||||
/* Do we have to call edit_refresh(), or can we get away with
|
/* Do we have to call edit_refresh(), or can we get away with
|
||||||
* update_line()? */
|
* update_line()? */
|
||||||
|
|
||||||
char key[
|
|
||||||
#ifdef NANO_WIDE
|
#ifdef NANO_WIDE
|
||||||
MB_LEN_MAX
|
char *key =
|
||||||
|
charalloc(MB_CUR_MAX)
|
||||||
#else
|
#else
|
||||||
1
|
charalloc(1)
|
||||||
#endif
|
#endif
|
||||||
]; /* The current multibyte character we have. */
|
;
|
||||||
int key_len; /* The length of the current multibyte
|
|
||||||
* character. */
|
|
||||||
|
|
||||||
assert(current != NULL && current->data != NULL);
|
assert(current != NULL && current->data != NULL);
|
||||||
|
|
||||||
/* Turn off constant cursor position display. */
|
/* Turn off constant cursor position display. */
|
||||||
UNSET(CONSTUPDATE);
|
UNSET(CONSTUPDATE);
|
||||||
|
|
||||||
#ifdef NANO_WIDE
|
|
||||||
wctomb(NULL, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (i = 0; i < kbinput_len; i++) {
|
for (i = 0; i < kbinput_len; i++) {
|
||||||
|
int key_len;
|
||||||
|
|
||||||
/* Null to newline, if needed. */
|
/* Null to newline, if needed. */
|
||||||
if (kbinput[i] == '\0')
|
if (kbinput[i] == '\0')
|
||||||
kbinput[i] = '\n';
|
kbinput[i] = '\n';
|
||||||
|
@ -3628,7 +3624,7 @@ void do_output(int *kbinput, size_t kbinput_len)
|
||||||
charcpy(¤t->data[current_x], key, key_len);
|
charcpy(¤t->data[current_x], key, key_len);
|
||||||
current_len += key_len;
|
current_len += key_len;
|
||||||
/* FIXME: Should totsize be the number of single-byte characters
|
/* FIXME: Should totsize be the number of single-byte characters
|
||||||
* or the number of multibyte characters? Assume for former for
|
* or the number of multibyte characters? Assume the former for
|
||||||
* now. */
|
* now. */
|
||||||
totsize += key_len;
|
totsize += key_len;
|
||||||
set_modified();
|
set_modified();
|
||||||
|
@ -3669,15 +3665,13 @@ void do_output(int *kbinput, size_t kbinput_len)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NANO_WIDE
|
|
||||||
wctomb(NULL, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Turn constant cursor position display back on if it was on
|
/* Turn constant cursor position display back on if it was on
|
||||||
* before. */
|
* before. */
|
||||||
if (old_constupdate)
|
if (old_constupdate)
|
||||||
SET(CONSTUPDATE);
|
SET(CONSTUPDATE);
|
||||||
|
|
||||||
|
free(key);
|
||||||
|
|
||||||
if (do_refresh)
|
if (do_refresh)
|
||||||
edit_refresh();
|
edit_refresh();
|
||||||
else
|
else
|
||||||
|
|
|
@ -135,10 +135,6 @@
|
||||||
|
|
||||||
#define VERMSG "GNU nano " VERSION
|
#define VERMSG "GNU nano " VERSION
|
||||||
|
|
||||||
/* FIXME: We should be checking for this instead of unconditionally
|
|
||||||
* using it. */
|
|
||||||
#define NANO_WIDE 1
|
|
||||||
|
|
||||||
/* If we aren't using ncurses, turn the mouse support off, as it's
|
/* If we aren't using ncurses, turn the mouse support off, as it's
|
||||||
* ncurses-specific. */
|
* ncurses-specific. */
|
||||||
#ifndef NCURSES_MOUSE_VERSION
|
#ifndef NCURSES_MOUSE_VERSION
|
||||||
|
|
116
src/winio.c
116
src/winio.c
|
@ -122,7 +122,7 @@ void reset_kbinput(void)
|
||||||
* default keystroke buffer is empty. */
|
* default keystroke buffer is empty. */
|
||||||
void get_buffer(WINDOW *win)
|
void get_buffer(WINDOW *win)
|
||||||
{
|
{
|
||||||
int input;
|
int input, input_key_code;
|
||||||
|
|
||||||
/* If the keystroke buffer isn't empty, get out. */
|
/* If the keystroke buffer isn't empty, get out. */
|
||||||
if (key_buffer != NULL)
|
if (key_buffer != NULL)
|
||||||
|
@ -134,19 +134,36 @@ void get_buffer(WINDOW *win)
|
||||||
#ifndef NANO_SMALL
|
#ifndef NANO_SMALL
|
||||||
allow_pending_sigwinch(TRUE);
|
allow_pending_sigwinch(TRUE);
|
||||||
#endif
|
#endif
|
||||||
input = wgetch(win);
|
|
||||||
|
#ifdef NANO_WIDE
|
||||||
|
if (!ISSET(NO_UTF8)) {
|
||||||
|
wint_t tmp;
|
||||||
|
|
||||||
|
input_key_code = wget_wch(win, &tmp);
|
||||||
|
input = (int)tmp;
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
input = wgetch(win);
|
||||||
|
input_key_code = !is_byte_char(input);
|
||||||
|
#ifdef NANO_WIDE
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef NANO_SMALL
|
#ifndef NANO_SMALL
|
||||||
allow_pending_sigwinch(FALSE);
|
allow_pending_sigwinch(FALSE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Increment the length of the keystroke buffer, save the value of
|
/* Increment the length of the keystroke buffer, save the value of
|
||||||
* the keystroke in key, and set key_code to TRUE if the keystroke
|
* the keystroke in key, and set key_code to TRUE if the keystroke
|
||||||
* is an extended keypad value and hence shouldn't be treated as a
|
* is an extended keypad value or FALSE if it isn't. */
|
||||||
* multibyte character. */
|
|
||||||
key_buffer_len++;
|
key_buffer_len++;
|
||||||
key_buffer = (buffer *)nmalloc(sizeof(buffer));
|
key_buffer = (buffer *)nmalloc(sizeof(buffer));
|
||||||
key_buffer[0].key = input;
|
key_buffer[0].key = input;
|
||||||
key_buffer[0].key_code = !is_byte_char(input);
|
key_buffer[0].key_code =
|
||||||
|
#ifdef NANO_WIDE
|
||||||
|
!ISSET(NO_UTF8) ? (input_key_code == KEY_CODE_YES) :
|
||||||
|
#endif
|
||||||
|
input_key_code;
|
||||||
|
|
||||||
/* Read in the remaining characters using non-blocking input. */
|
/* Read in the remaining characters using non-blocking input. */
|
||||||
nodelay(win, TRUE);
|
nodelay(win, TRUE);
|
||||||
|
@ -155,73 +172,49 @@ void get_buffer(WINDOW *win)
|
||||||
#ifndef NANO_SMALL
|
#ifndef NANO_SMALL
|
||||||
allow_pending_sigwinch(TRUE);
|
allow_pending_sigwinch(TRUE);
|
||||||
#endif
|
#endif
|
||||||
input = wgetch(win);
|
|
||||||
#ifndef NANO_SMALL
|
|
||||||
allow_pending_sigwinch(FALSE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#ifdef NANO_WIDE
|
||||||
|
if (!ISSET(NO_UTF8)) {
|
||||||
|
wint_t tmp;
|
||||||
|
|
||||||
|
input_key_code = wget_wch(win, &tmp);
|
||||||
|
input = (int)tmp;
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
input = wgetch(win);
|
||||||
|
input_key_code = !is_byte_char(input);
|
||||||
|
#ifdef NANO_WIDE
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/* If there aren't any more characters, stop reading. */
|
/* If there aren't any more characters, stop reading. */
|
||||||
if (input == ERR)
|
if (
|
||||||
|
#ifdef NANO_WIDE
|
||||||
|
(!ISSET(NO_UTF8) && input_key_code == ERR) ||
|
||||||
|
#endif
|
||||||
|
input == ERR)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Otherwise, increment the length of the keystroke buffer, save
|
/* Otherwise, increment the length of the keystroke buffer, save
|
||||||
* the value of the keystroke in key, and set key_code to TRUE
|
* the value of the keystroke in key, and set key_code to TRUE
|
||||||
* if the keystroke is an extended keypad value and hence
|
* if the keystroke is an extended keypad value or FALSE if it
|
||||||
* shouldn't be treated as a multibyte character. */
|
* isn't. */
|
||||||
key_buffer_len++;
|
key_buffer_len++;
|
||||||
key_buffer = (buffer *)nrealloc(key_buffer, key_buffer_len *
|
key_buffer = (buffer *)nrealloc(key_buffer, key_buffer_len *
|
||||||
sizeof(buffer));
|
sizeof(buffer));
|
||||||
key_buffer[key_buffer_len - 1].key = input;
|
key_buffer[key_buffer_len - 1].key = input;
|
||||||
key_buffer[key_buffer_len - 1].key_code = !is_byte_char(input);
|
key_buffer[key_buffer_len - 1].key_code =
|
||||||
|
#ifdef NANO_WIDE
|
||||||
|
!ISSET(NO_UTF8) ? (input_key_code == KEY_CODE_YES) :
|
||||||
|
#endif
|
||||||
|
input_key_code;
|
||||||
|
|
||||||
|
#ifndef NANO_SMALL
|
||||||
|
allow_pending_sigwinch(FALSE);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Switch back to non-blocking input. */
|
/* Switch back to non-blocking input. */
|
||||||
nodelay(win, FALSE);
|
nodelay(win, FALSE);
|
||||||
|
|
||||||
#ifdef NANO_WIDE
|
|
||||||
if (!ISSET(NO_UTF8)) {
|
|
||||||
size_t i;
|
|
||||||
buffer *clean_key_buffer = NULL;
|
|
||||||
size_t clean_key_buffer_len = 0;
|
|
||||||
|
|
||||||
mbtowc(NULL, NULL, 0);
|
|
||||||
|
|
||||||
/* Change all complete and valid multibyte keystrokes to
|
|
||||||
* their wide character values, discarding the others. */
|
|
||||||
for (i = 0; i < key_buffer_len; i++) {
|
|
||||||
wchar_t wide_key;
|
|
||||||
int wide_key_len;
|
|
||||||
|
|
||||||
if (key_buffer[i].key_code) {
|
|
||||||
mbtowc(NULL, NULL, 0);
|
|
||||||
|
|
||||||
wide_key_len = 1;
|
|
||||||
wide_key = key_buffer[i].key;
|
|
||||||
} else
|
|
||||||
wide_key_len = mbtowc(&wide_key,
|
|
||||||
(const char *)&key_buffer[i].key, 1);
|
|
||||||
|
|
||||||
if (wide_key_len != -1) {
|
|
||||||
clean_key_buffer_len++;
|
|
||||||
clean_key_buffer = (buffer *)nrealloc(clean_key_buffer,
|
|
||||||
clean_key_buffer_len * sizeof(buffer));
|
|
||||||
|
|
||||||
clean_key_buffer[clean_key_buffer_len - 1].key =
|
|
||||||
(int)wide_key;
|
|
||||||
clean_key_buffer[clean_key_buffer_len - 1].key_code =
|
|
||||||
key_buffer[i].key_code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mbtowc(NULL, NULL, 0);
|
|
||||||
|
|
||||||
/* Replace the default keystroke buffer with the non-(-1)
|
|
||||||
* keystroke buffer. */
|
|
||||||
key_buffer_len = clean_key_buffer_len;
|
|
||||||
free(key_buffer);
|
|
||||||
key_buffer = clean_key_buffer;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the length of the default keystroke buffer. */
|
/* Return the length of the default keystroke buffer. */
|
||||||
|
@ -258,12 +251,10 @@ void unget_input(buffer *input, size_t input_len)
|
||||||
#ifdef NANO_WIDE
|
#ifdef NANO_WIDE
|
||||||
if (!ISSET(NO_UTF8)) {
|
if (!ISSET(NO_UTF8)) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
char *key = charalloc(MB_CUR_MAX);
|
||||||
wctomb(NULL, 0);
|
|
||||||
|
|
||||||
/* Keep all valid wide keystrokes, discarding the others. */
|
/* Keep all valid wide keystrokes, discarding the others. */
|
||||||
for (i = 0; i < input_len; i++) {
|
for (i = 0; i < input_len; i++) {
|
||||||
char key[MB_LEN_MAX];
|
|
||||||
int key_len = input[i].key_code ? 1 :
|
int key_len = input[i].key_code ? 1 :
|
||||||
wctomb(key, (wchar_t)input[i].key);
|
wctomb(key, (wchar_t)input[i].key);
|
||||||
|
|
||||||
|
@ -278,8 +269,7 @@ void unget_input(buffer *input, size_t input_len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wctomb(NULL, 0);
|
free(key);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
#endif
|
#endif
|
||||||
clean_input = input;
|
clean_input = input;
|
||||||
|
|
Loading…
Reference in New Issue