Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
int
get_key(char *buf, size_t size, size_t *nread)
{
	static struct {
		union {
			const char *s;
			char c;
		} input;
		size_t length;
		int key;
	} keys[] = {
		{ { (char *)8 },		1,	DEL },
		{ { (char *)10 },		1,	ENTER },
		{ { (char *)127 },		1,	DEL },
		{ { (char *)CTRL('A') },	1,	CTRL_A },
		{ { (char *)CTRL('B') },	1,	LEFT },
		{ { (char *)CTRL('D') },	1,	CTRL_D },
		{ { (char *)CTRL('E') },	1,	CTRL_E },
		{ { (char *)CTRL('F') },	1,	RIGHT },
		{ { (char *)CTRL('K') },	1,	CTRL_K },
		{ { (char *)CTRL('N') },	1,	DOWN },
		{ { (char *)CTRL('P') },	1,	UP },
		{ { (char *)CTRL('U') },	1,	CTRL_U },
		{ { (char *)CTRL('W') },	1,	CTRL_W },
		{ { "\033\n" },			2,	ALT_ENTER },
		{ { "\033[A" },			3,	UP },
		{ { "\033OA" },			3,	UP },
		{ { "\033[B" },			3,	DOWN },
		{ { "\033OB" },			3,	DOWN },
		{ { "\033[C" },			3,	RIGHT },
		{ { "\033OC" },			3,	RIGHT },
		{ { "\033[D" },			3,	LEFT },
		{ { "\033OD" },			3,	LEFT },
		{ { NULL },			0,	0 },
	};
	const char	*input;
	int		 i;

	*nread = 0;
getc:
	buf[(*nread)++] = tty_getc();
	size--;
	for (i = 0; keys[i].input.s; i++) {
		input = keys[i].length > 1 ? keys[i].input.s : &keys[i].input.c;
		if (*nread > keys[i].length || strncmp(buf, input, *nread))
			continue;

		if (*nread == keys[i].length)
			return keys[i].key;

		/* Partial match found, continue reading. */
		if (size > 0)
			goto getc;
	}

	if (*nread > 1 && buf[0] == '\033' && (buf[1] == '[' || buf[1] == 'O'))
		/*
		 * A escape sequence which is not a supported key is being read.
		 * Ensure the whole sequence is read.
		 */
		while ((buf[*nread - 1] < '@' || buf[*nread - 1] > '~')
		    && size-- > 0)
			buf[(*nread)++] = tty_getc();

	if (!isu8start(buf[0]))
		return UNKNOWN;

	/*
	 * Ensure a whole Unicode character is read. The number of MSBs in the
	 * first octet of a Unicode character is equal to the number of octets
	 * the character consists of, followed by a zero. Therefore, as long as
	 * the MSB is not zero there is still bytes left to read.
	 */
	while (((buf[0] << *nread) & 0x80) == 0x80 && size-- > 0)
		buf[(*nread)++] = tty_getc();

	return UNKNOWN;
}
Example #4
0
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);
	}
}