int min_match(const char *string, size_t offset, size_t *start, size_t *end) { char *s, *e, *q; q = query; if ((s = e = strcasechr(&string[offset], q)) == NULL) return 0; for (;;) { for (e++, q++; isu8cont(*q); e++, q++); if (*q == '\0') break; if ((e = strcasechr(e, q)) == NULL) return 0; } *start = s - string; *end = e - string; /* Less than or equal is used in order to obtain the left-most match. */ if (min_match(string, offset + 1, start, end) && (size_t)(e - s) <= *end - *start) { *start = s - string; *end = e - string; } return 1; }
/* * wr_fputs - like fputs(), but makes control characters visible and * turns \n into \r\n */ void wr_fputs(char *s) { #define PUTC(c) if (putchar(c) == EOF) goto err; for (; *s != '\0'; ++s) { if (*s == '\n') { PUTC('\r'); PUTC('\n'); continue; } if (isu8cont(*s)) continue; if (isprint(*s) || isspace(*s) || *s == '\a') { PUTC(*s); } else { PUTC('?'); } } return; err: err(1, NULL); #undef PUTC }
static edit_status editor_delete_char (rp_input_line *line) { size_t diff = 0; if (line->position == line->length) return EDIT_NO_OP; if (isu8start (line->buffer[line->position])) { do diff++; while (isu8cont (line->buffer[line->position + diff])); } else diff++; memmove (&line->buffer[line->position], &line->buffer[line->position + diff], line->length - line->position + diff + 1); line->length -= diff; return EDIT_DELETE; }
static edit_status editor_backward_char (rp_input_line *line) { if (line->position == 0) return EDIT_NO_OP; do line->position--; while (line->position > 0 && isu8cont (line->buffer[line->position])); return EDIT_MOVE; }
void print_query(char *query, size_t length, size_t position, size_t scroll) { size_t i = 0; tty_putp(restore_cursor); put_line(query + scroll, length - scroll); tty_putp(restore_cursor); while (i < position - scroll) { while (isu8cont(query[++i])); tty_putp(cursor_right); } }
static edit_status editor_forward_char (rp_input_line *line) { if (line->position == line->length) return EDIT_NO_OP; if (isu8start (line->buffer[line->position])) { do line->position++; while (isu8cont (line->buffer[line->position])); } else line->position++; return EDIT_MOVE; }
static edit_status editor_backward_delete_char (rp_input_line *line) { size_t diff = 1; if (line->position == 0) return EDIT_NO_OP; while (line->position - diff > 0 && isu8cont (line->buffer[line->position - diff])) diff++; memmove (&line->buffer[line->position - diff], &line->buffer[line->position], line->length - line->position + 1); line->position -= diff; line->length -= diff; return EDIT_DELETE; }
int print_choices(int selection) { int col, i, j, k; size_t query_length; struct choice *choice; tty_putp(clr_eos); /* Emit query line. */ tty_putc('\n'); query_length = strlen(query); for (choice = choices.v, col = i = 0; i < (ssize_t)choices.length && i < lines - 1 && (query_length == 0 || choice->score > 0); choice++, i++) { if (i == selection) tty_putp(enter_standout_mode); for (col = j = 0; j < (ssize_t)choice->match_start && col < columns; col += !isu8cont(choice->string[j]), j++) if (tty_putc(choice->string[j]) == EOF) err(1, "tty_putc"); tty_putp(enter_underline_mode); for (; j < (ssize_t)choice->match_end && col < columns; col += !isu8cont(choice->string[j]), j++) if (tty_putc(choice->string[j]) == EOF) err(1, "tty_putc"); tty_putp(exit_underline_mode); for (; j < (ssize_t)choice->length && col < columns; col += !isu8cont(choice->string[j]), j++) { /* A null character will be present before the * terminating null character if descriptions is * enabled. */ if (choice->string[j] == '\0') { if (tty_putc(' ') == EOF) err(1, "tty_putc"); } else if (tty_putc(choice->string[j]) == EOF) { err(1, "tty_putc"); } } for (k = MAX(columns - choice->printable_length + (choice->length - col), 0); k > 0; k--) if (tty_putc(' ') == EOF) err(1, "tty_putc"); if (i == selection) tty_putp(exit_standout_mode); } return i; }
const struct choice * selected_choice(void) { char buf[6]; int key, selection = 0, visible_choices_count; int word_position; size_t cursor_position, length, query_length, scroll; cursor_position = query_length = strlen(query); filter_choices(); init_tty(); if (cursor_position >= (size_t)columns) scroll = cursor_position - columns + 1; else scroll = 0; visible_choices_count = print_choices(selection); print_query(query, query_length, cursor_position, scroll); tty_putp(cursor_normal); for (;;) { fflush(tty_out); memset(buf, 0, sizeof(buf)); key = get_key(buf, sizeof(buf), &length); switch (key) { case ENTER: if (visible_choices_count > 0) { restore_tty(); if (selection >= 0 && selection < (ssize_t)choices.length) return &choices.v[selection]; else return NULL; } break; case ALT_ENTER: restore_tty(); choices.v[choices.length].string = query; choices.v[choices.length].description = ""; return &choices.v[choices.length]; case DEL: if (cursor_position > 0) { for (length = 1; isu8cont(query[cursor_position - length]); length++); delete_between( query, query_length, cursor_position - length, cursor_position); cursor_position -= length; query_length -= length; filter_choices(); selection = 0; } break; case CTRL_D: if (cursor_position < query_length) { for (length = 1; isu8cont(query[cursor_position + length]); length++); delete_between( query, query_length, cursor_position, cursor_position + length); query_length -= length; filter_choices(); selection = 0; } break; case CTRL_U: delete_between( query, query_length, 0, cursor_position); query_length -= cursor_position; cursor_position = 0; filter_choices(); selection = 0; break; case CTRL_K: delete_between( query, query_length, cursor_position, query_length); query_length = cursor_position; filter_choices(); selection = 0; break; case CTRL_W: if (cursor_position == 0) break; for (word_position = cursor_position;;) { while (isu8cont(query[--word_position])); if (word_position < 1) break; if (query[word_position] != ' ' && query[word_position - 1] == ' ') break; } delete_between( query, query_length, word_position, cursor_position); query_length -= cursor_position - word_position; cursor_position = word_position; filter_choices(); selection = 0; break; case CTRL_A: cursor_position = 0; break; case CTRL_E: cursor_position = query_length; break; case DOWN: if (selection < visible_choices_count - 1) ++selection; break; case UP: if (selection > 0) --selection; break; case LEFT: while (cursor_position > 0 && isu8cont(query[--cursor_position])); break; case RIGHT: while (cursor_position < query_length && isu8cont(query[++cursor_position])); break; default: if (!isu8start(buf[0]) && !isprint(buf[0])) continue; if (query_size < query_length + length) { query_size = 2*query_length + length; if ((query = reallocarray(query, query_size, sizeof(char))) == NULL) err(1, NULL); } if (cursor_position < query_length) memmove(query + cursor_position + length, query + cursor_position, query_length - cursor_position); memcpy(query + cursor_position, buf, length); cursor_position += length; query_length += length; query[query_length] = '\0'; filter_choices(); selection = 0; break; } tty_putp(cursor_invisible); visible_choices_count = print_choices(selection); if (cursor_position >= scroll + columns) scroll = cursor_position - columns + 1; if (cursor_position < scroll) scroll = cursor_position; print_query(query, query_length, cursor_position, scroll); tty_putp(cursor_normal); } }