forward-word should accept a word of an autosuggestion

https://github.com/fish-shell/fish-shell/issues/435
This commit is contained in:
ridiculousfish 2012-12-10 16:23:08 -08:00
parent 983bc5cecc
commit eec6db0a23
6 changed files with 136 additions and 105 deletions

View file

@ -34,7 +34,8 @@ struct autoload_function_t : public lru_node_t
bool is_internalized; /** Whether this function came from a builtin "internalized" script */
};
struct builtin_script_t {
struct builtin_script_t
{
const wchar_t *name;
const char *def;
};

View file

@ -461,7 +461,7 @@ static void builtin_bind_function_names()
/**
Add specified key binding.
*/
static int builtin_bind_add(wchar_t *seq, wchar_t *cmd, int terminfo)
static int builtin_bind_add(const wchar_t *seq, const wchar_t *cmd, int terminfo)
{
if (terminfo)

View file

@ -1283,13 +1283,29 @@ static void update_autosuggestion(void)
#endif
}
static void accept_autosuggestion(void)
/* Accept any autosuggestion by replacing the command line with it. If full is true, take the whole thing; if it's false, then take only the first "word" */
static void accept_autosuggestion(bool full)
{
/* Accept any autosuggestion by replacing the command line with it. */
if (! data->autosuggestion.empty())
{
/* Accept the autosuggestion */
if (full)
{
/* Just take the whole thing */
data->command_line = data->autosuggestion;
}
else
{
/* Accept characters up to a word separator */
move_word_state_machine_t state;
for (size_t idx = data->command_line.size(); idx < data->autosuggestion.size(); idx++)
{
wchar_t wc = data->autosuggestion.at(idx);
if (! state.consume_char(wc))
break;
data->command_line.push_back(wc);
}
}
data->buff_pos = data->command_line.size();
data->command_line_changed();
reader_super_highlight_me_plenty(data->buff_pos);
@ -2026,98 +2042,6 @@ static void handle_token_history(int forward, int reset)
}
}
/* Our state machine that implements "one word" movement or erasure. */
class move_word_state_machine_t
{
enum
{
s_whitespace,
s_separator,
s_slash,
s_nonseparators_except_slash,
s_end
} state;
public:
move_word_state_machine_t() : state(s_whitespace)
{
}
bool consume_char(wchar_t c)
{
//printf("state %d, consume '%lc'\n", state, c);
bool consumed = false;
/* Always treat separators as first. All this does is ensure that we treat ^ as a string character instead of as stderr redirection, which I hypothesize is usually what is desired. */
bool was_first = true;
while (state != s_end && ! consumed)
{
switch (state)
{
case s_whitespace:
if (iswspace(c))
{
/* Consumed whitespace */
consumed = true;
}
else if (tok_is_string_character(c, was_first))
{
/* String path */
state = s_slash;
}
else
{
/* Separator path */
state = s_separator;
}
break;
case s_separator:
if (! iswspace(c) && ! tok_is_string_character(c, was_first))
{
/* Consumed separator */
consumed = true;
}
else
{
state = s_end;
}
break;
case s_slash:
if (c == L'/')
{
/* Consumed slash */
consumed = true;
}
else
{
state = s_nonseparators_except_slash;
}
break;
case s_nonseparators_except_slash:
if (c != L'/' && tok_is_string_character(c, was_first))
{
/* Consumed string character except slash */
consumed = true;
}
else
{
state = s_end;
}
break;
/* We won't get here, but keep the compiler happy */
case s_end:
default:
break;
}
}
return consumed;
}
};
/**
Move buffer position one word or erase one word. This function
updates both the internal buffer and the screen. It is used by
@ -3338,7 +3262,7 @@ const wchar_t *reader_readline()
}
else
{
accept_autosuggestion();
accept_autosuggestion(true);
}
break;
}
@ -3366,8 +3290,15 @@ const wchar_t *reader_readline()
/* move one word right*/
case R_FORWARD_WORD:
{
if (data->buff_pos < data->command_length())
{
move_word(MOVE_DIR_RIGHT, false /* do not erase */, false);
}
else
{
accept_autosuggestion(false /* accept only one word */);
}
break;
}
@ -3440,7 +3371,7 @@ const wchar_t *reader_readline()
case R_ACCEPT_AUTOSUGGESTION:
{
accept_autosuggestion();
accept_autosuggestion(true);
break;
}

View file

@ -568,7 +568,8 @@ static void s_move(screen_t *s, data_buffer_t *b, int new_x, int new_y)
return;
// If we are at the end of our window, then either the cursor stuck to the edge or it didn't. We don't know! We can fix it up though.
if (s->actual.cursor.x == common_get_width()) {
if (s->actual.cursor.x == common_get_width())
{
// Either issue a cr to go back to the beginning of this line, or a nl to go to the beginning of the next one, depending on what we think is more efficient
if (new_y <= s->actual.cursor.y)
{
@ -887,7 +888,8 @@ static void s_update(screen_t *scr, const wchar_t *left_prompt, const wchar_t *r
}
/* If we're soft wrapped, and if we're going to change the first character of the next line, don't skip over the last two characters so that we maintain soft-wrapping */
if (o_line.is_soft_wrapped && i + 1 < scr->desired.line_count()) {
if (o_line.is_soft_wrapped && i + 1 < scr->desired.line_count())
{
bool first_character_of_next_line_will_change = true;
if (i + 1 < scr->actual.line_count())
{

View file

@ -669,6 +669,85 @@ void tok_set_pos(tokenizer_t *tok, int pos)
}
move_word_state_machine_t::move_word_state_machine_t() : state(s_whitespace)
{
}
bool move_word_state_machine_t::consume_char(wchar_t c)
{
//printf("state %d, consume '%lc'\n", state, c);
bool consumed = false;
/* Always treat separators as first. All this does is ensure that we treat ^ as a string character instead of as stderr redirection, which I hypothesize is usually what is desired. */
bool was_first = true;
while (state != s_end && ! consumed)
{
switch (state)
{
case s_whitespace:
if (iswspace(c))
{
/* Consumed whitespace */
consumed = true;
}
else if (tok_is_string_character(c, was_first))
{
/* String path */
state = s_slash;
}
else
{
/* Separator path */
state = s_separator;
}
break;
case s_separator:
if (! iswspace(c) && ! tok_is_string_character(c, was_first))
{
/* Consumed separator */
consumed = true;
}
else
{
state = s_end;
}
break;
case s_slash:
if (c == L'/')
{
/* Consumed slash */
consumed = true;
}
else
{
state = s_nonseparators_except_slash;
}
break;
case s_nonseparators_except_slash:
if (c != L'/' && tok_is_string_character(c, was_first))
{
/* Consumed string character except slash */
consumed = true;
}
else
{
state = s_end;
}
break;
/* We won't get here, but keep the compiler happy */
case s_end:
default:
break;
}
}
return consumed;
}
#ifdef TOKENIZER_TEST
/**

View file

@ -184,4 +184,22 @@ const wchar_t *tok_get_desc(int type);
int tok_get_error(tokenizer_t *tok);
/* Our state machine that implements "one word" movement or erasure. */
class move_word_state_machine_t
{
enum
{
s_whitespace,
s_separator,
s_slash,
s_nonseparators_except_slash,
s_end
} state;
public:
move_word_state_machine_t();
bool consume_char(wchar_t c);
};
#endif