Skip to content

Commit

Permalink
forward-word should accept a word of an autosuggestion
Browse files Browse the repository at this point in the history
  • Loading branch information
ridiculousfish committed Dec 11, 2012
1 parent 983bc5c commit eec6db0
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 105 deletions.
7 changes: 4 additions & 3 deletions autoload.h
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion builtin.cpp
Expand Up @@ -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)
Expand Down
127 changes: 29 additions & 98 deletions reader.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -3338,7 +3262,7 @@ const wchar_t *reader_readline()
} }
else else
{ {
accept_autosuggestion(); accept_autosuggestion(true);
} }
break; break;
} }
Expand Down Expand Up @@ -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;
} }


Expand Down Expand Up @@ -3440,7 +3371,7 @@ const wchar_t *reader_readline()


case R_ACCEPT_AUTOSUGGESTION: case R_ACCEPT_AUTOSUGGESTION:
{ {
accept_autosuggestion(); accept_autosuggestion(true);
break; break;
} }


Expand Down
8 changes: 5 additions & 3 deletions screen.cpp
Expand Up @@ -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)
{ {
Expand Down Expand Up @@ -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())
{ {
Expand Down
79 changes: 79 additions & 0 deletions tokenizer.cpp
Expand Up @@ -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


/** /**
Expand Down
18 changes: 18 additions & 0 deletions tokenizer.h
Expand Up @@ -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

0 comments on commit eec6db0

Please sign in to comment.