/* Return a pointer to start of current string, and set the suitable maximum * of can be displayed.(*len <= roll_display_window_size) */ char *roll_display_ptr(int *len, int *padding) { *len = *padding = 0; if (roll_display_length_max <= roll_display_window_size) { if (len) *len = roll_display_orig_size; if (padding) *padding = roll_display_window_size - roll_display_length_max; return roll_display_orig; } char *ret = roll_display_curr; char *tmp = roll_display_curr; int l = 0; int t; /* Assume non-ascii characters use 2 width of ascii to display. */ while (l < roll_display_window_size && *tmp) { t = utf8_char_length(tmp); l += (1 == t) ? 1 : 2; *len += t; tmp += t; } /* If display next non-ascii character will use width greater than * specified '*len' */ if (l > roll_display_window_size) { *len -= t; l -= (1 == t) ? 1 : 2; if (padding) *padding = roll_display_window_size - l; } if (likely(*tmp)) roll_display_curr += utf8_char_length(roll_display_curr); else roll_display_curr = roll_display_orig; return ret; }
static const char * get_author_initials(const char *author) { static char initials[256]; size_t pos = 0; const char *end = strchr(author, '\0'); #define is_initial_sep(c) (isspace(c) || ispunct(c) || (c) == '@' || (c) == '-') memset(initials, 0, sizeof(initials)); while (author < end) { unsigned char bytes; size_t i; while (author < end && is_initial_sep(*author)) author++; bytes = utf8_char_length(author); if (bytes >= sizeof(initials) - 1 - pos) break; while (bytes--) { initials[pos++] = *author++; } i = pos; while (author < end && !is_initial_sep(*author)) { bytes = utf8_char_length(author); if (bytes >= sizeof(initials) - 1 - i) { while (author < end && !is_initial_sep(*author)) author++; break; } while (bytes--) { initials[i++] = *author++; } } initials[i++] = 0; } return initials; }
/* Calculates how much of string can be shown within the given maximum width * and sets trimmed parameter to non-zero value if all of string could not be * shown. If the reserve flag is true, it will reserve at least one * trailing character, which can be useful when drawing a delimiter. * * Returns the number of bytes to output from string to satisfy max_width. */ size_t utf8_length(const char **start, int max_chars, size_t skip, int *width, size_t max_width, int *trimmed, bool reserve, int tab_size) { const char *string = *start; const char *end = max_chars < 0 ? strchr(string, '\0') : string + max_chars; unsigned char last_bytes = 0; size_t last_ucwidth = 0; *width = 0; *trimmed = 0; while (string < end) { unsigned char bytes = utf8_char_length(string); size_t ucwidth; unsigned long unicode; if (string + bytes > end) break; /* Change representation to figure out whether * it is a single- or double-width character. */ unicode = utf8_to_unicode(string, bytes); /* FIXME: Graceful handling of invalid Unicode character. */ if (!unicode) break; ucwidth = unicode_width(unicode, tab_size); if (skip > 0) { skip -= ucwidth <= skip ? ucwidth : skip; *start += bytes; } *width += ucwidth; if (max_width > 0 && *width > max_width) { *trimmed = 1; *width -= ucwidth; if (reserve && *width == max_width) { string -= last_bytes; *width -= last_ucwidth; } break; } string += bytes; if (ucwidth) { last_bytes = bytes; last_ucwidth = ucwidth; } else { last_bytes += bytes; } } return string - *start; }
unsigned int source_pos_t::col(char *input) { unsigned int col = 1; char *c = input + line_offset; char *e = input + offset; while (c < e) { size_t len = utf8_char_length(*c); c += len; col++; } return col; }
const char* utf8_skip(const char *string, size_t skip) { while (skip-- > 0) { unsigned char len = utf8_char_length(string); assert(len > 0); while (len-- > 0) { if (!*string) return string; string++; } } return string; }
size_t utf8_char_count(const char *string) { size_t count = 0; while (1) { unsigned char len = utf8_char_length(string); while (len-- > 0) { if (!*string) return count; string++; } count += 1; } }
int roll_display_init(char *s, int window_size) { if (!s || window_size <= 0) return -1; char *ptr = s; int tmp; roll_display_orig = s; roll_display_curr = s; roll_display_window_size = window_size; roll_display_orig_size = strlen(s); while (*ptr) { tmp = utf8_char_length(ptr); roll_display_length_max += (1 == tmp? 1 : 2) ; ptr += tmp; } return 0; }
int get_key_value(const char *name, struct key_input *input) { int i; memset(input, 0, sizeof(*input)); for (i = 0; i < ARRAY_SIZE(key_table); i++) if (!strcasecmp(key_table[i].name, name)) { if (key_table[i].value == ' ') { name = " "; break; } if (key_table[i].value == '#') { name = "#"; break; } input->data.key = key_table[i].value; return OK; } if (name[0] == '^' && name[1] == '[') { input->modifiers.escape = 1; name += 2; } else if (name[0] == '^') { input->modifiers.control = 1; name += 1; } i = utf8_char_length(name); if (strlen(name) == i && utf8_to_unicode(name, i) != 0) { strncpy(input->data.bytes, name, i); input->modifiers.multibytes = 1; return OK; } return ERR; }
static enum status_code parse_key_value(struct key *key, const char **name_ptr, size_t offset, const char *replacement, const char *end) { const char *name = replacement ? replacement : *name_ptr + offset; size_t namelen = utf8_char_length(name); const char *nameend = name + namelen; if (strlen(name) < namelen || utf8_to_unicode(name, namelen) == 0) return error("Error parsing UTF-8 bytes: %s", name); strncpy(key->data.bytes, name, namelen); key->modifiers.multibytes = 1; if (end) { *name_ptr = end + 1; if (!replacement && nameend + 1 < end) return success("Ignoring text after key mapping: %.*s", (int) (end - nameend), nameend); } else { *name_ptr = nameend; } return SUCCESS; }
int get_input(int prompt_position, struct key_input *input, bool modifiers) { struct view *view; int i, key, cursor_y, cursor_x; if (prompt_position) input_mode = TRUE; memset(input, 0, sizeof(*input)); while (TRUE) { bool loading = FALSE; foreach_view (view, i) { update_view(view); if (view_is_displayed(view) && view->has_scrolled && use_scroll_redrawwin) redrawwin(view->win); view->has_scrolled = FALSE; if (view->pipe) loading = TRUE; } /* Update the cursor position. */ if (prompt_position) { getbegyx(status_win, cursor_y, cursor_x); cursor_x = prompt_position; } else { view = display[current_view]; getbegyx(view->win, cursor_y, cursor_x); cursor_x = view->width - 1; cursor_y += view->pos.lineno - view->pos.offset; } setsyx(cursor_y, cursor_x); /* Refresh, accept single keystroke of input */ doupdate(); nodelay(status_win, loading); key = wgetch(status_win); /* wgetch() with nodelay() enabled returns ERR when * there's no input. */ if (key == ERR) { } else if (key == KEY_ESC && modifiers) { input->modifiers.escape = 1; } else if (key == KEY_RESIZE) { int height, width; getmaxyx(stdscr, height, width); wresize(status_win, 1, width); mvwin(status_win, height - 1, 0); wnoutrefresh(status_win); resize_display(); redraw_display(TRUE); } else { int pos, key_length; input_mode = FALSE; if (key == erasechar()) key = KEY_BACKSPACE; /* * Ctrl-<key> values are represented using a 0x1F * bitmask on the key value. To 'unmap' we assume that: * * - Ctrl-Z is handled by Ncurses. * - Ctrl-m is the same as Return/Enter. * - Ctrl-i is the same as Tab. * * For all other key values in the range the Ctrl flag * is set and the key value is updated to the proper * ASCII value. */ if (KEY_CTL('a') <= key && key <= KEY_CTL('x') && key != KEY_RETURN && key != KEY_TAB) { input->modifiers.control = 1; key = key | 0x40; } if ((key >= KEY_MIN && key < KEY_MAX) || key < 0x1F) { // || key == ' ') { input->data.key = key; return input->data.key; } input->modifiers.multibytes = 1; input->data.bytes[0] = key; key_length = utf8_char_length(input->data.bytes); for (pos = 1; pos < key_length && pos < sizeof(input->data.bytes) - 1; pos++) { input->data.bytes[pos] = wgetch(status_win); } return OK; } }