More work towards autosuggesting completions

This commit is contained in:
ridiculousfish 2012-02-25 18:54:49 -08:00
parent 5ea78f55f2
commit 38e40862fe
14 changed files with 184 additions and 140 deletions

View file

@ -261,7 +261,7 @@ static void builtin_print_help( parser_t &parser, const wchar_t *cmd, wcstring &
screen_height = common_get_height(); screen_height = common_get_height();
lines = count_char( str, L'\n' ); lines = count_char( str, L'\n' );
if( !is_interactive || (lines > 2*screen_height/3) ) if( !get_is_interactive() || (lines > 2*screen_height/3) )
{ {
wchar_t *pos; wchar_t *pos;
int cut=0; int cut=0;
@ -2569,7 +2569,7 @@ static int builtin_cd( parser_t &parser, wchar_t **argv )
} }
if( !is_interactive ) if( !get_is_interactive() )
{ {
stderr_buffer.append(parser.current_line()); stderr_buffer.append(parser.current_line());
} }
@ -2599,7 +2599,7 @@ static int builtin_cd( parser_t &parser, wchar_t **argv )
dir ); dir );
} }
if( !is_interactive ) if( !get_is_interactive() )
{ {
stderr_buffer.append(parser.current_line()); stderr_buffer.append(parser.current_line());
} }

View file

@ -2062,6 +2062,7 @@ void assert_is_main_thread(const char *who)
if (! is_main_thread()) { if (! is_main_thread()) {
fprintf(stderr, "Warning: %s called off of main thread. Break on debug_thread_error to debug.\n", who); fprintf(stderr, "Warning: %s called off of main thread. Break on debug_thread_error to debug.\n", who);
debug_thread_error(); debug_thread_error();
sleep(1000);
} }
} }

View file

