static inline int myisalnum(char *s) { int cat, c; fz_chartorune(&c, s); cat = ucdn_get_general_category(c); if (cat >= UCDN_GENERAL_CATEGORY_LL && cat <= UCDN_GENERAL_CATEGORY_LU) return 1; if (cat >= UCDN_GENERAL_CATEGORY_ND && cat <= UCDN_GENERAL_CATEGORY_NO) return 1; return 0; }
static int ui_input_key(struct input *input) { switch (ui.key) { case KEY_LEFT: if (ui.mod == GLFW_MOD_CONTROL + GLFW_MOD_SHIFT) { input->q = prev_word(input->q, input->text); } else if (ui.mod == GLFW_MOD_CONTROL) { if (input->p != input->q) input->p = input->q = input->p < input->q ? input->p : input->q; else input->p = input->q = prev_word(input->q, input->text); } else if (ui.mod == GLFW_MOD_SHIFT) { if (input->q > input->text) input->q = prev_char(input->q, input->text); } else if (ui.mod == 0) { if (input->p != input->q) input->p = input->q = input->p < input->q ? input->p : input->q; else if (input->q > input->text) input->p = input->q = prev_char(input->q, input->text); } break; case KEY_RIGHT: if (ui.mod == GLFW_MOD_CONTROL + GLFW_MOD_SHIFT) { input->q = next_word(input->q, input->end); } else if (ui.mod == GLFW_MOD_CONTROL) { if (input->p != input->q) input->p = input->q = input->p > input->q ? input->p : input->q; else input->p = input->q = next_word(input->q, input->end); } else if (ui.mod == GLFW_MOD_SHIFT) { if (input->q < input->end) input->q = next_char(input->q); } else if (ui.mod == 0) { if (input->p != input->q) input->p = input->q = input->p > input->q ? input->p : input->q; else if (input->q < input->end) input->p = input->q = next_char(input->q); } break; case KEY_UP: case KEY_HOME: if (ui.mod == GLFW_MOD_CONTROL + GLFW_MOD_SHIFT) { input->q = input->text; } else if (ui.mod == GLFW_MOD_CONTROL) { input->p = input->q = input->text; } else if (ui.mod == GLFW_MOD_SHIFT) { input->q = input->text; } else if (ui.mod == 0) { input->p = input->q = input->text; } break; case KEY_DOWN: case KEY_END: if (ui.mod == GLFW_MOD_CONTROL + GLFW_MOD_SHIFT) { input->q = input->end; } else if (ui.mod == GLFW_MOD_CONTROL) { input->p = input->q = input->end; } else if (ui.mod == GLFW_MOD_SHIFT) { input->q = input->end; } else if (ui.mod == 0) { input->p = input->q = input->end; } break; case KEY_DELETE: if (input->p != input->q) ui_input_delete_selection(input); else if (input->p < input->end) { char *np = next_char(input->p); memmove(input->p, np, input->end - np); input->end -= np - input->p; *input->end = 0; input->q = input->p; } break; case KEY_ESCAPE: return -1; case KEY_ENTER: return 1; case KEY_BACKSPACE: if (input->p != input->q) ui_input_delete_selection(input); else if (input->p > input->text) { char *pp = prev_char(input->p, input->text); memmove(pp, input->p, input->end - input->p); input->end -= input->p - pp; *input->end = 0; input->q = input->p = pp; } break; case KEY_CTL_A: input->p = input->q = input->text; break; case KEY_CTL_E: input->p = input->q = input->end; break; case KEY_CTL_W: if (input->p != input->q) ui_input_delete_selection(input); else { input->p = prev_word(input->p, input->text); ui_input_delete_selection(input); } break; case KEY_CTL_U: input->p = input->q = input->end = input->text; break; case KEY_CTL_C: case KEY_CTL_X: if (input->p != input->q) { char buf[sizeof input->text]; char *p = input->p < input->q ? input->p : input->q; char *q = input->p > input->q ? input->p : input->q; memmove(buf, p, q - p); buf[q-p] = 0; glfwSetClipboardString(window, buf); if (ui.key == KEY_CTL_X) ui_input_delete_selection(input); } break; case KEY_CTL_V: { const char *buf = glfwGetClipboardString(window); if (buf) ui_input_paste(input, buf, (int)strlen(buf)); } break; default: if (ui.key >= 32) { int cat = ucdn_get_general_category(ui.key); if (ui.key == ' ' || (cat >= UCDN_GENERAL_CATEGORY_LL && cat < UCDN_GENERAL_CATEGORY_ZL)) { char buf[8]; int n = fz_runetochar(buf, ui.key); ui_input_paste(input, buf, n); } } break; } return 0; }
static void generate_text(fz_context *ctx, fz_pool *pool, fz_html *box, const char *text) { fz_html *flow; int collapse = box->style.white_space & WS_COLLAPSE; int bsp = box->style.white_space & WS_ALLOW_BREAK_SPACE; int bnl = box->style.white_space & WS_FORCE_BREAK_NEWLINE; flow = box; while (flow->type != BOX_FLOW) flow = flow->up; while (*text) { if (bnl && (*text == '\n' || *text == '\r')) { if (text[0] == '\r' && text[1] == '\n') text += 2; else text += 1; add_flow_break(ctx, pool, flow, &box->style); } else if (iswhite(*text)) { const char *mark = text++; if (collapse) while (iswhite(*text)) ++text; /* TODO: tabs */ if (bsp) add_flow_glue(ctx, pool, flow, &box->style, " ", 1); else add_flow_word(ctx, pool, flow, &box->style, mark, text); } else { const char *mark = text; int c, addglue = 0; while (*text && !iswhite(*text)) { /* TODO: Unicode Line Breaking Algorithm (UAX #14) */ text += fz_chartorune(&c, text); if (iscjk(c)) { int cat = ucdn_get_general_category(c); if (addglue && !not_at_bol(cat, c)) add_flow_glue(ctx, pool, flow, &box->style, "", 0); add_flow_word(ctx, pool, flow, &box->style, mark, text); if (!not_at_eol(cat, c)) addglue = 1; mark = text; } else { addglue = 0; } } if (mark != text) add_flow_word(ctx, pool, flow, &box->style, mark, text); } } }