mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-27 20:25:12 +00:00
More work towards autosuggesting completions
This commit is contained in:
parent
5ea78f55f2
commit
38e40862fe
14 changed files with 184 additions and 140 deletions
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
122
complete.cpp
122
complete.cpp
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
58
complete.h
58
complete.h
|
@ -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
17
env.cpp
|
@ -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
4
env.h
|
@ -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 );
|
||||||
|
|
||||||
|
|
13
expand.cpp
13
expand.cpp
|
@ -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 )
|
||||||
{
|
{
|
||||||
|
|
2
kill.cpp
2
kill.cpp
|
@ -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 )
|
||||||
|
|
46
parser.cpp
46
parser.cpp
|
@ -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) )
|
||||||
{
|
{
|
||||||
|
|
9
proc.cpp
9
proc.cpp
|
@ -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
2
proc.h
|
@ -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
|
||||||
|
|
26
reader.cpp
26
reader.cpp
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue