Made tests compile again

Renamed autosuggest_handle_special to autosuggest_special_validate_from_history
Began work to factor autosuggest_special_validate_from_history together with autosuggest_suggest_special
This commit is contained in:
ridiculousfish 2012-05-07 12:55:13 -07:00
parent 99b51ce6ea
commit 1a264ab7c2
6 changed files with 169 additions and 162 deletions

View File

@ -397,7 +397,7 @@ static void test_parser()
{ {
say( L"Testing parser" ); say( L"Testing parser" );
parser_t parser(PARSER_TYPE_GENERAL); parser_t parser(PARSER_TYPE_GENERAL, true);
say( L"Testing null input to parser" ); say( L"Testing null input to parser" );
if( !parser.test( 0, 0, 0, 0 ) ) if( !parser.test( 0, 0, 0, 0 ) )
@ -582,7 +582,7 @@ static void test_path()
/** Test the 'test' builtin */ /** Test the 'test' builtin */
int builtin_test( parser_t &parser, wchar_t **argv ); int builtin_test( parser_t &parser, wchar_t **argv );
static bool run_test_test(int expected, wcstring_list_t &lst) { static bool run_test_test(int expected, wcstring_list_t &lst) {
parser_t parser(PARSER_TYPE_GENERAL); parser_t parser(PARSER_TYPE_GENERAL, true);
size_t i, count = lst.size(); size_t i, count = lst.size();
wchar_t **argv = new wchar_t *[count+2]; wchar_t **argv = new wchar_t *[count+2];
argv[0] = (wchar_t *)L"test"; argv[0] = (wchar_t *)L"test";
@ -678,7 +678,7 @@ static void test_colors()
/* Testing autosuggestion */ /* Testing autosuggestion */
static void test_autosuggest() { static void test_autosuggest() {
bool autosuggest_handle_special(const wcstring &str, const wcstring &working_directory, bool *outSuggestionOK); bool autosuggest_special_validate_from_history(const wcstring &str, const wcstring &working_directory, bool *outSuggestionOK);
} }

View File

@ -231,10 +231,11 @@ rgb_color_t highlight_get_color( int highlight, bool is_background )
/** /**
Highligt operators (such as $, ~, %, as well as escaped characters. Highlight operators (such as $, ~, %, as well as escaped characters.
*/ */
static void highlight_param( const wcstring &buffstr, std::vector<int> &colors, int pos, wcstring_list_t *error ) static void highlight_param( const wcstring &buffstr, std::vector<int> &colors, int pos, wcstring_list_t *error )
{ {
return;
const wchar_t * const buff = buffstr.c_str(); const wchar_t * const buff = buffstr.c_str();
enum {e_unquoted, e_single_quoted, e_double_quoted} mode = e_unquoted; enum {e_unquoted, e_single_quoted, e_double_quoted} mode = e_unquoted;
size_t in_pos, len = buffstr.size(); size_t in_pos, len = buffstr.size();
@ -533,6 +534,125 @@ static int has_expand_reserved( const wchar_t *str )
return 0; return 0;
} }
/* A class representing the result of parsing a command line, containing both the last command and its arguments. This is used by autosuggestions */
class autosuggest_parsed_command_t {
public:
/* The command, like "cd" */
wcstring command;
/* Arguments to the command */
wcstring_list_t arguments;
autosuggest_parsed_command_t(const wcstring &str) {
if (str.empty())
return;
wcstring cmd;
wcstring_list_t args;
bool had_cmd = false, recognized_cmd = false;
tokenizer tok;
for (tok_init( &tok, str.c_str(), TOK_SQUASH_ERRORS); tok_has_next(&tok); tok_next(&tok))
{
int last_type = tok_last_type(&tok);
switch( last_type )
{
case TOK_STRING:
{
if( had_cmd )
{
/* Parameter to the command */
args.push_back(tok_last(&tok));
}
else
{
/* Command. First check that the command actually exists. */
wcstring local_cmd = tok_last( &tok );
bool expanded = expand_one(cmd, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_VARIABLES);
if (! expanded || has_expand_reserved(cmd.c_str()))
{
/* We can't expand this cmd, ignore it */
}
else
{
bool is_subcommand = false;
int mark = tok_get_pos( &tok );
if (parser_keywords_is_subcommand(cmd))
{
int sw;
tok_next( &tok );
sw = parser_keywords_is_switch( tok_last( &tok ) );
if( !parser_keywords_is_block( cmd ) &&
sw == ARG_SWITCH )
{
/* It's an argument to the subcommand itself */
}
else
{
if( sw == ARG_SKIP )
mark = tok_get_pos( &tok );
is_subcommand = true;
}
tok_set_pos( &tok, mark );
}
if (!is_subcommand)
{
/* It's really a command */
had_cmd = true;
cmd = local_cmd;
}
}
}
break;
}
case TOK_REDIRECT_NOCLOB:
case TOK_REDIRECT_OUT:
case TOK_REDIRECT_IN:
case TOK_REDIRECT_APPEND:
case TOK_REDIRECT_FD:
{
if( !had_cmd )
{
break;
}
tok_next( &tok );
break;
}
case TOK_PIPE:
case TOK_BACKGROUND:
case TOK_END:
{
had_cmd = false;
cmd.empty();
args.empty();
break;
}
case TOK_COMMENT:
case TOK_ERROR:
default:
{
break;
}
}
}
tok_destroy( &tok );
/* Remember our command if we have one */
if (had_cmd) {
this->command.swap(cmd);
this->arguments.swap(args);
}
}
};
/* Attempts to suggest a completion for a command we handle specially, like 'cd'. Returns true if we recognized the command (even if we couldn't think of a suggestion for it) */ /* Attempts to suggest a completion for a command we handle specially, like 'cd'. Returns true if we recognized the command (even if we couldn't think of a suggestion for it) */
bool autosuggest_suggest_special(const wcstring &str, const wcstring &working_directory, wcstring &outString) { bool autosuggest_suggest_special(const wcstring &str, const wcstring &working_directory, wcstring &outString) {
if (str.empty()) if (str.empty())
@ -706,157 +826,40 @@ bool autosuggest_suggest_special(const wcstring &str, const wcstring &working_di
return recognized_cmd; return recognized_cmd;
} }
bool autosuggest_handle_special(const wcstring &str, const wcstring &working_directory, bool *outSuggestionOK) { bool autosuggest_special_validate_from_history(const wcstring &str, const wcstring &working_directory, bool *outSuggestionOK) {
ASSERT_IS_BACKGROUND_THREAD(); ASSERT_IS_BACKGROUND_THREAD();
assert(outSuggestionOK != NULL); assert(outSuggestionOK != NULL);
if (str.empty()) bool handled = false, suggestionOK = false;
return false;
wcstring cmd; /* Parse the string */
bool had_cmd = false; autosuggest_parsed_command_t parsed(str);
bool handled = false; if (parsed.command == L"cd" && ! parsed.arguments.empty()) {
bool suggestionOK = true; /* We can possibly handle this specially */
wcstring dir = parsed.arguments.back();
tokenizer tok; if (expand_one(dir, EXPAND_SKIP_CMDSUBST))
for( tok_init( &tok, str.c_str(), TOK_SQUASH_ERRORS ); {
tok_has_next( &tok ); handled = true;
tok_next( &tok ) ) bool is_help = string_prefixes_string(dir, L"--help") || string_prefixes_string(dir, L"-h");
{ if (is_help) {
int last_type = tok_last_type( &tok ); suggestionOK = false;
} else {
switch( last_type ) wchar_t *path = path_allocate_cdpath(dir.c_str(), working_directory.c_str());
{ if (path == NULL) {
case TOK_STRING: suggestionOK = false;
{ } else if (paths_are_same_file(working_directory, path)) {
if( had_cmd ) /* Don't suggest the working directory as the path! */
{ suggestionOK = false;
if( cmd == L"cd" ) } else {
{ suggestionOK = true;
wcstring dir = tok_last( &tok ); }
if (expand_one(dir, EXPAND_SKIP_CMDSUBST)) free(path);
{ }
/* We can specially handle the cd command */ }
handled = true; } else {
bool is_help = string_prefixes_string(dir, L"--help") || string_prefixes_string(dir, L"-h"); /* Either an error or some other command, so we don't handle it specially */
if (is_help) {
suggestionOK = false;
} else {
wchar_t *path = path_allocate_cdpath(dir.c_str(), working_directory.c_str());
if (path == NULL) {
suggestionOK = false;
} else if (paths_are_same_file(working_directory, path)) {
/* Don't suggest the working directory as the path! */
suggestionOK = false;
} else {
suggestionOK = true;
}
free(path);
}
}
}
}
else
{
/*
Command. First check that the command actually exists.
*/
cmd = tok_last( &tok );
bool expanded = expand_one(cmd, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_VARIABLES);
if (! expanded || has_expand_reserved(cmd.c_str()))
{
}
else
{
int is_subcommand = 0;
int mark = tok_get_pos( &tok );
if( parser_keywords_is_subcommand( cmd ) )
{
int sw;
if( cmd == L"builtin")
{
}
else if( cmd == L"command")
{
}
tok_next( &tok );
sw = parser_keywords_is_switch( tok_last( &tok ) );
if( !parser_keywords_is_block( cmd ) &&
sw == ARG_SWITCH )
{
}
else
{
if( sw == ARG_SKIP )
{
mark = tok_get_pos( &tok );
}
is_subcommand = 1;
}
tok_set_pos( &tok, mark );
}
if( !is_subcommand )
{
had_cmd = true;
}
}
}
break;
}
case TOK_REDIRECT_NOCLOB:
case TOK_REDIRECT_OUT:
case TOK_REDIRECT_IN:
case TOK_REDIRECT_APPEND:
case TOK_REDIRECT_FD:
{
if( !had_cmd )
{
break;
}
tok_next( &tok );
break;
}
case TOK_PIPE:
case TOK_BACKGROUND:
{
had_cmd = false;
break;
}
case TOK_END:
{
had_cmd = false;
break;
}
case TOK_COMMENT:
{
break;
}
case TOK_ERROR:
default:
{
break;
}
}
} }
tok_destroy( &tok );
*outSuggestionOK = suggestionOK; *outSuggestionOK = suggestionOK;
return handled; return handled;
} }
@ -924,7 +927,8 @@ static void tokenize( const wchar_t * const buff, std::vector<int> &color, const
{ {
color.at(tok_get_pos( &tok )) = HIGHLIGHT_PARAM; color.at(tok_get_pos( &tok )) = HIGHLIGHT_PARAM;
} }
#if 0
if( cmd == L"cd" ) if( cmd == L"cd" )
{ {
wcstring dir = tok_last( &tok ); wcstring dir = tok_last( &tok );
@ -937,6 +941,7 @@ static void tokenize( const wchar_t * const buff, std::vector<int> &color, const
} }
} }
} }
#endif
/* Highlight the parameter. highlight_param wants to write one more color than we have characters (hysterical raisins) so allocate one more in the vector. But don't copy it back. */ /* Highlight the parameter. highlight_param wants to write one more color than we have characters (hysterical raisins) so allocate one more in the vector. But don't copy it back. */
const wcstring param_str = param; const wcstring param_str = param;
@ -1032,10 +1037,10 @@ static void tokenize( const wchar_t * const buff, std::vector<int> &color, const
any files for that any files for that
*/ */
if( use_builtin ) if( use_builtin )
is_cmd |= builtin_exists( cmd ); is_cmd = is_cmd || builtin_exists( cmd );
if( use_function ) if( use_function )
is_cmd |= function_exists_no_autoload( cmd, vars ); is_cmd = is_cmd || function_exists_no_autoload( cmd, vars );
/* /*
Moving on to expensive tests Moving on to expensive tests
@ -1047,7 +1052,7 @@ static void tokenize( const wchar_t * const buff, std::vector<int> &color, const
if( use_command ) if( use_command )
{ {
wcstring tmp; wcstring tmp;
is_cmd |= !!path_get_path_string( cmd, tmp, vars ); is_cmd = is_cmd || path_get_path_string( cmd, tmp, vars );
} }
if( is_cmd ) if( is_cmd )

View File

@ -106,7 +106,7 @@ void highlight_universal( const wcstring &buffstr, std::vector<int> &color, int
*/ */
rgb_color_t highlight_get_color( int highlight, bool is_background ); rgb_color_t highlight_get_color( int highlight, bool is_background );
bool autosuggest_handle_special(const wcstring &str, const wcstring &working_directory, bool *outSuggestionOK); bool autosuggest_special_validate_from_history(const wcstring &str, const wcstring &working_directory, bool *outSuggestionOK);
bool autosuggest_suggest_special(const wcstring &str, const wcstring &working_directory, wcstring &outString); bool autosuggest_suggest_special(const wcstring &str, const wcstring &working_directory, wcstring &outString);

View File

@ -16,10 +16,13 @@ Functions having to do with parser keywords, like testing if a function is a blo
bool parser_keywords_is_switch( const wcstring &cmd ) bool parser_keywords_is_switch( const wcstring &cmd )
{ {
if( cmd == L"--" ) if (cmd == L"--") {
return ARG_SKIP; return ARG_SKIP;
else } else if (! cmd.empty() && cmd.at(0) == L'-') {
return ! cmd.empty() && cmd.at(0) == L'-'; return ARG_SWITCH;
} else {
return ARG_NON_SWITCH;
}
} }
bool parser_keywords_skip_arguments( const wcstring &cmd ) bool parser_keywords_skip_arguments( const wcstring &cmd )

View File

@ -7,15 +7,14 @@ Functions having to do with parser keywords, like testing if a function is a blo
#define FISH_PARSER_KEYWORD_H #define FISH_PARSER_KEYWORD_H
/** /**
Return valuse for parser_keywords_is_switch() Return values for parser_keywords_is_switch()
*/ */
enum enum
{ {
ARG_NON_SWITCH, ARG_NON_SWITCH,
ARG_SWITCH, ARG_SWITCH,
ARG_SKIP ARG_SKIP
} };
;

View File

@ -1269,7 +1269,7 @@ struct autosuggestion_context_t {
continue; continue;
bool item_ok = false; bool item_ok = false;
if (autosuggest_handle_special(item.str(), working_directory, &item_ok)) { if (autosuggest_special_validate_from_history(item.str(), working_directory, &item_ok)) {
/* The command autosuggestion was handled specially, so we're done */ /* The command autosuggestion was handled specially, so we're done */
} else { } else {
/* See if the item has any required paths */ /* See if the item has any required paths */