xaizek / vifm (License: GPLv2+) (since 2018-12-07)
Vifm is a file manager with curses interface, which provides Vi[m]-like environment for managing objects within file systems, extended with some useful ideas from mutt.
Commit 671b12cd4d74984f345bca925486c226668ce1b6

Fix truncating wide characters on drawing columns
The changes here:
* let the previous column finish at the first character of the current
one (`print_start` -> `cur_col_start`)
* make sure the tail from the previous column gets cleared
(`prev_col_end` -> `real_prev_end`) to avoid drawing a wide character
at position N first and then drawing something else at position N+1
which is considered taken by the terminal

Got broken on introducing column-specific highlighting in 0.14-beta by
commit f542f60b09222859673148fe4dc3b680b033f606:

Perform filling per column

That is given:

<column1|filler1><filler2|column2>

Don't draw filler1 and filler2 in a single call.

Thanks to Snake52996.

Fixes #1078 on GitHub.
Author: xaizek
Author date (UTC): 2025-04-29 16:43
Committer name: xaizek
Committer date (UTC): 2025-05-02 07:58
Parent(s): 5ea32dce950c5d015b2c20d298aed6ee2a7d4cbe
Signing key: 99DC5E4DB05F6BE2
Tree: e0ae5ae40f9bb70d74167de0da74d5712000617d
File Lines added Lines deleted
ChangeLog 3 0
THANKS 1 0
src/ui/column_view.c 3 3
tests/column_view/utf8.c 28 1
File ChangeLog changed (mode: 100644) (index 3e99de63a..fbeaacfea)
65 65
66 66 Fixed an unlikely memory leak on parsing of malformed 'viewcolumns'. Fixed an unlikely memory leak on parsing of malformed 'viewcolumns'.
67 67
68 Fixed truncating wide characters on drawing columns broken on introducing
69 column-specific highlighting in 0.14-beta. Thanks to Snake52996.
70
68 71 0.14-beta to 0.14 (2025-02-08) 0.14-beta to 0.14 (2025-02-08)
69 72
70 73 Improved documentation on zh/zl menu keys a bit. Improved documentation on zh/zl menu keys a bit.
File THANKS changed (mode: 100644) (index fad5eb4ae..f91f2b5bf)
... ... sirex (sirexas)
304 304 Sitaram Chamarty Sitaram Chamarty
305 305 smoothdad smoothdad
306 306 smpolymen smpolymen
307 Snake52996
307 308 spence91 spence91
308 309 Stas Malavin Stas Malavin
309 310 Stas Panteleev Stas Panteleev
File src/ui/column_view.c changed (mode: 100644) (index 2b52f0c1c..6e0bc9b06)
... ... columns_format_line(columns_t *cols, void *format_data, int max_line_width)
354 354 * character inside previous column. */ * character inside previous column. */
355 355 if(prev_col_end > print_start) if(prev_col_end > print_start)
356 356 { {
357 const int prev_col_max_width = (print_start > prev_col_start)
358 ? (print_start - prev_col_start)
357 const int prev_col_max_width = (cur_col_start > prev_col_start)
358 ? (cur_col_start - prev_col_start)
359 359 : 0; : 0;
360 360 const size_t break_point = utf8_strsnlen(prev_col_buf, const size_t break_point = utf8_strsnlen(prev_col_buf,
361 361 prev_col_max_width); prev_col_max_width);
362 362 prev_col_buf[break_point] = '\0'; prev_col_buf[break_point] = '\0';
363 363 int real_prev_end = prev_col_start + get_width_on_screen(prev_col_buf); int real_prev_end = prev_col_start + get_width_on_screen(prev_col_buf);
364 364 fill_gap_pos(format_data, real_prev_end, print_start, prev_col_id); fill_gap_pos(format_data, real_prev_end, print_start, prev_col_id);
365 print_start = prev_col_end;
365 print_start = real_prev_end;
366 366 } }
367 367 else else
368 368 { {
File tests/column_view/utf8.c changed (mode: 100644) (index d310e81a2..56a8bea83)
... ... static const size_t MAX_WIDTH = 20;
22 22 static char print_buffer[80 + 1]; static char print_buffer[80 + 1];
23 23
24 24 static const char *col1_str; static const char *col1_str;
25 static const char *col2_str;
25 26
26 27 SETUP_ONCE() SETUP_ONCE()
27 28 { {
 
... ... SETUP()
39 40 col2_next = &column2_func; col2_next = &column2_func;
40 41
41 42 col1_str = "师从螺丝刀йклмнопрстуфхцчшщьыъэюя"; col1_str = "师从螺丝刀йклмнопрстуфхцчшщьыъэюя";
43 col2_str = "яюэъыьщшчцхфутсрпонмлкйизжёедгв推";
42 44 } }
43 45
44 46 TEARDOWN() TEARDOWN()
 
... ... column1_func(void *data, size_t buf_len, char buf[], const format_info_t *info)
64 66 static void static void
65 67 column2_func(void *data, size_t buf_len, char buf[], const format_info_t *info) column2_func(void *data, size_t buf_len, char buf[], const format_info_t *info)
66 68 { {
67 snprintf(buf, buf_len + 1, "%s", "яюэъыьщшчцхфутсрпонмлкйизжёедгв推");
69 snprintf(buf, buf_len + 1, "%s", col2_str);
68 70 } }
69 71
70 72 static void static void
 
... ... TEST(none_cropping_allows_for_correct_gaps, IF(locale_works))
140 142 assert_string_equal(expected, print_buffer); assert_string_equal(expected, print_buffer);
141 143 } }
142 144
145 TEST(none_cropping_cuts_wide_strings_correctly, IF(locale_works))
146 {
147 static column_info_t column_infos[2] = {
148 { .column_id = COL1_ID, .full_width = 10UL, .text_width = 10UL,
149 .align = AT_LEFT, .sizing = ST_AUTO, .cropping = CT_NONE, },
150 { .column_id = COL2_ID, .full_width = 4UL, .text_width = 4UL,
151 .align = AT_RIGHT, .sizing = ST_AUTO, .cropping = CT_NONE, },
152 };
153
154 col1_str = "师从螺丝";
155 col2_str = "xyz";
156
157 perform_test(column_infos, 2, 9);
158 assert_string_equal("师从螺xyz", print_buffer);
159
160 perform_test(column_infos, 2, 10);
161 assert_string_equal("师从螺 xyz", print_buffer);
162
163 perform_test(column_infos, 2, 11);
164 assert_string_equal("师从螺丝xyz", print_buffer);
165
166 perform_test(column_infos, 2, 12);
167 assert_string_equal("师从螺丝 xyz", print_buffer);
168 }
169
143 170 TEST(add_ellipsis_ok, IF(locale_works)) TEST(add_ellipsis_ok, IF(locale_works))
144 171 { {
145 172 static column_info_t column_infos[2] = { static column_info_t column_infos[2] = {
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/vifm

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/vifm

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master