Message ID | 20221010182603.55042-1-xdavidwuph@gmail.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | [v2] client: handle wide chars for table rows | expand |
Hi Pinghao, On Tue, 2022-10-11 at 02:26 +0800, Pinghao Wu wrote: > Find out printing width of wide chars via wcwidth(). > --- > client/display.c | 18 ++++++++++++++---- > client/main.c | 3 +++ > 2 files changed, 17 insertions(+), 4 deletions(-) > > diff --git a/client/display.c b/client/display.c > index b729ad4c..42b5336e 100644 > --- a/client/display.c > +++ b/client/display.c > @@ -30,6 +30,7 @@ > #include <sys/stat.h> > #include <sys/ioctl.h> > #include <unistd.h> > +#include <wchar.h> > > #include <readline/history.h> > #include <readline/readline.h> > @@ -401,18 +402,27 @@ static char* next_line(char *s, unsigned int > *max, char **color_out) > unsigned int i; > int last_space = -1; > int last_color = -1; > + int s_len = strlen(s); > > /* Find the last space before 'max', as well as any color */ > - for (i = 0; i <= *max && s[i] != '\0'; i++) { > + for (i = 0; i <= *max && i != s_len; i++) { I know you didn't write the for-loop originally, but now since you're incrementing i by some value larger than 1 it makes more sense to use a while loop and break out if i > *max. In addition I think you could blow past the i != s_len check. I think this entire thing could be simplified now with you're changes by putting l_utf8_get_codepoint into a while loop and always calling wcwidth() for each character. Then we aren't distinguishing between ascii and utf-8, just always increment i/max by the needed values (also taking into account the space/color checks obviously). > if (s[i] == ' ') > last_space = i; > else if (s[i] == 0x1b) { > /* color escape won't count for column width > */ > *max += color_end(s + i); > last_color = i; > - /* Add width for non-codepoint UTF-8 bytes */ > - } else if (((uint8_t)s[i] >> 6) == 2) > - *max += 1; > + /* Non-ASCII */ > + } else if (s[i] & 0x80) { > + wchar_t w; > + int w_mblen = l_utf8_get_codepoint(&s[i], > s_len - i, &w); > + if (w_mblen > 0) { > + /* Compensate max bytes */ > + *max += w_mblen - wcwidth(w); > + /* Skip other bytes of this codepoint > */ > + i += w_mblen - 1; > + } > + } > } > > /* Reached the end of the string within the column bounds */ > diff --git a/client/main.c b/client/main.c > index df5c0a61..7e8dead4 100644 > --- a/client/main.c > +++ b/client/main.c > @@ -25,6 +25,7 @@ > #endif > > #include <errno.h> > +#include <locale.h> > #include <signal.h> > #include <ell/ell.h> > > @@ -50,6 +51,8 @@ int main(int argc, char *argv[]) > { > bool all_done; > > + setlocale(LC_CTYPE, ""); > + > if (!l_main_init()) > return EXIT_FAILURE; >
diff --git a/client/display.c b/client/display.c index b729ad4c..42b5336e 100644 --- a/client/display.c +++ b/client/display.c @@ -30,6 +30,7 @@ #include <sys/stat.h> #include <sys/ioctl.h> #include <unistd.h> +#include <wchar.h> #include <readline/history.h> #include <readline/readline.h> @@ -401,18 +402,27 @@ static char* next_line(char *s, unsigned int *max, char **color_out) unsigned int i; int last_space = -1; int last_color = -1; + int s_len = strlen(s); /* Find the last space before 'max', as well as any color */ - for (i = 0; i <= *max && s[i] != '\0'; i++) { + for (i = 0; i <= *max && i != s_len; i++) { if (s[i] == ' ') last_space = i; else if (s[i] == 0x1b) { /* color escape won't count for column width */ *max += color_end(s + i); last_color = i; - /* Add width for non-codepoint UTF-8 bytes */ - } else if (((uint8_t)s[i] >> 6) == 2) - *max += 1; + /* Non-ASCII */ + } else if (s[i] & 0x80) { + wchar_t w; + int w_mblen = l_utf8_get_codepoint(&s[i], s_len - i, &w); + if (w_mblen > 0) { + /* Compensate max bytes */ + *max += w_mblen - wcwidth(w); + /* Skip other bytes of this codepoint */ + i += w_mblen - 1; + } + } } /* Reached the end of the string within the column bounds */ diff --git a/client/main.c b/client/main.c index df5c0a61..7e8dead4 100644 --- a/client/main.c +++ b/client/main.c @@ -25,6 +25,7 @@ #endif #include <errno.h> +#include <locale.h> #include <signal.h> #include <ell/ell.h> @@ -50,6 +51,8 @@ int main(int argc, char *argv[]) { bool all_done; + setlocale(LC_CTYPE, ""); + if (!l_main_init()) return EXIT_FAILURE;