/* Truncate the msg to the width by placing ellipsis in the middle and put the * result to the buffer. */ static void truncate_with_ellipsis(const char msg[], size_t width, char buffer[]) { const size_t screen_len = utf8_strsw(msg); const size_t screen_left_len = (width - 3)/2; const size_t screen_right_len = (width - 3) - screen_left_len; const size_t left = utf8_nstrsnlen(msg, screen_left_len); const size_t right = utf8_nstrsnlen(msg, screen_len - screen_right_len); strncpy(buffer, msg, left); strcpy(buffer + left, "..."); strcpy(buffer + left + 3, msg + right); assert(utf8_strsw(buffer) == width); }
static void column_line_print(const void *data, int column_id, const char buf[], size_t offset, AlignType align) { strncpy(print_buffer + utf8_nstrsnlen(print_buffer, offset), buf, strlen(buf)); }
/* Draws box and title of the menu. */ static void draw_menu_frame(const menu_state_t *m) { const size_t title_len = getmaxx(menu_win) - 2*4; const char *const suffix = menu_and_view_are_in_sync(m->d, m->view) ? "" : replace_home_part(m->d->cwd); const char *const at = (suffix[0] == '\0' ? "" : " @ "); char *const title = format_str("%s%s%s", m->d->title, at, suffix); if(utf8_strsw(title) > title_len) { const size_t len = utf8_nstrsnlen(title, title_len - 3); strcpy(title + len, "..."); } box(menu_win, 0, 0); wattron(menu_win, A_BOLD); checked_wmove(menu_win, 0, 3); wprint(menu_win, " "); wprint(menu_win, title); wprint(menu_win, " "); wattroff(menu_win, A_BOLD); free(title); }
TEST(length_is_less_or_equal_to_string_length, IF(utf8_locale)) { const char *str = "01 R\366yksopp - You Know I Have To Go (\326z" "g\374r \326zkan 5 AM Edit).mp3"; const size_t len = strlen(str); size_t i; for(i = 0; i < len; ++i) { assert_true(utf8_nstrsnlen(str, i) <= i); } }
/* Prints item prefixed with a label truncating the item if it's too long. * Returns increment for curr_y. */ static int print_item(const char label[], const char path[], int curr_y) { const int max_width = getmaxx(menu_win) - strlen(label) - 2; const size_t print_len = utf8_nstrsnlen(path, max_width); mvwaddstr(menu_win, curr_y, 2, label); if(path[print_len] == '\0') { wprint(menu_win, path); } else { char path_buf[PATH_MAX]; copy_str(path_buf, MIN(sizeof(path_buf), print_len + 1), path); wprint(menu_win, path_buf); } return 2; }
/* Draws single menu item at position specified by line argument. Non-zero * clear argument suppresses drawing current items in different color. */ static void draw_menu_item(menu_state_t *ms, int pos, int line, int clear) { menu_data_t *const m = ms->d; int i; int off; char *item_tail; const int width = (curr_stats.load_stage == 0) ? 100 : getmaxx(menu_win) - 2; /* Calculate color for the line. */ int attrs; col_attr_t col = cfg.cs.color[WIN_COLOR]; if(cfg.hl_search && ms->search_highlight && ms->matches != NULL && ms->matches[pos][0] >= 0) { cs_mix_colors(&col, &cfg.cs.color[SELECTED_COLOR]); } if(!clear && pos == m->pos) { cs_mix_colors(&col, &cfg.cs.color[CURR_LINE_COLOR]); } attrs = COLOR_PAIR(colmgr_get_pair(col.fg, col.bg)) | col.attr; /* Calculate offset of m->hor_pos's character in item text. */ off = 0; i = m->hor_pos; while(i-- > 0 && m->items[pos][off] != '\0') { off += utf8_chrw(m->items[pos] + off); } item_tail = strdup(m->items[pos] + off); replace_char(item_tail, '\t', ' '); wattron(menu_win, attrs); /* Clear the area. */ checked_wmove(menu_win, line, 1); if(curr_stats.load_stage != 0) { wprintw(menu_win, "%*s", width, ""); } /* Draw visible part of item. */ checked_wmove(menu_win, line, 2); if(utf8_strsw(item_tail) > (size_t)(width - 2)) { void *p; const size_t len = utf8_nstrsnlen(item_tail, width - 3 - 2 + 1); memset(item_tail + len, ' ', strlen(item_tail) - len); p = realloc(item_tail, len + 4); if(p != NULL) { item_tail = p; strcpy(item_tail + len - 1, "..."); } wprint(menu_win, item_tail); } else { const size_t len = utf8_nstrsnlen(item_tail, width - 2 + 1); item_tail[len] = '\0'; wprint(menu_win, item_tail); } wattroff(menu_win, attrs); if(ms->search_highlight && ms->matches != NULL && ms->matches[pos][0] >= 0) { draw_search_match(item_tail, ms->matches[pos][0] - m->hor_pos, ms->matches[pos][1] - m->hor_pos, line, width, attrs); } free(item_tail); }