@ -143,7 +143,7 @@ typedef struct complete_entry_opt
/** True if old style long options are used */ /** True if old style long options are used */
int old_mode; int old_mode;
/** Completion flags */ /** Completion flags */
int flags; complete_flags_t flags;
const wchar_t *localized_desc() const const wchar_t *localized_desc() const
{ {
@ -198,6 +198,9 @@ class completer_t {
{ {
} }
bool empty() const { return completions.empty(); }
const std::vector<completion_t> &get_completions(void) { return completions; }
bool try_complete_variable( const wcstring &str ); bool try_complete_variable( const wcstring &str );
bool try_complete_user( const wcstring &str ); bool try_complete_user( const wcstring &str );
@ -206,15 +209,14 @@ class completer_t {
const wcstring &str, const wcstring &str,
bool use_switches); bool use_switches);
void complete_param_expand( const wcstring &str, bool do_file); void complete_param_expand(const wcstring &str, bool do_file);
void complete_cmd( const wcstring &str, void complete_cmd( const wcstring &str,
bool use_function, bool use_function,
bool use_builtin, bool use_builtin,
bool use_command); bool use_command);
bool empty() const { return completions.empty(); } bool complete_variable(const wcstring &str, int start_offset);
const std::vector<completion_t> &get_completions(void) { return completions; }
}; };
@ -244,7 +246,7 @@ void completion_autoload_t::command_removed(const wcstring &cmd) {
Create a new completion entry Create a new completion entry
*/ */
void completion_allocate(std::vector<completion_t> &completions, const wcstring &comp, const wcstring &desc, int flags) void completion_allocate(std::vector<completion_t> &completions, const wcstring &comp, const wcstring &desc, complete_flags_t flags)
{ {
completions.push_back(completion_t(comp, desc, flags)); completions.push_back(completion_t(comp, desc, flags));
} }
@ -362,7 +364,7 @@ void complete_add( const wchar_t *cmd,
const wchar_t *condition, const wchar_t *condition,
const wchar_t *comp, const wchar_t *comp,
const wchar_t *desc, const wchar_t *desc,
int flags ) complete_flags_t flags )
{ {
CHECK( cmd, ); CHECK( cmd, );
@ -757,7 +759,7 @@ static void complete_strings( std::vector<completion_t> &comp_out,
const wchar_t *desc, const wchar_t *desc,
const wchar_t *(*desc_func)(const wcstring &), const wchar_t *(*desc_func)(const wcstring &),
std::vector<completion_t> &possible_comp, std::vector<completion_t> &possible_comp,
int flags ) complete_flags_t flags )
{ {
wcstring tmp = wc_escaped; wcstring tmp = wc_escaped;
if (! expand_one(tmp, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_WILDCARDS)) if (! expand_one(tmp, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_WILDCARDS))
@ -1090,21 +1092,24 @@ static void complete_from_args( const wcstring &str,
const wcstring &args, const wcstring &args,
const wcstring &desc, const wcstring &desc,
std::vector<completion_t> &comp_out, std::vector<completion_t> &comp_out,
int flags ) complete_type_t type,
complete_flags_t flags )
{ {
/* If type is COMPLETE_AUTOSUGGEST, it means we're on a background thread, so don't call proc_push_interactive */
std::vector<completion_t> possible_comp; std::vector<completion_t> possible_comp;
parser_t parser(PARSER_TYPE_COMPLETIONS_ONLY); parser_t parser(PARSER_TYPE_COMPLETIONS_ONLY);
proc_push_interactive(0);
if (type != COMPLETE_AUTOSUGGEST)
proc_push_interactive(0);
parser.eval_args( args.c_str(), possible_comp ); parser.eval_args( args.c_str(), possible_comp );
proc_pop_interactive(); if (type != COMPLETE_AUTOSUGGEST)
proc_pop_interactive();
complete_strings( comp_out, str.c_str(), desc.c_str(), 0, possible_comp, flags ); complete_strings( comp_out, str.c_str(), desc.c_str(), 0, possible_comp, flags );
// al_foreach( &possible_comp, &free );
// al_destroy( &possible_comp );
} }
/** /**
@ -1249,7 +1254,7 @@ static int complete_param( const wchar_t *cmd_orig,
{ {
use_common &= ((o->result_mode & NO_COMMON )==0); use_common &= ((o->result_mode & NO_COMMON )==0);
use_files &= ((o->result_mode & NO_FILES )==0); use_files &= ((o->result_mode & NO_FILES )==0);
complete_from_args( arg, o->comp, o->localized_desc(), comp_out, o->flags ); complete_from_args( arg, o->comp, o->localized_desc(), comp_out, type, o->flags );
} }
} }
@ -1273,7 +1278,7 @@ static int complete_param( const wchar_t *cmd_orig,
old_style_match = 1; old_style_match = 1;
use_common &= ((o->result_mode & NO_COMMON )==0); use_common &= ((o->result_mode & NO_COMMON )==0);
use_files &= ((o->result_mode & NO_FILES )==0); use_files &= ((o->result_mode & NO_FILES )==0);
complete_from_args( str, o->comp, o->localized_desc(), comp_out, o->flags ); complete_from_args( str, o->comp, o->localized_desc(), comp_out, type, o->flags );
} }
} }
} }
@ -1300,7 +1305,7 @@ static int complete_param( const wchar_t *cmd_orig,
{ {
use_common &= ((o->result_mode & NO_COMMON )==0); use_common &= ((o->result_mode & NO_COMMON )==0);
use_files &= ((o->result_mode & NO_FILES )==0); use_files &= ((o->result_mode & NO_FILES )==0);
complete_from_args( str, o->comp.c_str(), o->localized_desc(), comp_out, o->flags ); complete_from_args( str, o->comp.c_str(), o->localized_desc(), comp_out, type, o->flags );
} }
} }
@ -1326,7 +1331,7 @@ static int complete_param( const wchar_t *cmd_orig,
if( (o->short_opt == L'\0' ) && (o->long_opt[0]==L'\0')) if( (o->short_opt == L'\0' ) && (o->long_opt[0]==L'\0'))
{ {
use_files &= ((o->result_mode & NO_FILES )==0); use_files &= ((o->result_mode & NO_FILES )==0);
complete_from_args( str, o->comp, o->localized_desc(), comp_out, o->flags ); complete_from_args( str, o->comp, o->localized_desc(), comp_out, type, o->flags );
} }
if( wcslen(str) > 0 && use_switches ) if( wcslen(str) > 0 && use_switches )
@ -1370,7 +1375,7 @@ static int complete_param( const wchar_t *cmd_orig,
int req_arg=0; /* Does this switch _require_ an argument */ int req_arg=0; /* Does this switch _require_ an argument */
int offset = 0; int offset = 0;
int flags = 0; complete_flags_t flags = 0;
if( match ) if( match )
@ -1426,7 +1431,6 @@ bool completer_t::complete_param( const wcstring &cmd_orig, const wcstring &popt
static void complete_param_expand( const wchar_t *str, std::vector<completion_t> &comp_out, int do_file, complete_type_t type ) static void complete_param_expand( const wchar_t *str, std::vector<completion_t> &comp_out, int do_file, complete_type_t type )
{ {
const wchar_t *comp_str; const wchar_t *comp_str;
int flags;
if( (wcsncmp( str, L"--", 2 )) == 0 && (comp_str = wcschr(str, L'=' ) ) ) if( (wcsncmp( str, L"--", 2 )) == 0 && (comp_str = wcschr(str, L'=' ) ) )
{ {
@ -1437,7 +1441,7 @@ static void complete_param_expand( const wchar_t *str, std::vector<completion_t>
comp_str = str; comp_str = str;
} }
flags = EXPAND_SKIP_CMDSUBST | ACCEPT_INCOMPLETE; expand_flags_t flags = EXPAND_SKIP_CMDSUBST | ACCEPT_INCOMPLETE;
if (! do_file) if (! do_file)
flags |= EXPAND_SKIP_WILDCARDS; flags |= EXPAND_SKIP_WILDCARDS;
@ -1464,11 +1468,13 @@ void completer_t::complete_param_expand( const wcstring &str, bool do_file)
*/ */
static int complete_variable( const wchar_t *whole_var, static int complete_variable( const wchar_t *whole_var,
int start_offset, int start_offset,
std::vector<completion_t> &comp_list ) std::vector<completion_t> &comp_list,
complete_type_t type)
{ {
const wchar_t *var = &whole_var[start_offset]; const wchar_t *var = &whole_var[start_offset];
int varlen = wcslen( var ); int varlen = wcslen( var );
int res = 0; int res = 0;
bool wants_description = (type != COMPLETE_AUTOSUGGEST);
const wcstring_list_t names = env_get_names(0); const wcstring_list_t names = env_get_names(0);
for( size_t i=0; i<names.size(); i++ ) for( size_t i=0; i<names.size(); i++ )
@ -1489,34 +1495,39 @@ static int complete_variable( const wchar_t *whole_var,
if( match || match_no_case ) if( match || match_no_case )
{ {
const env_var_t value_unescaped = env_get_string( env_name ); wcstring comp;
if( !value_unescaped.missing() ) int flags = 0;
{ int offset = 0;
wcstring comp;
int flags = 0;
int offset = 0;
if( match ) if( match )
{ {
comp.append(env_name.c_str() + varlen); comp.append(env_name.c_str() + varlen);
offset = varlen; offset = varlen;
} }
else else
{ {
comp.append(whole_var, start_offset); comp.append(whole_var, start_offset);
comp.append(env_name); comp.append(env_name);
flags = COMPLETE_NO_CASE | COMPLETE_DONT_ESCAPE; flags = COMPLETE_NO_CASE | COMPLETE_DONT_ESCAPE;
} }
wcstring value = expand_escape_variable( value_unescaped ); wcstring desc;
if (wants_description)
{
env_var_t value_unescaped = env_get_string( env_name );
if (value_unescaped.missing())
continue;
wcstring desc = format_string(COMPLETE_VAR_DESC_VAL, value.c_str()); wcstring value = expand_escape_variable( value_unescaped );
completion_allocate( comp_list, if (type != COMPLETE_AUTOSUGGEST)
comp.c_str(), desc = format_string(COMPLETE_VAR_DESC_VAL, value.c_str());
desc.c_str(), }
flags );
res =1; completion_allocate( comp_list,
} comp.c_str(),
desc.c_str(),
flags );
res =1;
} }
} }
@ -1524,13 +1535,18 @@ static int complete_variable( const wchar_t *whole_var,
return res; return res;
} }
bool completer_t::complete_variable(const wcstring &str, int start_offset)
{
return ::complete_variable(str.c_str(), start_offset, this->completions, this->type);
}
/** /**
Search the specified string for the \$ sign. If found, try to Search the specified string for the \$ sign. If found, try to
complete as an environment variable. complete as an environment variable.
\return 0 if unable to complete, 1 otherwise \return 0 if unable to complete, 1 otherwise
*/ */
static int try_complete_variable( const wchar_t *cmd, std::vector<completion_t> &comp ) static int try_complete_variable( const wchar_t *cmd, std::vector<completion_t> &comp, complete_type_t type )
{ {
int len = wcslen( cmd ); int len = wcslen( cmd );
int i; int i;
@ -1540,7 +1556,7 @@ static int try_complete_variable( const wchar_t *cmd, std::vector<completion_t>
if( cmd[i] == L'$' ) if( cmd[i] == L'$' )
{ {
/* wprintf( L"Var prefix \'%ls\'\n", &cmd[i+1] );*/ /* wprintf( L"Var prefix \'%ls\'\n", &cmd[i+1] );*/
return complete_variable( cmd, i+1, comp ); return complete_variable( cmd, i+1, comp, type);
} }
if( !isalnum(cmd[i]) && cmd[i]!=L'_' ) if( !isalnum(cmd[i]) && cmd[i]!=L'_' )
{ {
@ -1552,7 +1568,7 @@ static int try_complete_variable( const wchar_t *cmd, std::vector<completion_t>
bool completer_t::try_complete_variable( const wcstring &str ) bool completer_t::try_complete_variable( const wcstring &str )
{ {
return ::try_complete_variable(str.c_str(), this->completions) > 0; return ::try_complete_variable(str.c_str(), this->completions, this->type) > 0;
} }
/** /**
@ -1910,7 +1926,7 @@ void complete( const wchar_t *cmd, std::vector<completion_t> &comp, complete_typ
if( !done ) if( !done )
{ {
if( try_complete_variable( tok_begin, comp ) || try_complete_user( tok_begin, comp )) if( try_complete_variable( tok_begin, comp, type ) || try_complete_user( tok_begin, comp ))
{ {
done=1; done=1;
} }

View file

@ -67,39 +67,41 @@
*/ */
#define PROG_COMPLETE_SEP L'\t' #define PROG_COMPLETE_SEP L'\t'
/** enum {
Do not insert space afterwards if this is the only completion. (The /**
default is to try insert a space) Do not insert space afterwards if this is the only completion. (The
*/ default is to try insert a space)
#define COMPLETE_NO_SPACE 1 */
COMPLETE_NO_SPACE = 1 << 0,
/** /**
This compeltion is case insensitive. This compeltion is case insensitive.
Warning: The contents of the completion_t structure is actually Warning: The contents of the completion_t structure is actually
different if this flag is set! Specifically, the completion string different if this flag is set! Specifically, the completion string
contains the _entire_ completion token, not only the current contains the _entire_ completion token, not only the current
*/ */
#define COMPLETE_NO_CASE 2 COMPLETE_NO_CASE = 1 << 1,
/** /**
This compeltion is the whole argument, not just the remainder. This This compeltion is the whole argument, not just the remainder. This
flag must never be set on completions returned from the complete() flag must never be set on completions returned from the complete()
function. It is strictly for internal use in the completion code. function. It is strictly for internal use in the completion code.
*/ */
#define COMPLETE_WHOLE_ARGUMENT 4 COMPLETE_WHOLE_ARGUMENT = 1 << 2,
/** /**
This completion may or may not want a space at the end - guess by This completion may or may not want a space at the end - guess by
checking the last character of the completion. checking the last character of the completion.
*/ */
#define COMPLETE_AUTO_SPACE 8 COMPLETE_AUTO_SPACE = 1 << 3,
/**
This completion should be inserted as-is, without escaping.
*/
#define COMPLETE_DONT_ESCAPE 16
/**
This completion should be inserted as-is, without escaping.
*/
COMPLETE_DONT_ESCAPE = 1 << 4
};
typedef int complete_flags_t;
class completion_t class completion_t

17
env.cpp
View file

@ -97,7 +97,7 @@ struct var_entry_t
/** /**
Struct representing one level in the function variable stack Struct representing one level in the function variable stack
*/ */
typedef struct env_node struct env_node_t
{ {
/** /**
Variable table Variable table
@ -118,12 +118,11 @@ typedef struct env_node
/** /**
Pointer to next level Pointer to next level
*/ */
struct env_node *next; struct env_node_t *next;
env_node() : new_scope(0), exportv(0), next(NULL) { } env_node_t() : new_scope(0), exportv(0), next(NULL) { }
} };
env_node_t;
class variable_entry_t { class variable_entry_t {
bool exportv; /**< Whether the variable should be exported */ bool exportv; /**< Whether the variable should be exported */
@ -337,7 +336,7 @@ static void handle_locale()
dcgettext( "fish", "Changing language to English", LC_MESSAGES ); dcgettext( "fish", "Changing language to English", LC_MESSAGES );
if( is_interactive ) if( get_is_interactive() )
{ {
debug( 0, _(L"Changing language to English") ); debug( 0, _(L"Changing language to English") );
} }
@ -1479,6 +1478,8 @@ static void add_key_to_string_set(const std::map<wcstring, var_entry_t*> &envs,
wcstring_list_t env_get_names( int flags ) wcstring_list_t env_get_names( int flags )
{ {
scoped_lock lock(env_lock);
wcstring_list_t result; wcstring_list_t result;
std::set<wcstring> names; std::set<wcstring> names;
int show_local = flags & ENV_LOCAL; int show_local = flags & ENV_LOCAL;
@ -1489,9 +1490,9 @@ wcstring_list_t env_get_names( int flags )
get_names_show_exported = get_names_show_exported =
flags & ENV_EXPORT|| (!(flags & ENV_UNEXPORT)); (flags & ENV_EXPORT) || !(flags & ENV_UNEXPORT);
get_names_show_unexported = get_names_show_unexported =
flags & ENV_UNEXPORT|| (!(flags & ENV_EXPORT)); (flags & ENV_UNEXPORT) || !(flags & ENV_EXPORT);
if( !show_local && !show_global && !show_universal ) if( !show_local && !show_global && !show_universal )
{ {

4
env.h
View file

@ -93,7 +93,7 @@ int env_set( const wchar_t *key,
valid until the next call to env_get(), env_set(), env_push() or valid until the next call to env_get(), env_set(), env_push() or
env_pop() takes place. env_pop() takes place.
*/ */
const wchar_t *env_get( const wchar_t *key ); //const wchar_t *env_get( const wchar_t *key );
class env_var_t : public wcstring { class env_var_t : public wcstring {
private: private:
@ -153,7 +153,7 @@ void env_pop();
char **env_export_arr( int recalc ); char **env_export_arr( int recalc );
/** /**
Insert all variable names into l. These are not copies of the strings and should not be freed after use. Returns all variable names.
*/ */
wcstring_list_t env_get_names( int flags ); wcstring_list_t env_get_names( int flags );

View file

@ -145,11 +145,11 @@ int expand_is_clean( const wchar_t *in )
/** /**
Return the environment variable value for the string starting at \c in. Return the environment variable value for the string starting at \c in.
*/ */
static const wchar_t* expand_var(const wchar_t *in) static env_var_t expand_var(const wchar_t *in)
{ {
if( !in ) if( !in )
return 0; return env_var_t::missing_var();
return env_get( in ); return env_get_string( in );
} }
/** /**
@ -818,7 +818,6 @@ static int expand_variables_internal( parser_t &parser, wchar_t * const in, std:
int start_pos = i+1; int start_pos = i+1;
int stop_pos; int stop_pos;
int var_len; int var_len;
const wchar_t * var_val;
int is_single = (c==VARIABLE_EXPAND_SINGLE); int is_single = (c==VARIABLE_EXPAND_SINGLE);
int var_name_stop_pos; int var_name_stop_pos;
@ -849,9 +848,9 @@ static int expand_variables_internal( parser_t &parser, wchar_t * const in, std:
} }
var_tmp.append(in + start_pos, var_len); var_tmp.append(in + start_pos, var_len);
var_val = expand_var(var_tmp.c_str() ); env_var_t var_val = expand_var(var_tmp.c_str() );
if( var_val ) if( ! var_val.missing() )
{ {
int all_vars=1; int all_vars=1;
wcstring_list_t var_item_list; wcstring_list_t var_item_list;
@ -873,7 +872,7 @@ static int expand_variables_internal( parser_t &parser, wchar_t * const in, std:
if( is_ok ) if( is_ok )
{ {
tokenize_variable_array( var_val, var_item_list ); tokenize_variable_array( var_val.c_str(), var_item_list );
if( !all_vars ) if( !all_vars )
{ {

View file

@ -266,7 +266,7 @@ const wchar_t *kill_yank()
void kill_sanity_check() void kill_sanity_check()
{ {
int i; int i;
if( is_interactive ) if( get_is_interactive() )
{ {
/* Test that the kill-ring is consistent */ /* Test that the kill-ring is consistent */
if( kill_current != 0 ) if( kill_current != 0 )

View file

@ -762,6 +762,8 @@ void parser_t::print_errors_stderr()
int parser_t::eval_args( const wchar_t *line, std::vector<completion_t> &args ) int parser_t::eval_args( const wchar_t *line, std::vector<completion_t> &args )
{ {
tokenizer tok; tokenizer tok;
const bool show_errors = (this->parser_type == PARSER_TYPE_GENERAL || this->parser_type == PARSER_TYPE_ERRORS_ONLY);
/* /*
eval_args may be called while evaulating another command, so we eval_args may be called while evaulating another command, so we
save the previous tokenizer and restore it on exit save the previous tokenizer and restore it on exit
@ -773,11 +775,14 @@ int parser_t::eval_args( const wchar_t *line, std::vector<completion_t> &args )
CHECK( line, 1 ); CHECK( line, 1 );
// CHECK( args, 1 ); // CHECK( args, 1 );
proc_push_interactive(0); // PCA we need to suppress calling proc_push_interactive off of the main thread. I'm not sure exactly what it does.
if (this->parser_type == PARSER_TYPE_GENERAL)
proc_push_interactive(0);
current_tokenizer = &tok; current_tokenizer = &tok;
current_tokenizer_pos = 0; current_tokenizer_pos = 0;
tok_init( &tok, line, 0 ); tok_init( &tok, line, (show_errors ? 0 : TOK_SQUASH_ERRORS) );
error_code=0; error_code=0;
for(;do_loop && tok_has_next( &tok) ; tok_next( &tok ) ) for(;do_loop && tok_has_next( &tok) ; tok_next( &tok ) )
@ -794,7 +799,7 @@ int parser_t::eval_args( const wchar_t *line, std::vector<completion_t> &args )
DIE_MEM(); DIE_MEM();
} }
if( expand_string( tmp, args, 0 ) == EXPAND_ERROR ) if( expand_string( tmp, args, (show_errors ? 0 : EXPAND_NO_DESCRIPTIONS) ) == EXPAND_ERROR )
{ {
err_pos=tok_get_pos( &tok ); err_pos=tok_get_pos( &tok );
do_loop=0; do_loop=0;
@ -809,10 +814,11 @@ int parser_t::eval_args( const wchar_t *line, std::vector<completion_t> &args )
case TOK_ERROR: case TOK_ERROR:
{ {
error( SYNTAX_ERROR, if (show_errors)
tok_get_pos( &tok ), error( SYNTAX_ERROR,
TOK_ERR_MSG, tok_get_pos( &tok ),
tok_last(&tok) ); TOK_ERR_MSG,
tok_last(&tok) );
do_loop=0; do_loop=0;
break; break;
@ -820,10 +826,11 @@ int parser_t::eval_args( const wchar_t *line, std::vector<completion_t> &args )
default: default:
{ {
error( SYNTAX_ERROR, if (show_errors)
tok_get_pos( &tok ), error( SYNTAX_ERROR,
UNEXPECTED_TOKEN_ERR_MSG, tok_get_pos( &tok ),
tok_get_desc( tok_last_type(&tok)) ); UNEXPECTED_TOKEN_ERR_MSG,
tok_get_desc( tok_last_type(&tok)) );
do_loop=0; do_loop=0;
break; break;
@ -831,13 +838,16 @@ int parser_t::eval_args( const wchar_t *line, std::vector<completion_t> &args )
} }
} }
this->print_errors_stderr(); if (show_errors)
this->print_errors_stderr();
tok_destroy( &tok ); tok_destroy( &tok );
current_tokenizer=previous_tokenizer; current_tokenizer=previous_tokenizer;
current_tokenizer_pos = previous_pos; current_tokenizer_pos = previous_pos;
proc_pop_interactive();
if (this->parser_type == PARSER_TYPE_GENERAL)
proc_pop_interactive();
return 1; return 1;
} }
@ -1114,7 +1124,7 @@ const wchar_t *parser_t::current_line()
/** /**
If we are not going to print a stack trace, at least print the line number and filename If we are not going to print a stack trace, at least print the line number and filename
*/ */
if( !is_interactive || is_function() ) if( !get_is_interactive() || is_function() )
{ {
int prev_width = my_wcswidth( lineinfo.c_str() ); int prev_width = my_wcswidth( lineinfo.c_str() );
if( file ) if( file )
@ -1139,7 +1149,7 @@ const wchar_t *parser_t::current_line()
Skip printing character position if we are in interactive mode Skip printing character position if we are in interactive mode
and the error was on the first character of the line. and the error was on the first character of the line.
*/ */
if( !is_interactive || is_function() || (current_line_width!=0) ) if( !get_is_interactive() || is_function() || (current_line_width!=0) )
{ {
// Workaround since it seems impossible to print 0 copies of a character using %*lc // Workaround since it seems impossible to print 0 copies of a character using %*lc
if( offset+current_line_width ) if( offset+current_line_width )
@ -1559,7 +1569,7 @@ void parser_t::parse_job_argument_list( process_t *p,
{ {
job_set_flag( j, JOB_WILDCARD_ERROR, 1 ); job_set_flag( j, JOB_WILDCARD_ERROR, 1 );
proc_set_last_status( STATUS_UNMATCHED_WILDCARD ); proc_set_last_status( STATUS_UNMATCHED_WILDCARD );
if( is_interactive && !is_block ) if( get_is_interactive() && !is_block )
{ {
int tmp; int tmp;
@ -2210,11 +2220,11 @@ void parser_t::eval_job( tokenizer *tok )
job_set_flag( j, JOB_SKIP_NOTIFICATION, is_subshell \ job_set_flag( j, JOB_SKIP_NOTIFICATION, is_subshell \
|| is_block \ || is_block \
|| is_event \ || is_event \
|| (!is_interactive)); || (!get_is_interactive()));
current_block->job = j; current_block->job = j;
if( is_interactive ) if( get_is_interactive() )
{ {
if( tcgetattr (0, &j->tmodes) ) if( tcgetattr (0, &j->tmodes) )
{ {

View file

@ -101,7 +101,6 @@ job_list_t &job_list(void) {
return s_job_list; return s_job_list;
} }
int is_interactive=-1;
int is_interactive_session=0; int is_interactive_session=0;
int is_subshell=0; int is_subshell=0;
int is_block=0; int is_block=0;
@ -112,6 +111,12 @@ pid_t proc_last_bg_pid = 0;
int job_control_mode = JOB_CONTROL_INTERACTIVE; int job_control_mode = JOB_CONTROL_INTERACTIVE;
int no_exec=0; int no_exec=0;
static int is_interactive = -1;
int get_is_interactive(void) {
ASSERT_IS_MAIN_THREAD();
return is_interactive;
}
/** /**
The event variable used to send all process event The event variable used to send all process event
@ -1236,6 +1241,7 @@ void proc_sanity_check()
void proc_push_interactive( int value ) void proc_push_interactive( int value )
{ {
ASSERT_IS_MAIN_THREAD();
int old = is_interactive; int old = is_interactive;
interactive_stack.push_back(is_interactive); interactive_stack.push_back(is_interactive);
is_interactive = value; is_interactive = value;
@ -1245,6 +1251,7 @@ void proc_push_interactive( int value )
void proc_pop_interactive() void proc_pop_interactive()
{ {
ASSERT_IS_MAIN_THREAD();
int old = is_interactive; int old = is_interactive;
is_interactive= interactive_stack.back(); is_interactive= interactive_stack.back();
interactive_stack.pop_back(); interactive_stack.pop_back();

2
proc.h
View file

@ -366,7 +366,7 @@ extern int is_block;
/** /**
Whether we are reading from the keyboard right now Whether we are reading from the keyboard right now
*/ */
extern int is_interactive; int get_is_interactive(void);
/** /**
Whether this shell is attached to the keyboard at all Whether this shell is attached to the keyboard at all

View file

@ -1049,6 +1049,9 @@ static void completion_insert( const wchar_t *val, int flags )
} }
insert_char( L' ' ); insert_char( L' ' );
} }
/* Since we just inserted a completion, don't immediately do a new autosuggestion */
data->suppress_autosuggestion = true;
} }
free(replaced); free(replaced);
@ -1235,9 +1238,6 @@ struct autosuggestion_context_t {
int threaded_autosuggest(void) { int threaded_autosuggest(void) {
ASSERT_IS_BACKGROUND_THREAD(); ASSERT_IS_BACKGROUND_THREAD();
std::vector<completion_t> completions;
complete(search_string.c_str(), completions, COMPLETE_AUTOSUGGEST);
while (searcher.go_backwards()) { while (searcher.go_backwards()) {
history_item_t item = searcher.current_item(); history_item_t item = searcher.current_item();
bool item_ok = false; bool item_ok = false;
@ -1259,6 +1259,15 @@ struct autosuggestion_context_t {
} }
} }
/* Try normal completions */
std::vector<completion_t> completions;
complete2(search_string, completions, COMPLETE_AUTOSUGGEST);
if (! completions.empty()) {
this->autosuggestion = this->search_string;
this->autosuggestion.append(completions.at(0).completion);
return 1;
}
/* Since we didn't find a suggestion from history, try other means */ /* Since we didn't find a suggestion from history, try other means */
wcstring special_suggestion; wcstring special_suggestion;
if (autosuggest_suggest_special(search_string, working_directory, special_suggestion)) { if (autosuggest_suggest_special(search_string, working_directory, special_suggestion)) {
@ -1436,8 +1445,7 @@ static int handle_completions( std::vector<completion_t> &comp )
*/ */
if( !(c.flags & COMPLETE_NO_CASE) || reader_can_replace( tok, c.flags ) ) if( !(c.flags & COMPLETE_NO_CASE) || reader_can_replace( tok, c.flags ) )
{ {
completion_insert( c.completion.c_str(), completion_insert( c.completion.c_str(), c.flags );
c.flags );
} }
done = 1; done = 1;
len = 1; len = 1;
@ -1732,7 +1740,7 @@ static void reader_interactive_destroy()
void reader_sanity_check() void reader_sanity_check()
{ {
if( is_interactive) if( get_is_interactive())
{ {
if( !data ) if( !data )
sanity_lose(); sanity_lose();
@ -2440,7 +2448,7 @@ static void reader_super_highlight_me_plenty( int match_highlight_pos )
/* Here's a hack. Check to see if our autosuggestion still applies; if so, don't recompute it. Since the autosuggestion computation is asynchronous, this avoids "flashing" as you type into the autosuggestion. */ /* Here's a hack. Check to see if our autosuggestion still applies; if so, don't recompute it. Since the autosuggestion computation is asynchronous, this avoids "flashing" as you type into the autosuggestion. */
const wcstring &cmd = data->command_line, &suggest = data->autosuggestion; const wcstring &cmd = data->command_line, &suggest = data->autosuggestion;
if (! suggest.empty() && ! cmd.empty() && string_prefixes_string(cmd, suggest)) { if (can_autosuggest() && ! suggest.empty() && string_prefixes_string(cmd, suggest)) {
/* The autosuggestion is still reasonable, so do nothing */ /* The autosuggestion is still reasonable, so do nothing */
} else { } else {
update_autosuggestion(); update_autosuggestion();
@ -2450,7 +2458,7 @@ static void reader_super_highlight_me_plenty( int match_highlight_pos )
int exit_status() int exit_status()
{ {
if( is_interactive ) if( get_is_interactive() )
return job_list().empty() && data->end_loop; return job_list().empty() && data->end_loop;
else else
return end_loop; return end_loop;
@ -3444,7 +3452,7 @@ int reader_read( int fd, io_data_t *io )
int inter = ((fd == STDIN_FILENO) && isatty(STDIN_FILENO)); int inter = ((fd == STDIN_FILENO) && isatty(STDIN_FILENO));
proc_push_interactive( inter ); proc_push_interactive( inter );
res= is_interactive?read_i():read_ni( fd, io ); res= get_is_interactive() ? read_i():read_ni( fd, io );
/* /*
If the exit command was called in a script, only exit the If the exit command was called in a script, only exit the

View file

@ -41,7 +41,7 @@ void sanity_lose()
int sanity_check() int sanity_check()
{ {
if( !insane ) if( !insane )
if( is_interactive ) if( get_is_interactive() )
history_sanity_check(); history_sanity_check();
if( !insane ) if( !insane )
reader_sanity_check(); reader_sanity_check();

View file

@ -503,7 +503,7 @@ void signal_set_handlers()
{ {
struct sigaction act; struct sigaction act;
if( is_interactive == -1 ) if( get_is_interactive() == -1 )
return; return;
sigemptyset( & act.sa_mask ); sigemptyset( & act.sa_mask );
@ -527,7 +527,7 @@ void signal_set_handlers()
*/ */
sigaction( SIGPIPE, &act, 0); sigaction( SIGPIPE, &act, 0);
if( is_interactive ) if( get_is_interactive() )
{ {
/* /*
Interactive mode. Ignore interactive signals. We are a Interactive mode. Ignore interactive signals. We are a