Change lookahead_list into a queue

Using builtin `commandline -f`, one would expect to have commands executed in
the order that they were given.  This motivates the change to a queue.

Unfortunately, fish internals still need lookahead_list to act as a stack.  Add
and rename functions to support both cases and have lookahead_list as
a std::deque internally.

This code is delicate, and we should probably dog-food this in nightly for
a while before the next-minor release.

Fixes #1567
This commit is contained in:
Sanne Wouda 2015-04-05 20:07:17 +02:00 committed by ridiculousfish
parent 3559f20c8f
commit 32936b0eb9
6 changed files with 48 additions and 33 deletions

View file

@ -455,10 +455,10 @@ static int builtin_commandline(parser_t &parser, wchar_t **argv)
{
/*
input_unreadch inserts the specified keypress or
readline function at the top of the stack of unused
readline function at the back of the queue of unused
keypresses
*/
input_unreadch(c);
input_queue_ch(c);
}
else
{

View file

@ -2389,11 +2389,9 @@ static void test_input()
input_mapping_add(prefix_binding.c_str(), L"up-line");
input_mapping_add(desired_binding.c_str(), L"down-line");
/* Push the desired binding on the stack (backwards!) */
size_t idx = desired_binding.size();
while (idx--)
{
input_unreadch(desired_binding.at(idx));
/* Push the desired binding to the queue */
for (size_t idx = 0; idx < desired_binding.size(); idx++) {
input_queue_ch(desired_binding.at(idx));
}
/* Now test */

View file

@ -583,7 +583,7 @@ static void input_mapping_execute(const input_mapping_t &m, bool allow_commands)
wchar_t code = input_function_get_code(command);
if (code != (wchar_t)-1)
{
input_unreadch(code);
input_common_next_ch(code);
}
else if (allow_commands)
{
@ -596,16 +596,16 @@ static void input_mapping_execute(const input_mapping_t &m, bool allow_commands)
proc_set_last_status(last_status);
input_unreadch(R_NULL);
input_common_next_ch(R_NULL);
}
else
{
/* We don't want to run commands yet. Put the characters back and return R_NULL */
for (wcstring::const_reverse_iterator it = m.seq.rbegin(), end = m.seq.rend(); it != end; ++it)
{
input_unreadch(*it);
input_common_next_ch(*it);
}
input_unreadch(R_NULL);
input_common_next_ch(R_NULL);
return; /* skip the input_set_bind_mode */
}
}
@ -648,10 +648,10 @@ static bool input_mapping_is_match(const input_mapping_t &m)
/*
Return the read characters
*/
input_unreadch(c);
input_common_next_ch(c);
for (k=j-1; k>=0; k--)
{
input_unreadch(m.seq[k]);
input_common_next_ch(m.seq[k]);
}
}
@ -659,9 +659,9 @@ static bool input_mapping_is_match(const input_mapping_t &m)
}
void input_unreadch(wint_t ch)
void input_queue_ch(wint_t ch)
{
input_common_unreadch(ch);
input_common_queue_ch(ch);
}
static void input_mapping_execute_matching_or_generic(bool allow_commands)
@ -679,7 +679,7 @@ static void input_mapping_execute_matching_or_generic(bool allow_commands)
if (m.mode != bind_mode)
{
//debug(0, L"skipping mapping because mode %ls != %ls\n", m.mode.c_str(), input_get_bind_mode());
//debug(0, L"skipping mapping because mode %ls != %ls\n", m.mode.c_str(), input_get_bind_mode().c_str());
continue;
}
@ -703,7 +703,7 @@ static void input_mapping_execute_matching_or_generic(bool allow_commands)
//debug(0, L"no generic found, ignoring...");
wchar_t c = input_common_readch(0);
if (c == R_EOF)
input_common_unreadch(c);
input_common_next_ch(c);
}
}
@ -745,7 +745,7 @@ wint_t input_readch(bool allow_commands)
else
{
while ((c = input_common_readch(0)) && c >= R_MIN && c <= R_MAX);
input_unreadch(c);
input_common_next_ch(c);
return input_readch();
}
}
@ -757,7 +757,7 @@ wint_t input_readch(bool allow_commands)
}
else
{
input_unreadch(c);
input_common_next_ch(c);
input_mapping_execute_matching_or_generic(allow_commands);
// regarding allow_commands, we're in a loop, but if a fish command
// is executed, R_NULL is unread, so the next pass through the loop

View file

@ -112,11 +112,11 @@ void input_destroy();
wint_t input_readch(bool allow_commands = true);
/**
Push a character or a readline function onto the stack of unread
Enqueue a character or a readline function to the queue of unread
characters that input_readch will return before actually reading from fd
0.
*/
void input_unreadch(wint_t ch);
void input_queue_ch(wint_t ch);
/**

View file

@ -38,7 +38,7 @@ Implementation file for the low level input library
#define WAIT_ON_ESCAPE 10
/** Characters that have been read and returned by the sequence matching code */
static std::stack<wint_t, std::vector<wint_t> > lookahead_list;
static std::deque<wint_t> lookahead_list;
/* Queue of pairs of (function pointer, argument) to be invoked. Expected to be mostly empty. */
typedef std::pair<void (*)(void *), void *> callback_info_t;
@ -53,19 +53,24 @@ static bool has_lookahead(void)
static wint_t lookahead_pop(void)
{
wint_t result = lookahead_list.top();
lookahead_list.pop();
wint_t result = lookahead_list.front();
lookahead_list.pop_front();
return result;
}
static void lookahead_push(wint_t c)
static void lookahead_push_back(wint_t c)
{
lookahead_list.push(c);
lookahead_list.push_back(c);
}
static wint_t lookahead_top(void)
static void lookahead_push_front(wint_t c)
{
return lookahead_list.top();
lookahead_list.push_front(c);
}
static wint_t lookahead_front(void)
{
return lookahead_list.front();
}
/** Callback function for handling interrupts on reading */
@ -278,7 +283,7 @@ wchar_t input_common_readch(int timed)
{
if (!timed)
{
while (has_lookahead() && lookahead_top() == WEOF)
while (has_lookahead() && lookahead_front() == WEOF)
lookahead_pop();
if (! has_lookahead())
return input_common_readch(0);
@ -289,9 +294,14 @@ wchar_t input_common_readch(int timed)
}
void input_common_unreadch(wint_t ch)
void input_common_queue_ch(wint_t ch)
{
lookahead_push(ch);
lookahead_push_back(ch);
}
void input_common_next_ch(wint_t ch)
{
lookahead_push_front(ch);
}
void input_common_add_callback(void (*callback)(void *), void *arg)

View file

@ -47,11 +47,18 @@ void input_common_destroy();
wchar_t input_common_readch(int timed);
/**
Push a character or a readline function onto the stack of unread
Enqueue a character or a readline function to the queue of unread
characters that input_readch will return before actually reading from fd
0.
*/
void input_common_unreadch(wint_t ch);
void input_common_queue_ch(wint_t ch);
/**
Add a character or a readline function to the front of the queue of unread
characters. This will be the first character returned by input_readch
(unless this function is called more than once).
*/
void input_common_next_ch(wint_t ch);
/** Adds a callback to be invoked at the next turn of the "event loop." The callback function will be invoked and passed arg. */
void input_common_add_callback(void (*callback)(void *), void *arg);