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,9 +34,10 @@ struct autoload_function_t : public lru_node_t
bool is_internalized; /** Whether this function came from a builtin "internalized" script */ 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; const wchar_t *name;
const char *def;
}; };
struct builtin_script_t; struct builtin_script_t;

View file

@ -461,7 +461,7 @@ static void builtin_bind_function_names()
/** /**
Add specified key binding. 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) if (terminfo)

View file

@ -1283,13 +1283,29 @@ static void update_autosuggestion(void)
#endif #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()) if (! data->autosuggestion.empty())
{ {
/* Accept the autosuggestion */ /* Accept the autosuggestion */
data->command_line = data->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->buff_pos = data->command_line.size();
data->command_line_changed(); data->command_line_changed();
reader_super_highlight_me_plenty(data->buff_pos); 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 Move buffer position one word or erase one word. This function
updates both the internal buffer and the screen. It is used by updates both the internal buffer and the screen. It is used by
@ -3338,7 +3262,7 @@ const wchar_t *reader_readline()
} }
else else
{ {
accept_autosuggestion(); accept_autosuggestion(true);
} }
break; break;
} }
@ -3367,7 +3291,14 @@ const wchar_t *reader_readline()
/* move one word right*/ /* move one word right*/
case R_FORWARD_WORD: case R_FORWARD_WORD:
{ {
move_word(MOVE_DIR_RIGHT, false /* do not erase */, false); 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; break;
} }
@ -3440,7 +3371,7 @@ const wchar_t *reader_readline()
case R_ACCEPT_AUTOSUGGESTION: case R_ACCEPT_AUTOSUGGESTION:
{ {
accept_autosuggestion(); accept_autosuggestion(true);
break; break;
} }

View file

@ -566,9 +566,10 @@ static void s_move(screen_t *s, data_buffer_t *b, int new_x, int new_y)
{ {
if (s->actual.cursor.x == new_x && s->actual.cursor.y == new_y) if (s->actual.cursor.x == new_x && s->actual.cursor.y == new_y)
return; 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 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 // 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) 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 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; bool first_character_of_next_line_will_change = true;
if (i + 1 < scr->actual.line_count()) 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 #ifdef TOKENIZER_TEST
/** /**

View file

@ -184,4 +184,22 @@ const wchar_t *tok_get_desc(int type);
int tok_get_error(tokenizer_t *tok); 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 #endif