[A] Add function ft_set_u8strwid_func
to set custom function to compute width of utf8 strings
This commit is contained in:
parent
4e70d08b22
commit
da5cbc0404
@ -3,6 +3,7 @@
|
||||
### API
|
||||
|
||||
- Changes in C++ API (introduced classes `char_table` and `utf8-table` instead of `table`).
|
||||
- Add function `ft_set_u8strwid_func` to set custom function to compute width of utf8 strings.
|
||||
|
||||
### Internal
|
||||
|
||||
|
@ -5,6 +5,24 @@
|
||||
|
||||
#include "fort.h"
|
||||
|
||||
#if defined(FT_HAVE_UTF8)
|
||||
/* Custom function to compute visible width of utf8 strings */
|
||||
int u8strwid(const void *beg, const void *end, size_t *width)
|
||||
{
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
const char *emojis[] = {"😃", "😍"};
|
||||
const size_t sz = sizeof(emojis) / sizeof(emojis[0]);
|
||||
const size_t raw_len = (const char *)end - (const char *)beg;
|
||||
|
||||
for (size_t i = 0; i < sz; ++i) {
|
||||
if (memcmp(beg, emojis[i], MIN(strlen(emojis[i]), raw_len)) == 0) {
|
||||
*width = 2; /* On my terminal emojis have width of 2 chars */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@ -28,6 +46,23 @@ int main(void)
|
||||
printf("%s\n", table_str);
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
|
||||
/* Example of providing custom function to compute utf8 string width */
|
||||
{
|
||||
ft_set_u8strwid_func(&u8strwid);
|
||||
|
||||
ft_table_t *table = ft_create_table();
|
||||
ft_set_border_style(table, FT_NICE_STYLE);
|
||||
|
||||
ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);
|
||||
ft_u8write_ln(table, "SMILING", "Native");
|
||||
ft_u8write_ln(table, "SMILING FACE WITH OPEN MOUTH", "😃");
|
||||
ft_u8write_ln(table, "SMILING FACE WITH HEART-SHAPED EYES", "😍");
|
||||
|
||||
const char *table_str = (const char *)ft_to_u8string(table);
|
||||
printf("%s\n", table_str);
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Example of wchar table */
|
||||
|
@ -1,8 +1,27 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "fort.hpp"
|
||||
|
||||
#if defined(FT_HAVE_UTF8)
|
||||
/* Custom function to compute visible width of utf8 strings */
|
||||
int u8strwid(const void *beg, const void *end, size_t *width)
|
||||
{
|
||||
const char *emojis[] = {"😃", "😍"};
|
||||
const size_t sz = sizeof(emojis) / sizeof(emojis[0]);
|
||||
const size_t raw_len = (const char *)end - (const char *)beg;
|
||||
|
||||
for (size_t i = 0; i < sz; ++i) {
|
||||
if (memcmp(beg, emojis[i], std::min(strlen(emojis[i]), raw_len)) == 0) {
|
||||
*width = 2; /* On my terminal emojis have width of 2 chars */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@ -24,6 +43,22 @@ int main(void)
|
||||
|
||||
std::cout << table.to_string() << std::endl;
|
||||
}
|
||||
|
||||
|
||||
/* Example of providing custom function to compute utf8 string width */
|
||||
{
|
||||
ft_set_u8strwid_func(&u8strwid);
|
||||
|
||||
fort::utf8_table table;
|
||||
table.set_border_style(FT_NICE_STYLE);
|
||||
|
||||
table << fort::header
|
||||
<< "Description" << "Native" << fort::endr
|
||||
<< "SMILING FACE WITH OPEN MOUTH" << "😃" << fort::endr
|
||||
<< "SMILING FACE WITH HEART-SHAPED EYES" << "😍" << fort::endr;
|
||||
|
||||
std::cout << table.to_string() << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
27
lib/fort.c
27
lib/fort.c
@ -1821,6 +1821,12 @@ FT_INTERNAL
|
||||
int buffer_printf(f_string_buffer_t *buffer, size_t buffer_row, f_conv_context_t *cntx, size_t cod_width,
|
||||
const char *content_style_tag, const char *reset_content_style_tag);
|
||||
|
||||
#ifdef FT_HAVE_UTF8
|
||||
FT_INTERNAL
|
||||
void buffer_set_u8strwid_func(int (*u8strwid)(const void *beg, const void *end, size_t *width));
|
||||
#endif /* FT_HAVE_UTF8 */
|
||||
|
||||
|
||||
#endif /* STRING_BUFFER_H */
|
||||
|
||||
/********************************************************
|
||||
@ -3528,6 +3534,12 @@ const void *ft_to_u8string(const ft_table_t *table)
|
||||
{
|
||||
return (const void *)ft_to_string_impl(table, UTF8_BUF);
|
||||
}
|
||||
|
||||
void ft_set_u8strwid_func(int (*u8strwid)(const void *beg, const void *end, size_t *width))
|
||||
{
|
||||
buffer_set_u8strwid_func(u8strwid);
|
||||
}
|
||||
|
||||
#endif /* FT_HAVE_UTF8 */
|
||||
|
||||
/********************************************************
|
||||
@ -6300,9 +6312,24 @@ size_t string_buffer_raw_capacity(const f_string_buffer_t *buffer)
|
||||
}
|
||||
|
||||
#ifdef FT_HAVE_UTF8
|
||||
/* User provided function to compute utf8 string visible width */
|
||||
static int (*_custom_u8strwid)(const void *beg, const void *end, size_t *width) = NULL;
|
||||
|
||||
FT_INTERNAL
|
||||
void buffer_set_u8strwid_func(int (*u8strwid)(const void *beg, const void *end, size_t *width))
|
||||
{
|
||||
_custom_u8strwid = u8strwid;
|
||||
}
|
||||
|
||||
static
|
||||
size_t utf8_width(const void *beg, const void *end)
|
||||
{
|
||||
if (_custom_u8strwid) {
|
||||
size_t width = 0;
|
||||
if (!_custom_u8strwid(beg, end, &width))
|
||||
return width;
|
||||
}
|
||||
|
||||
size_t sz = (size_t)((const char *)end - (const char *)beg);
|
||||
char *tmp = (char *)F_MALLOC(sizeof(char) * (sz + 1));
|
||||
// @todo: add check to tmp
|
||||
|
21
lib/fort.h
21
lib/fort.h
@ -915,6 +915,27 @@ int ft_u8printf_ln(ft_table_t *table, const char *fmt, ...) FT_PRINTF_ATTRIBUTE_
|
||||
|
||||
const void *ft_to_u8string(const ft_table_t *table);
|
||||
|
||||
/**
|
||||
* Set custom function to compute visible width of utf8 string.
|
||||
*
|
||||
* libfort internally has a very simple logic to compute visible width of utf8
|
||||
* strings. It considers that each codepoint will occupy one position on the
|
||||
* terminal in case of monowidth font (some east asians wide and fullwidth
|
||||
* characters (see http://www.unicode.org/reports/tr11/tr11-33.html) will occupy
|
||||
* 2 positions). This logic is very simple and covers wide range of cases. But
|
||||
* obviously there a lot of cases when it is not sufficient. In such cases user
|
||||
* should use some external libraries and provide an appropriate function to
|
||||
* libfort.
|
||||
*
|
||||
* @param u8strwid
|
||||
* User provided function to evaluate width of utf8 string ( beg - start of
|
||||
* utf8 string, end - end of utf8 string (not included), width - pointer to
|
||||
* the result). If function succeed it should return 0, otherwise some non-
|
||||
* zero value. If function returns nonzero value libfort fallbacks to default
|
||||
* internal algorithm.
|
||||
*/
|
||||
void ft_set_u8strwid_func(int (*u8strwid)(const void *beg, const void *end, size_t *width));
|
||||
|
||||
#endif /* FT_HAVE_UTF8 */
|
||||
|
||||
|
||||
|
21
src/fort.h
21
src/fort.h
@ -915,6 +915,27 @@ int ft_u8printf_ln(ft_table_t *table, const char *fmt, ...) FT_PRINTF_ATTRIBUTE_
|
||||
|
||||
const void *ft_to_u8string(const ft_table_t *table);
|
||||
|
||||
/**
|
||||
* Set custom function to compute visible width of utf8 string.
|
||||
*
|
||||
* libfort internally has a very simple logic to compute visible width of utf8
|
||||
* strings. It considers that each codepoint will occupy one position on the
|
||||
* terminal in case of monowidth font (some east asians wide and fullwidth
|
||||
* characters (see http://www.unicode.org/reports/tr11/tr11-33.html) will occupy
|
||||
* 2 positions). This logic is very simple and covers wide range of cases. But
|
||||
* obviously there a lot of cases when it is not sufficient. In such cases user
|
||||
* should use some external libraries and provide an appropriate function to
|
||||
* libfort.
|
||||
*
|
||||
* @param u8strwid
|
||||
* User provided function to evaluate width of utf8 string ( beg - start of
|
||||
* utf8 string, end - end of utf8 string (not included), width - pointer to
|
||||
* the result). If function succeed it should return 0, otherwise some non-
|
||||
* zero value. If function returns nonzero value libfort fallbacks to default
|
||||
* internal algorithm.
|
||||
*/
|
||||
void ft_set_u8strwid_func(int (*u8strwid)(const void *beg, const void *end, size_t *width));
|
||||
|
||||
#endif /* FT_HAVE_UTF8 */
|
||||
|
||||
|
||||
|
@ -983,4 +983,10 @@ const void *ft_to_u8string(const ft_table_t *table)
|
||||
{
|
||||
return (const void *)ft_to_string_impl(table, UTF8_BUF);
|
||||
}
|
||||
|
||||
void ft_set_u8strwid_func(int (*u8strwid)(const void *beg, const void *end, size_t *width))
|
||||
{
|
||||
buffer_set_u8strwid_func(u8strwid);
|
||||
}
|
||||
|
||||
#endif /* FT_HAVE_UTF8 */
|
||||
|
@ -444,9 +444,24 @@ size_t string_buffer_raw_capacity(const f_string_buffer_t *buffer)
|
||||
}
|
||||
|
||||
#ifdef FT_HAVE_UTF8
|
||||
/* User provided function to compute utf8 string visible width */
|
||||
static int (*_custom_u8strwid)(const void *beg, const void *end, size_t *width) = NULL;
|
||||
|
||||
FT_INTERNAL
|
||||
void buffer_set_u8strwid_func(int (*u8strwid)(const void *beg, const void *end, size_t *width))
|
||||
{
|
||||
_custom_u8strwid = u8strwid;
|
||||
}
|
||||
|
||||
static
|
||||
size_t utf8_width(const void *beg, const void *end)
|
||||
{
|
||||
if (_custom_u8strwid) {
|
||||
size_t width = 0;
|
||||
if (!_custom_u8strwid(beg, end, &width))
|
||||
return width;
|
||||
}
|
||||
|
||||
size_t sz = (size_t)((const char *)end - (const char *)beg);
|
||||
char *tmp = (char *)F_MALLOC(sizeof(char) * (sz + 1));
|
||||
// @todo: add check to tmp
|
||||
|
@ -73,4 +73,10 @@ FT_INTERNAL
|
||||
int buffer_printf(f_string_buffer_t *buffer, size_t buffer_row, f_conv_context_t *cntx, size_t cod_width,
|
||||
const char *content_style_tag, const char *reset_content_style_tag);
|
||||
|
||||
#ifdef FT_HAVE_UTF8
|
||||
FT_INTERNAL
|
||||
void buffer_set_u8strwid_func(int (*u8strwid)(const void *beg, const void *end, size_t *width));
|
||||
#endif /* FT_HAVE_UTF8 */
|
||||
|
||||
|
||||
#endif /* STRING_BUFFER_H */
|
||||
|
@ -349,6 +349,20 @@ void test_str_n_substring(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(FT_HAVE_UTF8)
|
||||
/* Custom function to compute visible width of utf8 strings */
|
||||
int u8strwid(const void *beg, const void *end, size_t *width)
|
||||
{
|
||||
const char *custom_str = "custom_string";
|
||||
const size_t raw_len = (const char *)end - (const char *)beg;
|
||||
if (memcmp(beg, custom_str, MIN(strlen(custom_str), raw_len)) == 0) {
|
||||
*width = 25;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_buffer_text_visible_width(void)
|
||||
{
|
||||
f_string_buffer_t *buffer = create_string_buffer(200, CHAR_BUF);
|
||||
@ -467,6 +481,17 @@ void test_buffer_text_visible_width(void)
|
||||
assert_true(buffer_text_visible_width(buffer) == 30);
|
||||
|
||||
|
||||
/* Test custom width function for utf8 strings */
|
||||
ft_set_u8strwid_func(&u8strwid);
|
||||
buffer->str.u8str = (void *)"custom_string";
|
||||
assert_true(buffer_text_visible_width(buffer) == 25);
|
||||
buffer->str.u8str = (void *)"123456789012345678901234\ncustom_string";
|
||||
assert_true(buffer_text_visible_width(buffer) == 25);
|
||||
buffer->str.u8str = (void *)"12345678901234567890123456\ncustom_string";
|
||||
assert_true(buffer_text_visible_width(buffer) == 26);
|
||||
buffer->str.u8str = (void *)"common_string";
|
||||
assert_true(buffer_text_visible_width(buffer) == 13);
|
||||
ft_set_u8strwid_func(NULL);
|
||||
#endif
|
||||
|
||||
buffer->type = CHAR_BUF;
|
||||
|
Loading…
Reference in New Issue
Block a user