diff options
| author | Přemysl Janouch <p.janouch@gmail.com> | 2013-06-02 00:01:23 +0200 | 
|---|---|---|
| committer | Přemysl Janouch <p.janouch@gmail.com> | 2013-06-02 00:04:43 +0200 | 
| commit | 1cc91a4b179b13c19d3318e64896088fefde6c3c (patch) | |
| tree | 21dbf2d46a4a1e62df8b472773fdd2141f4d0553 /src | |
| parent | d3b966a93f176ce669f228b0d0dad0b9682c3e11 (diff) | |
| download | tdv-1cc91a4b179b13c19d3318e64896088fefde6c3c.tar.gz tdv-1cc91a4b179b13c19d3318e64896088fefde6c3c.tar.xz tdv-1cc91a4b179b13c19d3318e64896088fefde6c3c.zip | |
Fix double- and zero-wide characters
It's not perfect but seems to work well enough.
Diffstat (limited to 'src')
| -rw-r--r-- | src/sdtui.c | 87 | 
1 files changed, 71 insertions, 16 deletions
| diff --git a/src/sdtui.c b/src/sdtui.c index 502aec3..f875389 100644 --- a/src/sdtui.c +++ b/src/sdtui.c @@ -18,7 +18,8 @@   *   */ -#define _XOPEN_SOURCE_EXTENDED         /**< Yes, we want ncursesw. */ +#define _XOPEN_SOURCE  500             //!< wcwidth +#define _XOPEN_SOURCE_EXTENDED         //!< Yes, we want ncursesw.  #include <stdio.h>  #include <stdlib.h> @@ -98,6 +99,18 @@ struct curses_event  	MEVENT  mouse;  }; +static size_t +unichar_width (gunichar ch) +{ +	if (g_unichar_iszerowidth (ch)) +		return 0; +	return 1 + g_unichar_iswide (ch); +} + +#ifndef HAVE_WCWIDTH +#define wcwidth(x)  1 +#endif // ! HAVE_WCWIDTH +  static gboolean  is_character_in_locale (wchar_t c)  { @@ -353,31 +366,68 @@ app_add_utf8_string (Application *self, const gchar *str, int n)  	ssize_t wide_len = wcslen (wide_str);  	wchar_t padding = L' ', error = L'?', ellipsis = L'…'; +	if (!n) +		return 0; + +	// Compute how many wide characters fit in the limit +	gint cols, i; +	for (cols = i = 0; i < wide_len; i++) +	{ +		if (!is_character_in_locale (wide_str[i])) +			wide_str[i] = error; + +		gint width = wcwidth (wide_str[i]); +		if (n >= 0 && cols + width > n) +			break; +		cols += width; +	} +  	if (n < 0) -		n = wide_len; +		n = cols; -	if (wide_len > n) +	// Append ellipsis if the whole string didn't fit +	gint len = i; +	if (len != wide_len)  	{ -		if (is_character_in_locale (ellipsis) && n > 0) -			wide_str[n - 1] = ellipsis; -		else if (n >= 3) +		if (is_character_in_locale (ellipsis))  		{ -			wide_str[n - 1] = L'.'; -			wide_str[n - 2] = L'.'; -			wide_str[n - 3] = L'.'; +			if (cols + wcwidth (ellipsis) > n) +				cols -= wcwidth (wide_str[len - 1]); +			else +				len++; + +			wide_str[len - 1] = ellipsis; +			cols += wcwidth (ellipsis); +		} +		else if (n >= 3 && len >= 3) +		{ +			// With zero-width characters this overflows +			// It's just a fallback anyway +			cols -= wcwidth (wide_str[len - 1]); +			cols -= wcwidth (wide_str[len - 2]); +			cols -= wcwidth (wide_str[len - 3]); +			cols += 3; + +			wide_str[len - 1] = L'.'; +			wide_str[len - 2] = L'.'; +			wide_str[len - 3] = L'.';  		}  	} -	gint i;  	cchar_t cch; -	for (i = 0; i < n; i++) +	for (i = 0; i < len; i++)  	{ -		if (setcchar (&cch, (i < wide_len ? &wide_str[i] : &padding), -			A_NORMAL, 0, NULL) == ERR) -			setcchar (&cch, &error, A_NORMAL, 0, NULL); -		add_wch (&cch); +		if (setcchar (&cch, &wide_str[i], A_NORMAL, 0, NULL) == OK) +			add_wch (&cch); +		else +			// This shouldn't happen +			cols -= wcwidth (wide_str[i]);  	} +	setcchar (&cch, &padding, A_NORMAL, 0, NULL); +	while (cols++ < n) +		add_wch (&cch); +  	g_free (wide_str);  	return n;  } @@ -399,7 +449,12 @@ app_redraw_top (Application *self)  	app_add_utf8_string (self, input_utf8, COLS - indent);  	g_free (input_utf8); -	move (0, indent + self->input_pos); +	guint offset, i; +	for (offset = i = 0; i < self->input_pos; i++) +		// This may be inconsistent with the output of app_add_utf8_string() +		offset += unichar_width (g_array_index (self->input, gunichar, i)); + +	move (0, indent + offset);  	refresh ();  } | 
