From 4d83a6cd94b4ab63489a7fab6edad5ec39bfee06 Mon Sep 17 00:00:00 2001 From: Alexander Zhylin Date: Mon, 9 Mar 2026 18:22:18 +0200 Subject: [PATCH] utf-8: initial support --- TODO.md | 1 + src/utils/utf8.c | 41 +++++++++++++++++++++++++++++----- src/utils/utf8.h | 6 ++++- src/widget/file_list.c | 4 ++-- src/widget/fs_file_list.c | 17 +++++--------- src/widget_core/CMakeLists.txt | 5 +++++ src/widget_core/widget_core.c | 10 +++++---- 7 files changed, 60 insertions(+), 24 deletions(-) diff --git a/TODO.md b/TODO.md index e664283..7d9fceb 100644 --- a/TODO.md +++ b/TODO.md @@ -6,6 +6,7 @@ - [x] Create dynamic map of elements IDs and their pointers - [x] Adapt modals to new value-forwarding method - [ ] More intuitive navigation between nested groups (by pressing left and right buttons) +- [ ] UTF-8: correct sizing in modals ## Features: - [x] Search files diff --git a/src/utils/utf8.c b/src/utils/utf8.c index 03ed128..014e1c9 100644 --- a/src/utils/utf8.c +++ b/src/utils/utf8.c @@ -1,9 +1,40 @@ +#include #include +#include +#include +#include +#include size_t count_utf8_code_points(const char *s) { - size_t count = 0; - while (*s) { - count += (*s++ & 0xC0) != 0x80; - } - return count; + size_t count = 0; + while (*s) { + count += (*s++ & 0xC0) != 0x80; + } + return count; +} + +int64_t convert_utf8_to_wide(const char *utf8_str, wchar_t **restrict wide_str, + size_t *restrict len) { + // Step 1: Convert UTF-8 (MBCS) to wchar_t (wide) + size_t wide_len = + count_utf8_code_points(utf8_str); // Get required length (-1 on error) + if (wide_len == (size_t)-1) { + *len = 0; + perror("mbstowcs failed"); + return 1; + } + *wide_str = + malloc((wide_len + 1) * sizeof(wchar_t)); // +1 for null terminator + mbstowcs(*wide_str, utf8_str, wide_len + 1); // Perform conversion + *len = wide_len; + return 0; +} + +int64_t curs_printw(WINDOW *win, int64_t y, int64_t x, char *const utf8_str) { + wchar_t *wname = NULL; + size_t nsize = 0; + convert_utf8_to_wide(utf8_str, &wname, &nsize); + mvwaddwstr(win, y, x, wname); + free(wname); + return nsize; } diff --git a/src/utils/utf8.h b/src/utils/utf8.h index 6412f24..52cd0f2 100644 --- a/src/utils/utf8.h +++ b/src/utils/utf8.h @@ -1,7 +1,11 @@ #ifndef UTF8_H #define UTF8_H +#include #include +#include size_t count_utf8_code_points(const char *s); - +int64_t convert_utf8_to_wide(const char *utf8_str, wchar_t **restrict wide_str, + size_t *restrict len); +int64_t curs_printw(WINDOW *win, int64_t y, int64_t x, char *const utf8_str); #endif \ No newline at end of file diff --git a/src/widget/file_list.c b/src/widget/file_list.c index aa3d87a..4892794 100644 --- a/src/widget/file_list.c +++ b/src/widget/file_list.c @@ -169,8 +169,8 @@ void draw_file_list(ui_file_list_t *fui) { active_el = el; } p_x = 1; - mvwprintw(parent_win, p_y, p_x, "%s%n", el->name, &p_x); - mvwprintw(parent_win, p_y, p_x + 1, "%*s", sz_x - p_x, ""); + p_x += curs_printw(parent_win, p_y, p_x, el->name); + mvwprintw(parent_win, p_y, p_x, "%*s", sz_x - p_x, ""); if (cur_el_idx == fui->current_idx) { wattroff(parent_win, A_BOLD | A_REVERSE); } diff --git a/src/widget/fs_file_list.c b/src/widget/fs_file_list.c index 7d502c5..bbe0d99 100644 --- a/src/widget/fs_file_list.c +++ b/src/widget/fs_file_list.c @@ -11,6 +11,7 @@ #include #include #include +#include void reset_file_list(ui_fs_file_list_t *fl_ui); @@ -101,8 +102,7 @@ void select_item(ui_fs_file_list_t *fui, int32_t *resp_data) { } else { dp_current = strlen(fui->d_path); selection = fui->current->name + 1; - fui->d_path = - realloc(fui->d_path, dp_current + strlen(selection) + 2); + fui->d_path = realloc(fui->d_path, dp_current + strlen(selection) + 2); sprintf(fui->d_path, "%s/%s", fui->d_path, selection); fl_clear(&(fui->start), &(fui->current)); fui->start = get_files_from_fs(fui->d_path); @@ -134,7 +134,7 @@ void fs_file_list_cb(callback_args_t *args) { } break; case '\n': - select_item(fui, (int32_t *) args->resp_data.val.val.num); + select_item(fui, (int32_t *)args->resp_data.val.val.num); break; } } @@ -172,7 +172,6 @@ void draw_fs_file_list(ui_fs_file_list_t *fl_ui) { } wattrset(win, A_REVERSE); /* Match with modal background */ - do { if (p_y < 1) { p_y++; @@ -182,14 +181,8 @@ void draw_fs_file_list(ui_fs_file_list_t *fl_ui) { wattrset(win, COLOR_PAIR(3) | A_BOLD | A_REVERSE); } p_x = 1; - /* TODO: */ - wchar_t wname[512]; - mbstowcs(wname, el->name, 512); - // wchar_t text[] = L"ВUTF-8 работает! → ★ ℝ 日本語\n"; - mvwaddwstr(win, p_y, p_x++, L"Ё"); - mvwaddwstr(win, p_y, p_x++, L"Ж"); - // mvwprintw(win, p_y, p_x, "%s%n", el->name, &p_x); - mvwprintw(win, p_y, p_x + 1, "%*s", sz_x_f - p_x, ""); + p_x += curs_printw(win, p_y, p_x, el->name); + mvwprintw(win, p_y, p_x, "%*s", sz_x_f - p_x, ""); if (el == fl_ui->current) { wattroff(win, COLOR_PAIR(3) | A_BOLD); } diff --git a/src/widget_core/CMakeLists.txt b/src/widget_core/CMakeLists.txt index dc7ef61..330d1f4 100644 --- a/src/widget_core/CMakeLists.txt +++ b/src/widget_core/CMakeLists.txt @@ -2,6 +2,11 @@ add_library(widget_core STATIC) file(GLOB M_SOURCES "*.c") +target_link_libraries(widget_core + PRIVATE + utils +) + target_sources(widget_core PRIVATE ${M_SOURCES} diff --git a/src/widget_core/widget_core.c b/src/widget_core/widget_core.c index f287f18..63f9ed5 100644 --- a/src/widget_core/widget_core.c +++ b/src/widget_core/widget_core.c @@ -4,6 +4,7 @@ #include #include #include +#include extern uint32_t m_id; int32_t rsize_to_value(int32_t size, enum rsize rsize); @@ -14,7 +15,8 @@ void init_widget(widget_t *w, widget_t *w_parent, WINDOW **win, char *title) { w->sz.y = 0; w->ps.x = 0; w->ps.y = 0; - if (w_parent != NULL && w_parent->w_parent != NULL) { /* not root element of the window */ + if (w_parent != NULL && + w_parent->w_parent != NULL) { /* not root element of the window */ w->m.x = w_parent->m.x; w->m.y = w_parent->m.y; } else { @@ -56,11 +58,11 @@ int32_t get_max_line_len(const char *text, uint32_t *line_count) { strncpy(l_buf, text + i - c_line_len, c_line_len); \ l_buf[c_line_len] = '\0'; \ if ((attrs & PMT_ALIGN_CENTER) == PMT_ALIGN_CENTER) { \ - mvwprintw(win, line_v_pos, (win_width - c_line_len) / 2, "%s", l_buf); \ + curs_printw(win, line_v_pos, (win_width - c_line_len) / 2, l_buf); \ } else if (attrs & PMT_POS_CENTER) { \ - mvwprintw(win, line_v_pos, (win_width - m_line_len) / 2, "%s", l_buf); \ + curs_printw(win, line_v_pos, (win_width - m_line_len) / 2, l_buf); \ } else { \ - mvwprintw(win, line_v_pos, x, "%s", l_buf); \ + curs_printw(win, line_v_pos, x, l_buf); \ } uint32_t print_multiline_text(WINDOW *win, const char *_text,