Restore implicit cd for paths starting with ., .., or ~

This commit is contained in:
ridiculousfish 2012-06-02 14:04:25 -07:00
parent ae12e1b537
commit b7ba252965
6 changed files with 68 additions and 25 deletions

View file

@ -1351,22 +1351,13 @@ static wchar_t * expand_tilde_internal_compat( wchar_t *in )
void expand_tilde( wcstring &input)
{
if( input[0] == L'~' )
if( ! input.empty() && input.at(0) == L'~' )
{
input[0] = HOME_DIRECTORY;
input.at(0) = HOME_DIRECTORY;
expand_tilde_internal( input );
}
}
wchar_t * expand_tilde_compat( wchar_t *input )
{
if (input[0] == L'~') {
input[0] = HOME_DIRECTORY;
return expand_tilde_internal_compat(input);
}
return input;
}
/**
Remove any internal separators. Also optionally convert wildcard characters to
regular equivalents. This is done to support EXPAND_SKIP_WILDCARDS.

View file

@ -162,7 +162,6 @@ wcstring expand_escape_variable( const wcstring &in );
\param input the string to tilde expand
*/
void expand_tilde(wcstring &input);
wchar_t * expand_tilde_compat( wchar_t *input );
/**

View file

@ -916,7 +916,7 @@ static void tokenize( const wchar_t * const buff, std::vector<int> &color, const
}
else
{
int is_cmd = 0;
bool is_cmd = false;
int is_subcommand = 0;
int mark = tok_get_pos( &tok );
color.at(tok_get_pos( &tok )) = HIGHLIGHT_COMMAND;
@ -984,11 +984,11 @@ static void tokenize( const wchar_t * const buff, std::vector<int> &color, const
function, since we don't have to stat
any files for that
*/
if( use_builtin )
is_cmd = is_cmd || builtin_exists( cmd );
if (! is_cmd && use_builtin )
is_cmd = builtin_exists( cmd );
if( use_function )
is_cmd = is_cmd || function_exists_no_autoload( cmd, vars );
if (! is_cmd && use_function )
is_cmd = function_exists_no_autoload( cmd, vars );
/*
Moving on to expensive tests
@ -997,10 +997,17 @@ static void tokenize( const wchar_t * const buff, std::vector<int> &color, const
/*
Check if this is a regular command
*/
if( use_command )
if (! is_cmd && use_command )
{
wcstring tmp;
is_cmd = is_cmd || path_get_path_string( cmd, tmp, vars );
is_cmd = path_get_path_string( cmd, tmp, vars );
}
/* Maybe it is a path for a implicit cd command. */
if (! is_cmd)
{
if (use_builtin || (use_function && function_exists_no_autoload( L"cd", vars)))
is_cmd = path_can_be_implicit_cd(cmd, NULL, working_directory.c_str());
}
if( is_cmd )
@ -1181,7 +1188,7 @@ static void tokenize( const wchar_t * const buff, std::vector<int> &color, const
}
// PCA DOES_IO (calls is_potential_path, path_get_path, maybe others)
// PCA This function does I/O, (calls is_potential_path, path_get_path, maybe others) and so ought to only run on a background thread
void highlight_shell( const wcstring &buff, std::vector<int> &color, int pos, wcstring_list_t *error, const env_vars &vars )
{
ASSERT_IS_BACKGROUND_THREAD();

View file

@ -1956,10 +1956,28 @@ int parser_t::parse_job( process_t *p,
p->actual_cmd = path_get_path( args.at(0).completion.c_str() );
err = errno;
/*
Check if the specified command exists
*/
if( p->actual_cmd == NULL )
bool use_implicit_cd = false;
if (p->actual_cmd == NULL)
{
/* If the specified command does not exist, try using an implicit cd. */
wcstring implicit_cd_path;
use_implicit_cd = path_can_be_implicit_cd(args.at(0).completion, &implicit_cd_path);
if (use_implicit_cd)
{
args.clear();
args.push_back(completion_t(L"cd"));
args.push_back(completion_t(implicit_cd_path));
/* If we have defined a wrapper around cd, use it, otherwise use the cd builtin */
if (use_function && function_exists(L"cd"))
p->type = INTERNAL_FUNCTION;
else
p->type = INTERNAL_BUILTIN;
}
}
/* Check if the specified command exists */
if( p->actual_cmd == NULL && ! use_implicit_cd )
{
int tmp;

View file

@ -431,13 +431,38 @@ wchar_t *path_allocate_cdpath( const wcstring &dir, const wchar_t *wd )
}
bool path_can_get_cdpath(const wcstring &in, const wchar_t *wd) {
bool path_can_get_cdpath(const wcstring &in, const wchar_t *wd)
{
wchar_t *tmp = path_allocate_cdpath(in, wd);
bool result = (tmp != NULL);
free(tmp);
return result;
}
bool path_can_be_implicit_cd(const wcstring &path, wcstring *out_path, const wchar_t *wd)
{
wcstring exp_path = path;
expand_tilde(exp_path);
bool result = false;
if (string_prefixes_string(L"/", exp_path) ||
string_prefixes_string(L"./", exp_path) ||
string_prefixes_string(L"../", exp_path) ||
exp_path == L"..")
{
/* These paths can be implicit cd. Note that a single period cannot (that's used for sourcing files anyways) */
wchar_t *cd_path = path_allocate_cdpath(exp_path, wd);
if (cd_path)
{
/* It worked. Return the path if desired */
if (out_path)
out_path->assign(cd_path);
free(cd_path);
result = true;
}
}
return result;
}
bool path_get_config(wcstring &path)
{

3
path.h
View file

@ -31,6 +31,9 @@ bool path_get_config(wcstring &path);
*/
wchar_t *path_get_path( const wchar_t *cmd );
/** Returns whether the path can be used for an implicit cd command; if so, also returns the path by reference (if desired). This requires it to start with one of the allowed prefixes (., .., ~) and resolve to a directory. */
bool path_can_be_implicit_cd(const wcstring &path, wcstring *out_path = NULL, const wchar_t *wd = NULL);
class env_vars;
bool path_get_path_string(const wcstring &cmd, wcstring &output);
bool path_get_path_string(const wcstring &cmd, wcstring &output, const env_vars &vars);