mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-13 21:44:16 +00:00
Factor is_potential_path to properly handle CDPATH
This will let us color cd commands better
This commit is contained in:
parent
1a264ab7c2
commit
0c79bb6e7c
5 changed files with 211 additions and 237 deletions
434
highlight.cpp
434
highlight.cpp
|
@ -64,22 +64,54 @@ static const wchar_t * const highlight_var[] =
|
||||||
L"fish_color_autosuggestion"
|
L"fish_color_autosuggestion"
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/* If the given path looks like it's relative to the working directory, then prepend that working directory. */
|
||||||
Tests if the specified string is the prefix of any valid path in the system.
|
static wcstring apply_working_directory(const wcstring &path, const wcstring &working_directory) {
|
||||||
|
if (path.empty() || working_directory.empty())
|
||||||
\require_dir Whether the valid path must be a directory
|
return path;
|
||||||
\out_path If non-null, the path on output
|
|
||||||
\return zero it this is not a valid prefix, non-zero otherwise
|
/* We're going to make sure that if we want to prepend the wd, that the string has no leading / */
|
||||||
*/
|
bool prepend_wd;
|
||||||
// PCA DOES_IO
|
switch (path.at(0)) {
|
||||||
static bool is_potential_path( const wcstring &cpath, wcstring *out_path = NULL, bool require_dir = false )
|
case L'/':
|
||||||
|
case L'~':
|
||||||
|
prepend_wd = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
prepend_wd = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! prepend_wd) {
|
||||||
|
/* No need to prepend the wd, so just return the path we were given */
|
||||||
|
return path;
|
||||||
|
} else {
|
||||||
|
/* Remove up to one ./ */
|
||||||
|
wcstring path_component = path;
|
||||||
|
if (string_prefixes_string(L"./", path_component)) {
|
||||||
|
path_component.erase(0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Removing leading /s */
|
||||||
|
while (string_prefixes_string(L"/", path_component)) {
|
||||||
|
path_component.erase(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Construct and return a new path */
|
||||||
|
wcstring new_path = working_directory;
|
||||||
|
append_path_component(new_path, path_component);
|
||||||
|
return new_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tests whether the specified string cpath is the prefix of anything we could cd to. directories is a list of possible parent directories (typically either the working directory, or the cdpath). This does I/O! */
|
||||||
|
static bool is_potential_path( const wcstring &cpath, const wcstring_list_t &directories, bool require_dir = false, wcstring *out_path = NULL)
|
||||||
{
|
{
|
||||||
ASSERT_IS_BACKGROUND_THREAD();
|
ASSERT_IS_BACKGROUND_THREAD();
|
||||||
|
|
||||||
const wchar_t *unescaped, *in;
|
const wchar_t *unescaped, *in;
|
||||||
wcstring cleaned_path;
|
wcstring clean_path;
|
||||||
int has_magic = 0;
|
int has_magic = 0;
|
||||||
bool res = false;
|
bool result = false;
|
||||||
|
|
||||||
wcstring path(cpath);
|
wcstring path(cpath);
|
||||||
expand_tilde(path);
|
expand_tilde(path);
|
||||||
|
@ -115,7 +147,7 @@ static bool is_potential_path( const wcstring &cpath, wcstring *out_path = NULL,
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
cleaned_path += *in;
|
clean_path.append(in, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,62 +155,98 @@ static bool is_potential_path( const wcstring &cpath, wcstring *out_path = NULL,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !has_magic && ! cleaned_path.empty() )
|
if( ! has_magic && ! clean_path.empty() )
|
||||||
{
|
{
|
||||||
bool must_be_full_dir = cleaned_path[cleaned_path.length()-1] == L'/';
|
/* Don't test the same path multiple times, which can happen if the path is absolute and the CDPATH contains multiple entries */
|
||||||
DIR *dir;
|
std::set<wcstring> checked_paths;
|
||||||
if( must_be_full_dir )
|
|
||||||
{
|
|
||||||
dir = wopendir( cleaned_path );
|
|
||||||
if( dir )
|
|
||||||
{
|
|
||||||
res = true;
|
|
||||||
if (out_path)
|
|
||||||
*out_path = cleaned_path;
|
|
||||||
closedir( dir );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wcstring dir_name = wdirname(cleaned_path);
|
|
||||||
wcstring base_name = wbasename(cleaned_path);
|
|
||||||
|
|
||||||
if( dir_name == L"/" && base_name == L"/" )
|
|
||||||
{
|
|
||||||
res = true;
|
|
||||||
if (out_path)
|
|
||||||
*out_path = cleaned_path;
|
|
||||||
}
|
|
||||||
else if( (dir = wopendir( dir_name)) )
|
|
||||||
{
|
|
||||||
wcstring ent;
|
|
||||||
bool is_dir;
|
|
||||||
while (wreaddir_resolving(dir, dir_name, ent, &is_dir))
|
|
||||||
{
|
|
||||||
if (string_prefixes_string(base_name, ent) && (! require_dir || is_dir))
|
|
||||||
{
|
|
||||||
res = true;
|
|
||||||
if (out_path) {
|
|
||||||
out_path->assign(dir_name);
|
|
||||||
out_path->push_back(L'/');
|
|
||||||
out_path->append(ent);
|
|
||||||
path_make_canonical(*out_path);
|
|
||||||
/* We actually do want a trailing / for directories, since it makes autosuggestion a bit nicer */
|
|
||||||
if (is_dir)
|
|
||||||
out_path->push_back(L'/');
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir( dir );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (size_t wd_idx = 0; wd_idx < directories.size() && ! result; wd_idx++) {
|
||||||
|
const wcstring &wd = directories.at(wd_idx);
|
||||||
|
|
||||||
|
const wcstring abs_path = apply_working_directory(clean_path, wd);
|
||||||
|
|
||||||
|
/* Skip this if it's empty or we've already checked it */
|
||||||
|
if (abs_path.empty() || checked_paths.count(abs_path))
|
||||||
|
continue;
|
||||||
|
checked_paths.insert(abs_path);
|
||||||
|
|
||||||
|
/* If we end with a slash, then it must be a directory */
|
||||||
|
bool must_be_full_dir = abs_path.at(abs_path.size()-1) == L'/';
|
||||||
|
if (must_be_full_dir)
|
||||||
|
{
|
||||||
|
struct stat buf;
|
||||||
|
if (0 == wstat(abs_path, &buf) && S_ISDIR(buf.st_mode)) {
|
||||||
|
result = true;
|
||||||
|
/* Return the path suffix, not the whole absolute path */
|
||||||
|
if (out_path)
|
||||||
|
*out_path = clean_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DIR *dir = NULL;
|
||||||
|
|
||||||
|
/* We do not end with a slash; it does not have to be a directory */
|
||||||
|
const wcstring dir_name = wdirname(abs_path);
|
||||||
|
const wcstring base_name = wbasename(abs_path);
|
||||||
|
if (dir_name == L"/" && base_name == L"/")
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
if (out_path)
|
||||||
|
*out_path = clean_path;
|
||||||
|
}
|
||||||
|
else if ((dir = wopendir(dir_name))) {
|
||||||
|
/* We opened the dir_name; look for a string where the base name prefixes it */
|
||||||
|
wcstring ent;
|
||||||
|
|
||||||
|
// Don't ask for the is_dir value unless we care, because it can cause extra filesystem acces */
|
||||||
|
bool is_dir = false;
|
||||||
|
while (wreaddir_resolving(dir, dir_name, ent, require_dir ? &is_dir : NULL))
|
||||||
|
{
|
||||||
|
/* TODO: support doing the right thing on case-insensitive filesystems like HFS+ */
|
||||||
|
if (string_prefixes_string(base_name, ent) && (! require_dir || is_dir))
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
if (out_path) {
|
||||||
|
out_path->assign(dir_name);
|
||||||
|
out_path->push_back(L'/');
|
||||||
|
out_path->append(ent);
|
||||||
|
path_make_canonical(*out_path);
|
||||||
|
/* We actually do want a trailing / for directories, since it makes autosuggestion a bit nicer */
|
||||||
|
if (is_dir)
|
||||||
|
out_path->push_back(L'/');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
return res;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Given a string, return whether it prefixes a path that we could cd into. Return that path in out_path */
|
||||||
|
static bool is_potential_cd_path(const wcstring &path, const wcstring &working_directory, wcstring *out_path) {
|
||||||
|
/* Get the CDPATH */
|
||||||
|
env_var_t cdpath = env_get_string(L"CDPATH");
|
||||||
|
if (cdpath.missing_or_empty())
|
||||||
|
cdpath = L".";
|
||||||
|
|
||||||
|
/* Tokenize it into directories */
|
||||||
|
wcstring_list_t directories;
|
||||||
|
wcstokenizer tokenizer(cdpath, ARRAY_SEP_STR);
|
||||||
|
wcstring next_path;
|
||||||
|
while (tokenizer.next(next_path))
|
||||||
|
{
|
||||||
|
/* Ensure that we use the working directory for relative cdpaths like "." */
|
||||||
|
directories.push_back(apply_working_directory(next_path, working_directory));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call is_potential_path */
|
||||||
|
return is_potential_path(path, directories, true /* require_dir */, out_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
rgb_color_t highlight_get_color( int highlight, bool is_background )
|
rgb_color_t highlight_get_color( int highlight, bool is_background )
|
||||||
|
@ -235,7 +303,6 @@ rgb_color_t highlight_get_color( int highlight, bool is_background )
|
||||||
*/
|
*/
|
||||||
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();
|
||||||
|
@ -543,13 +610,18 @@ class autosuggest_parsed_command_t {
|
||||||
/* Arguments to the command */
|
/* Arguments to the command */
|
||||||
wcstring_list_t arguments;
|
wcstring_list_t arguments;
|
||||||
|
|
||||||
|
/* Position in the string of the start of the last argument */
|
||||||
|
int last_arg_pos;
|
||||||
|
|
||||||
autosuggest_parsed_command_t(const wcstring &str) {
|
autosuggest_parsed_command_t(const wcstring &str) {
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wcstring cmd;
|
wcstring cmd;
|
||||||
wcstring_list_t args;
|
wcstring_list_t args;
|
||||||
bool had_cmd = false, recognized_cmd = false;
|
int arg_pos = -1;
|
||||||
|
|
||||||
|
bool had_cmd = false;
|
||||||
tokenizer tok;
|
tokenizer tok;
|
||||||
for (tok_init( &tok, str.c_str(), TOK_SQUASH_ERRORS); tok_has_next(&tok); tok_next(&tok))
|
for (tok_init( &tok, str.c_str(), TOK_SQUASH_ERRORS); tok_has_next(&tok); tok_next(&tok))
|
||||||
{
|
{
|
||||||
|
@ -563,6 +635,7 @@ class autosuggest_parsed_command_t {
|
||||||
{
|
{
|
||||||
/* Parameter to the command */
|
/* Parameter to the command */
|
||||||
args.push_back(tok_last(&tok));
|
args.push_back(tok_last(&tok));
|
||||||
|
arg_pos = tok_get_pos(&tok);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -576,7 +649,7 @@ class autosuggest_parsed_command_t {
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool is_subcommand = false;
|
bool is_subcommand = false;
|
||||||
int mark = tok_get_pos( &tok );
|
int mark = tok_get_pos(&tok);
|
||||||
|
|
||||||
if (parser_keywords_is_subcommand(cmd))
|
if (parser_keywords_is_subcommand(cmd))
|
||||||
{
|
{
|
||||||
|
@ -631,6 +704,7 @@ class autosuggest_parsed_command_t {
|
||||||
had_cmd = false;
|
had_cmd = false;
|
||||||
cmd.empty();
|
cmd.empty();
|
||||||
args.empty();
|
args.empty();
|
||||||
|
arg_pos = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,182 +722,71 @@ class autosuggest_parsed_command_t {
|
||||||
if (had_cmd) {
|
if (had_cmd) {
|
||||||
this->command.swap(cmd);
|
this->command.swap(cmd);
|
||||||
this->arguments.swap(args);
|
this->arguments.swap(args);
|
||||||
|
this->last_arg_pos = arg_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 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 &outSuggestion) {
|
||||||
bool autosuggest_suggest_special(const wcstring &str, const wcstring &working_directory, wcstring &outString) {
|
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
ASSERT_IS_BACKGROUND_THREAD();
|
||||||
|
|
||||||
wcstring cmd;
|
|
||||||
bool had_cmd = false, recognized_cmd = false;
|
|
||||||
|
|
||||||
wcstring suggestion;
|
/* Parse the string */
|
||||||
|
const autosuggest_parsed_command_t parsed(str);
|
||||||
|
|
||||||
tokenizer tok;
|
bool result = false;
|
||||||
for( tok_init( &tok, str.c_str(), TOK_SQUASH_ERRORS );
|
if (parsed.command == L"cd" && ! parsed.arguments.empty()) {
|
||||||
tok_has_next( &tok );
|
/* We can possibly handle this specially */
|
||||||
tok_next( &tok ) )
|
wcstring dir = parsed.arguments.back();
|
||||||
{
|
wcstring suggested_path;
|
||||||
int last_type = tok_last_type( &tok );
|
|
||||||
|
/* We always return true because we recognized the command. This prevents us from falling back to dumber algorithms; for example we won't suggest a non-directory for the cd command. */
|
||||||
switch( last_type )
|
result = true;
|
||||||
{
|
outSuggestion.clear();
|
||||||
case TOK_STRING:
|
|
||||||
{
|
if (is_potential_cd_path(dir, working_directory, &suggested_path)) {
|
||||||
if( had_cmd )
|
|
||||||
{
|
|
||||||
recognized_cmd = (cmd == L"cd");
|
|
||||||
if( recognized_cmd )
|
|
||||||
{
|
|
||||||
wcstring dir = tok_last( &tok );
|
|
||||||
wcstring suggested_path;
|
|
||||||
|
|
||||||
if (is_potential_path(dir, &suggested_path, true /* require directory */)) {
|
|
||||||
|
|
||||||
/* suggested_path needs to actually have dir as a prefix (perhaps with different case). Handle stuff like ./ */
|
/* suggested_path needs to actually have dir as a prefix (perhaps with different case). Handle stuff like ./ */
|
||||||
bool wants_dot_slash = string_prefixes_string(L"./", dir);
|
bool wants_dot_slash = string_prefixes_string(L"./", dir);
|
||||||
bool has_dot_slash = string_prefixes_string(L"./", suggested_path);
|
bool has_dot_slash = string_prefixes_string(L"./", suggested_path);
|
||||||
|
|
||||||
if (wants_dot_slash && ! has_dot_slash) {
|
if (wants_dot_slash && ! has_dot_slash) {
|
||||||
suggested_path.insert(0, L"./");
|
suggested_path.insert(0, L"./");
|
||||||
} else if (! wants_dot_slash && has_dot_slash) {
|
} else if (! wants_dot_slash && has_dot_slash) {
|
||||||
suggested_path.erase(0, 2);
|
suggested_path.erase(0, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wants_tilde = string_prefixes_string(L"~", dir);
|
bool wants_tilde = string_prefixes_string(L"~", dir);
|
||||||
bool has_tilde = string_prefixes_string(L"~", suggested_path);
|
bool has_tilde = string_prefixes_string(L"~", suggested_path);
|
||||||
if (wants_tilde && ! has_tilde) {
|
if (wants_tilde && ! has_tilde) {
|
||||||
// The input string has a tilde, the output string does not
|
// The input string has a tilde, the output string does not
|
||||||
// Extract the tilde part, expand it, see if the expansion prefixes the suggestion
|
// Extract the tilde part, expand it, see if the expansion prefixes the suggestion
|
||||||
// If so, replace it with the tilde part
|
// If so, replace it with the tilde part
|
||||||
size_t slash_idx = dir.find(L'/');
|
size_t slash_idx = dir.find(L'/');
|
||||||
const wcstring tilde_part(dir, 0, slash_idx); //note that slash_idx is npos this will return everything
|
const wcstring tilde_part(dir, 0, slash_idx); //note that slash_idx is npos this will return everything
|
||||||
|
|
||||||
// Expand the tilde
|
// Expand the tilde
|
||||||
wcstring expanded_tilde = tilde_part;
|
wcstring expanded_tilde = tilde_part;
|
||||||
expand_tilde(expanded_tilde);
|
expand_tilde(expanded_tilde);
|
||||||
|
|
||||||
// Replace it
|
// Replace it
|
||||||
if (string_prefixes_string(expanded_tilde, suggested_path)) {
|
if (string_prefixes_string(expanded_tilde, suggested_path)) {
|
||||||
suggested_path.replace(0, expanded_tilde.size(), tilde_part);
|
suggested_path.replace(0, expanded_tilde.size(), tilde_part);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suggestion = str;
|
/* Success */
|
||||||
suggestion.erase(tok_get_pos(&tok));
|
outSuggestion = str;
|
||||||
suggestion.append(suggested_path);
|
outSuggestion.erase(parsed.last_arg_pos);
|
||||||
}
|
outSuggestion.append(suggested_path);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
/* Either an error or some other command, so we don't handle it specially */
|
||||||
{
|
|
||||||
/*
|
|
||||||
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 );
|
return result;
|
||||||
|
|
||||||
if (recognized_cmd) {
|
|
||||||
outString.swap(suggestion);
|
|
||||||
}
|
|
||||||
|
|
||||||
return recognized_cmd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool autosuggest_special_validate_from_history(const wcstring &str, const wcstring &working_directory, bool *outSuggestionOK) {
|
bool autosuggest_special_validate_from_history(const wcstring &str, const wcstring &working_directory, bool *outSuggestionOK) {
|
||||||
|
@ -1308,6 +1271,9 @@ void highlight_shell( const wcstring &buff, std::vector<int> &color, int pos, wc
|
||||||
color.at(i) = last_val;
|
color.at(i) = last_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Do something sucky and get the current working directory on this background thread. This should really be passed in. Note this needs to be a vector (of one directory). */
|
||||||
|
const wcstring_list_t working_directories(1, get_working_directory());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Color potentially valid paths in a special path color if they
|
Color potentially valid paths in a special path color if they
|
||||||
are the current token.
|
are the current token.
|
||||||
|
@ -1322,7 +1288,7 @@ void highlight_shell( const wcstring &buff, std::vector<int> &color, int pos, wc
|
||||||
if( tok_begin && tok_end )
|
if( tok_begin && tok_end )
|
||||||
{
|
{
|
||||||
const wcstring token(tok_begin, tok_end-tok_begin);
|
const wcstring token(tok_begin, tok_end-tok_begin);
|
||||||
if( is_potential_path( token ) )
|
if (is_potential_path(token, working_directories))
|
||||||
{
|
{
|
||||||
for( ptrdiff_t i=tok_begin-cbuff; i < (tok_end-cbuff); i++ )
|
for( ptrdiff_t i=tok_begin-cbuff; i < (tok_end-cbuff); i++ )
|
||||||
{
|
{
|
||||||
|
|
|
@ -106,7 +106,13 @@ 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 );
|
||||||
|
|
||||||
|
/** Given a command 'str' from the history, try to determine whether we ought to suggest it by specially recognizing the command.
|
||||||
|
Returns true if we validated the command. If so, returns by reference whether the suggestion is valid or not.
|
||||||
|
*/
|
||||||
bool autosuggest_special_validate_from_history(const wcstring &str, const wcstring &working_directory, bool *outSuggestionOK);
|
bool autosuggest_special_validate_from_history(const wcstring &str, const wcstring &working_directory, bool *outSuggestionOK);
|
||||||
|
|
||||||
|
/** Given the command line contents 'str', return via reference a suggestion by specially recognizing the command. 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);
|
||||||
|
|
||||||
|
|
||||||
|
|
1
path.h
1
path.h
|
@ -68,6 +68,7 @@ bool path_is_valid(const wcstring &path, const wcstring &working_directory);
|
||||||
/** Returns whether the two paths refer to the same file */
|
/** Returns whether the two paths refer to the same file */
|
||||||
bool paths_are_same_file(const wcstring &path1, const wcstring &path2);
|
bool paths_are_same_file(const wcstring &path1, const wcstring &path2);
|
||||||
|
|
||||||
|
/* Returns the current working directory as returned by wgetcwd */
|
||||||
wcstring get_working_directory(void);
|
wcstring get_working_directory(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1296,8 +1296,8 @@ struct autosuggestion_context_t {
|
||||||
|
|
||||||
// Here we do something a little funny
|
// Here we do something a little funny
|
||||||
// If the line ends with a space, and the cursor is not at the end,
|
// If the line ends with a space, and the cursor is not at the end,
|
||||||
// Don't use completion autosuggestions. It ends up being pretty weird seeing stuff get spammed on the right
|
// don't use completion autosuggestions. It ends up being pretty weird seeing stuff get spammed on the right
|
||||||
// While you go back to edit a line
|
// while you go back to edit a line
|
||||||
const bool line_ends_with_space = iswspace(search_string.at(search_string.size() - 1));
|
const bool line_ends_with_space = iswspace(search_string.at(search_string.size() - 1));
|
||||||
const bool cursor_at_end = (this->cursor_pos == search_string.size());
|
const bool cursor_at_end = (this->cursor_pos == search_string.size());
|
||||||
if (line_ends_with_space && ! cursor_at_end)
|
if (line_ends_with_space && ! cursor_at_end)
|
||||||
|
|
|
@ -73,10 +73,11 @@ bool wreaddir_resolving(DIR *dir, const std::wstring &dir_path, std::wstring &ou
|
||||||
|
|
||||||
out_name = str2wcstring(d->d_name);
|
out_name = str2wcstring(d->d_name);
|
||||||
if (out_is_dir) {
|
if (out_is_dir) {
|
||||||
|
/* The caller cares if this is a directory, so check */
|
||||||
bool is_dir;
|
bool is_dir;
|
||||||
if (d->d_type == DT_DIR) {
|
if (d->d_type == DT_DIR) {
|
||||||
is_dir = true;
|
is_dir = true;
|
||||||
} else if (d->d_type == DT_LNK) {
|
} else if (d->d_type == DT_LNK || d->d_type == DT_UNKNOWN) {
|
||||||
/* We want to treat symlinks to directories as directories. Use stat to resolve it. */
|
/* We want to treat symlinks to directories as directories. Use stat to resolve it. */
|
||||||
cstring fullpath = wcs2string(dir_path);
|
cstring fullpath = wcs2string(dir_path);
|
||||||
fullpath.push_back('/');
|
fullpath.push_back('/');
|
||||||
|
|
Loading…
Reference in a new issue