Example #1
0
File: keys.c Project: jubalh/vifm
/* Reads count of the command.  Sets *count to NO_COUNT_GIVEN if there is no
 * count in the current position.  Returns pointer to a character right next to
 * the count. */
static const wchar_t *
get_count(const wchar_t keys[], int *count)
{
	if(is_at_count(keys))
	{
		wchar_t *ptr;
		*count = wcstol(keys, &ptr, 10);
		/* Handle overflow correctly. */
		if(*count <= 0)
		{
			*count = INT_MAX;
		}
		keys = ptr;
	}
	else
	{
		*count = NO_COUNT_GIVEN;
	}

	return keys;
}
Example #2
0
File: keys.c Project: jubalh/vifm
/* Dispatches keys passed in using a tree of shortcuts registered in the root.
 * Returns error code. */
static int
dispatch_keys_at_root(const wchar_t keys[], keys_info_t *keys_info,
		key_chunk_t *root, key_info_t key_info, int no_remap)
{
	key_chunk_t *curr;
	const wchar_t *keys_start = keys;
	int has_duplicate;
	int result;

	/* The loop finds longest match of the input (keys) amoung registered
	 * shortcuts. */
	curr = root;
	while(*keys != L'\0')
	{
		key_chunk_t *p;
		int number_in_the_middle = 0;

		p = curr->child;
		while(p != NULL && p->key < *keys)
		{
			if(p->conf.type == BUILTIN_NIM_KEYS)
			{
				number_in_the_middle = 1;
			}
			p = p->next;
		}

		if(p == NULL || p->key != *keys)
		{
			if(curr == root)
				return KEYS_UNKNOWN;

			while(p != NULL)
			{
				if(p->conf.type == BUILTIN_NIM_KEYS)
				{
					number_in_the_middle = 1;
				}
				p = p->next;
			}

			if(curr->conf.followed != FOLLOWED_BY_NONE &&
					(!number_in_the_middle || !is_at_count(keys)))
			{
				break;
			}

			if(number_in_the_middle)
			{
				int count;
				const wchar_t *new_keys = get_count(keys, &count);
				if(new_keys != keys)
				{
					key_info.count = combine_counts(key_info.count, count);
					keys = new_keys;
					continue;
				}
			}

			if(curr->conf.type == BUILTIN_WAIT_POINT)
			{
				return KEYS_UNKNOWN;
			}

			has_duplicate = root == &user_cmds_root[vle_mode_get()] &&
					contains_chain(&builtin_cmds_root[vle_mode_get()], keys_start, keys);
			result = execute_next_keys(curr, curr->conf.type == USER_CMD ? keys : L"",
					&key_info, keys_info, has_duplicate, no_remap);
			if(curr->conf.type == USER_CMD)
				return result;
			if(IS_KEYS_RET_CODE(result))
			{
				if(result == KEYS_WAIT_SHORT)
					return KEYS_UNKNOWN;

				return result;
			}
			inc_counter(keys_info, keys - keys_start);
			return execute_keys_general(keys, 0, keys_info->mapped, no_remap);
		}
		keys++;
		curr = p;
	}

	if(*keys == '\0' && curr->conf.type != BUILTIN_WAIT_POINT &&
			curr->children_count > 0 && curr->conf.data.handler != NULL &&
			!keys_info->after_wait)
	{
		return KEYS_WAIT_SHORT;
	}

	has_duplicate = root == &user_cmds_root[vle_mode_get()] &&
			contains_chain(&builtin_cmds_root[vle_mode_get()], keys_start, keys);
	result = execute_next_keys(curr, keys, &key_info, keys_info, has_duplicate,
			no_remap);
	if(!IS_KEYS_RET_CODE(result))
	{
		inc_counter(keys_info, keys - keys_start);
	}
	else if(*keys == '\0' && result == KEYS_UNKNOWN && curr->children_count > 0)
	{
		return keys_info->after_wait ? KEYS_UNKNOWN : KEYS_WAIT_SHORT;
	}
	return result;
}
Example #3
0
File: keys.c Project: acklinr/vifm
/* Looks up possible continuations of keys for the given root and calls cb on
 * them. */
static void
keys_suggest(const key_chunk_t *root, const wchar_t keys[],
		const wchar_t prefix[], vle_keys_list_cb cb, int custom_only,
		int fold_subkeys)
{
	const key_chunk_t *curr = root;

	while(*keys != L'\0')
	{
		const key_chunk_t *p;
		int number_in_the_middle = 0;

		/* Look up current key among children of current node (might be root), while
		 * inspecting NIM as well. */
		for(p = curr->child; p != NULL && p->key < *keys; p = p->next)
		{
			if(p->type == BUILTIN_NIM_KEYS)
			{
				number_in_the_middle = 1;
			}
		}

		/* Go to the next character if a match found. */
		if(p != NULL && p->key == *keys)
		{
			++keys;
			curr = p;
			continue;
		}

		/* No match for the first character is fatal for the lookup. */
		if(curr == root)
		{
			return;
		}

		/* Need to inspect all children for NIM. */
		for(; p != NULL && !number_in_the_middle; p = p->next)
		{
			if(p->type == BUILTIN_NIM_KEYS)
			{
				number_in_the_middle = 1;
			}
		}

		/* Give up if this isn't one of cases where next character is not presented
		 * in the tree by design. */
		if(curr->conf.followed != FOLLOWED_BY_NONE &&
				(!number_in_the_middle || !is_at_count(keys)))
		{
			break;
		}

		/* Skip over number in the middle, if any. */
		if(number_in_the_middle)
		{
			int count;
			const wchar_t *new_keys = get_count(keys, &count);
			if(new_keys != keys)
			{
				keys = new_keys;
				continue;
			}
		}

		break;
	}

	if(!custom_only && *keys == L'\0')
	{
		suggest_children(curr, prefix, cb, fold_subkeys);
	}

	if(curr->type == BUILTIN_WAIT_POINT)
	{
		if(curr->conf.followed == FOLLOWED_BY_SELECTOR)
		{
			/* Suggest selectors. */
			keys_suggest(&selectors_root[vle_mode_get()], keys, L"sel: ", cb,
					custom_only, fold_subkeys);
		}
		else if(curr->conf.followed == FOLLOWED_BY_MULTIKEY)
		{
			/* Invoke optional external function to provide suggestions. */
			if(curr->conf.suggest != NULL)
			{
				curr->conf.suggest(cb);
			}
		}
	}
}