commit 17e5106b8ecac061d8558f1d73f284c5516347cd from: Omar Polo date: Sun Mar 21 16:19:01 2021 UTC UTF8 input for the minibuffer! commit - 8947c1f29122ab2e506b2bb723a4fc92bd9d3a59 commit + 17e5106b8ecac061d8558f1d73f284c5516347cd blob - 404312ec0aba8b3eca9ca668466fb8ffe6e5b933 blob + 17dd7e40516f85b94911879c02fb06aa540ab44a --- telescope.h +++ telescope.h @@ -256,16 +256,21 @@ void ui_end(void); /* utf.8 */ uint32_t utf8_decode(uint32_t*restrict, uint32_t*restrict, uint8_t); -void utf8_encode(uint32_t, char*); +size_t utf8_encode(uint32_t, char*); char *utf8_nth(char*, size_t); size_t utf8_cplen(char*); size_t utf8_chwidth(uint32_t); size_t utf8_snwidth(const char*, size_t); size_t utf8_swidth(const char*); +size_t utf8_swidth_between(const char*, const char*); +char *utf8_next_cp(char*); +char *utf8_prev_cp(char*, char*); /* util.c */ int mark_nonblock(int); int has_prefix(const char*, const char*); +int unicode_isspace(uint32_t); +int unicode_isgraph(uint32_t); void dispatch_imsg(struct imsgbuf*, imsg_handlerfn**, size_t); /* wrap.c */ blob - ac2a27eb58345f3820fc77fe3e629e65c662714e blob + ec6035aa0bce147c1c8b077104d6202d950a643b --- ui.c +++ ui.c @@ -36,7 +36,6 @@ #include -#include #include #include #include @@ -168,14 +167,15 @@ static struct { char *curmesg; char buf[1025]; - size_t off, len; + char *curs; + size_t cpoff; char prompt[32]; void (*donefn)(void); void (*abortfn)(void); struct histhead *history; struct hist *hist_cur; - size_t hist_off; + size_t hist_off; } ministate; struct lineprefix { @@ -766,8 +766,7 @@ cmd_load_current_url(struct tab *tab) &lu_history); strlcpy(ministate.prompt, "Load URL: ", sizeof(ministate.prompt)); strlcpy(ministate.buf, tab->hist_cur->h, sizeof(ministate.buf)); - ministate.off = strlen(tab->hist_cur->h); - ministate.len = ministate.off; + ministate.curs = strchr(ministate.buf, '\0'); } static void @@ -776,8 +775,7 @@ cmd_bookmark_page(struct tab *tab) enter_minibuffer(lu_self_insert, bp_select, exit_minibuffer, NULL); strlcpy(ministate.prompt, "Bookmark URL: ", sizeof(ministate.prompt)); strlcpy(ministate.buf, tab->hist_cur->h, sizeof(ministate.buf)); - ministate.off = strlen(tab->hist_cur->h); - ministate.len = ministate.off; + ministate.curs = strchr(ministate.buf, '\0'); } static void @@ -795,75 +793,72 @@ global_key_unbound(void) static void cmd_mini_delete_char(struct tab *tab) { + char *n; + minibuffer_taint_hist(); - if (ministate.len == 0 || ministate.off == ministate.len) + if (*(n = utf8_next_cp(ministate.curs)) == '\0') return; - memmove(&ministate.buf[ministate.off], - &ministate.buf[ministate.off+1], - ministate.len - ministate.off + 1); - ministate.len--; + memmove(ministate.curs, n, strlen(n)+1); } static void cmd_mini_delete_backward_char(struct tab *tab) { + char *p; + minibuffer_taint_hist(); - if (ministate.len == 0 || ministate.off == 0) + if ((p = utf8_prev_cp(ministate.curs, ministate.buf)) == ministate.buf) return; - memmove(&ministate.buf[ministate.off-1], - &ministate.buf[ministate.off], - ministate.len - ministate.off + 1); - ministate.off--; - ministate.len--; + memmove(p, ministate.curs, strlen(ministate.curs)+1); } static void cmd_mini_forward_char(struct tab *tab) { - if (ministate.off == ministate.len) + if (*ministate.curs == '\0') return; - ministate.off++; + ministate.curs = utf8_next_cp(ministate.curs); + ministate.cpoff++; } static void cmd_mini_backward_char(struct tab *tab) { - if (ministate.off == 0) + if (ministate.cpoff == 0) return; - ministate.off--; + ministate.cpoff--; + ministate.curs = utf8_prev_cp(ministate.curs-1, ministate.buf); } static void cmd_mini_move_end_of_line(struct tab *tab) { - ministate.off = ministate.len; + ministate.curs = strchr(ministate.buf, '\0'); + ministate.cpoff = utf8_cplen(ministate.buf); } static void cmd_mini_move_beginning_of_line(struct tab *tab) { - ministate.off = 0; + ministate.curs = ministate.buf; + ministate.cpoff = 0; } static void cmd_mini_kill_line(struct tab *tab) { minibuffer_taint_hist(); - - if (ministate.off == ministate.len) - return; - ministate.buf[ministate.off] = '\0'; - ministate.len -= ministate.off; + *ministate.curs = '\0'; } static void cmd_mini_abort(struct tab *tab) { - ministate.abortfn(); + ministate.abortfn(); } static void @@ -891,10 +886,8 @@ cmd_mini_previous_history_element(struct tab *tab) ministate.hist_off--; } - if (ministate.hist_cur != NULL) { - ministate.off = 0; - ministate.len = strlen(ministate.hist_cur->h); - } + if (ministate.hist_cur != NULL) + ministate.curs = ministate.hist_cur->h; } static void @@ -915,10 +908,8 @@ cmd_mini_next_history_element(struct tab *tab) ministate.hist_off++; } - if (ministate.hist_cur != NULL) { - ministate.off = 0; - ministate.len = strlen(ministate.hist_cur->h); - } + if (ministate.hist_cur != NULL) + ministate.curs = ministate.hist_cur->h; } static void @@ -959,26 +950,29 @@ minibuffer_taint_hist(void) static void minibuffer_self_insert(void) { + char tmp[5] = {0}; + size_t len; + minibuffer_taint_hist(); - if (ministate.len == sizeof(ministate.buf) -1) + if (thiskey.cp == 0) return; - /* TODO: utf8 handling! */ + len = utf8_encode(thiskey.cp, tmp); + if (ministate.curs + len > ministate.buf + sizeof(ministate.buf) - 1) + return; - memmove(&ministate.buf[ministate.off+1], - &ministate.buf[ministate.off], - ministate.len - ministate.off + 1); - ministate.buf[ministate.off] = thiskey.key; - ministate.off++; - ministate.len++; + memmove(ministate.curs + len, ministate.curs, strlen(ministate.curs)+1); + memcpy(ministate.curs, tmp, len); + ministate.curs = utf8_next_cp(ministate.curs); + ministate.cpoff++; } static void eecmd_self_insert(void) { - if (thiskey.meta || isspace(thiskey.key) || - !isgraph(thiskey.key)) { + if (thiskey.meta || unicode_isspace(thiskey.cp) || + !unicode_isgraph(thiskey.cp)) { global_key_unbound(); return; } @@ -1022,8 +1016,8 @@ ir_select(void) static void lu_self_insert(void) { - if (thiskey.meta || isspace(thiskey.key) || - !isgraph(thiskey.key)) { + if (thiskey.meta || unicode_isspace(thiskey.key) || + !unicode_isgraph(thiskey.key)) { global_key_unbound(); return; } @@ -1426,10 +1420,12 @@ redraw_modeline(struct tab *tab) static void redraw_minibuffer(void) { - size_t skip = 0, off_x = 0, off_y = 0; struct tab *tab; + size_t off_y, off_x = 0; + char *start; werase(minibuf); + if (in_minibuffer) { mvwprintw(minibuf, 0, 0, "%s", ministate.prompt); if (ministate.hist_cur != NULL) @@ -1439,37 +1435,33 @@ redraw_minibuffer(void) getyx(minibuf, off_y, off_x); - while (ministate.off - skip > (size_t)COLS / 2) { - skip += MIN(ministate.off/4, 1); + start = ministate.hist_cur != NULL + ? ministate.hist_cur->h + : ministate.buf; + while (utf8_swidth_between(start, ministate.curs) > (size_t)COLS/2) { + start = utf8_next_cp(start); } - if (ministate.hist_cur != NULL) - wprintw(minibuf, "%s", ministate.hist_cur->h + skip); - else - wprintw(minibuf, "%s", ministate.buf + skip); + waddstr(minibuf, start); } - if (ministate.curmesg != NULL) { - if (in_minibuffer) - wprintw(minibuf, " [%s]", ministate.curmesg); - else - wprintw(minibuf, "%s", ministate.curmesg); - } + if (ministate.curmesg != NULL) + wprintw(minibuf, in_minibuffer ? " [%s]" : "%s", + ministate.curmesg); if (!in_minibuffer && ministate.curmesg == NULL) - wprintw(minibuf, "%s", keybuf); + waddstr(minibuf, keybuf); /* If nothing else, show the URL at point */ if (!in_minibuffer && ministate.curmesg == NULL && *keybuf == '\0') { tab = current_tab(); if (tab->s.current_line != NULL && tab->s.current_line->parent->type == LINE_LINK) - wprintw(minibuf, "%s", - tab->s.current_line->parent->alt); + waddstr(minibuf, tab->s.current_line->parent->alt); } if (in_minibuffer) - wmove(minibuf, 0, off_x + ministate.off - skip); + wmove(minibuf, 0, off_x + utf8_swidth_between(start, ministate.curs)); } static void @@ -1625,8 +1617,8 @@ enter_minibuffer(void (*self_insert_fn)(void), void (* ministate.donefn = donefn; ministate.abortfn = abortfn; memset(ministate.buf, 0, sizeof(ministate.buf)); - ministate.off = 0; - ministate.len = 0; + ministate.curs = ministate.buf; + ministate.cpoff = 0; strlcpy(ministate.buf, "", sizeof(ministate.prompt)); ministate.history = hist; blob - 127fbb5153f75ff8a6135564ac27df0b9d7ae17c blob + 98aa6ca7aa2f966abcac792d28ef44e1c84b3624 --- utf8.c +++ utf8.c @@ -64,25 +64,31 @@ utf8_decode(uint32_t* restrict state, uint32_t* restri /* end of the converter, utility functions ahead */ /* encode cp in s. s must be at least 4 bytes wide */ -void +size_t utf8_encode(uint32_t cp, char *s) { if (cp <= 0x7F) { *s = (uint8_t)cp; + return 1; } else if (cp <= 0x7FF) { s[1] = (uint8_t)(( cp & 0x3F ) + 0x80); s[0] = (uint8_t)(((cp >> 6) & 0x1F) + 0xC0); + return 2; } else if (cp <= 0xFFFF) { s[2] = (uint8_t)(( cp & 0x3F) + 0x80); s[1] = (uint8_t)(((cp >> 6) & 0x3F) + 0x80); s[0] = (uint8_t)(((cp >> 12) & 0x0F) + 0xE0); + return 3; } else if (cp <= 0x10FFFF) { s[3] = (uint8_t)(( cp & 0x3F) + 0x80); s[2] = (uint8_t)(((cp >> 6) & 0x3F) + 0x80); s[1] = (uint8_t)(((cp >> 12) & 0x3F) + 0x80); s[0] = (uint8_t)(((cp >> 18) & 0x07) + 0xF0); - } else - s[0] = '\0'; + return 4; + } else { + s[0] = '\0'; + return 0; + } } char * @@ -159,3 +165,41 @@ utf8_swidth(const char *s) return tot; } + +size_t +utf8_swidth_between(const char *str, const char *end) +{ + size_t tot; + uint32_t cp = 0, state = 0; + + tot = 0; + for (; *str && str < end; ++str) + if (!utf8_decode(&state, &cp, *str)) + tot += utf8_chwidth(cp); + return tot; +} + +char * +utf8_next_cp(char *s) +{ + uint32_t cp = 0, state = 0; + + for (; *s; ++s) + if (!utf8_decode(&state, &cp, *s)) + break; + return s+1; +} + +char * +utf8_prev_cp(char *start, char *base) +{ + uint8_t c; + + for (; start > base; start--) { + c = *start; + if ((c & 0xC0) != 0x80) + return start; + } + + return base; +} blob - 88a155f7dac24ee2cba73a819c8ed0e2fd51ae35 blob + 5d0267624c08d1c1f99cedfe2af9e7b944e563d8 --- util.c +++ util.c @@ -16,6 +16,7 @@ #include "telescope.h" +#include #include #include #include @@ -44,6 +45,22 @@ has_prefix(const char *str, const char *prfx) return prfx[i] == '\0'; } +int +unicode_isspace(uint32_t cp) +{ + if (cp < INT8_MAX) + return isspace(cp); + return 0; +} + +int +unicode_isgraph(uint32_t cp) +{ + if (cp < INT8_MAX) + return isgraph(cp); + return 1; +} + void dispatch_imsg(struct imsgbuf *ibuf, imsg_handlerfn **handlers, size_t size) {