bool autosuggest_suggest_special(const wcstring &str, const wcstring &working_directory, wcstring &outSuggestion) { if (str.empty()) return false; ASSERT_IS_BACKGROUND_THREAD(); /* Parse the string */ wcstring parsed_command; wcstring_list_t parsed_arguments; int parsed_last_arg_pos = -1; if (! autosuggest_parse_command(str, &parsed_command, &parsed_arguments, &parsed_last_arg_pos)) return false; bool result = false; if (parsed_command == L"cd" && ! parsed_arguments.empty()) { /* We can possibly handle this specially */ wcstring dir = parsed_arguments.back(); wcstring suggested_path; /* 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. */ result = true; outSuggestion.clear(); if (is_potential_cd_path(dir, working_directory, &suggested_path)) { /* Success */ outSuggestion = str; outSuggestion.erase(parsed_last_arg_pos); outSuggestion.append(suggested_path); } } else { /* Either an error or some other command, so we don't handle it specially */ } return result; }
/* We have to return an escaped string here */ bool autosuggest_suggest_special(const wcstring &str, const wcstring &working_directory, wcstring &outSuggestion) { if (str.empty()) return false; ASSERT_IS_BACKGROUND_THREAD(); /* Parse the string */ wcstring parsed_command; wcstring_list_t parsed_arguments; int parsed_last_arg_pos = -1; if (! autosuggest_parse_command(str, &parsed_command, &parsed_arguments, &parsed_last_arg_pos)) return false; bool result = false; if (parsed_command == L"cd" && ! parsed_arguments.empty()) { /* We can possibly handle this specially */ const wcstring escaped_dir = parsed_arguments.back(); wcstring suggested_path; /* 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. */ result = true; outSuggestion.clear(); /* Unescape the parameter */ wcstring unescaped_dir = escaped_dir; bool unescaped = unescape_string(unescaped_dir, UNESCAPE_INCOMPLETE); /* Determine the quote type we got from the input directory. */ wchar_t quote = L'\0'; parse_util_get_parameter_info(escaped_dir, 0, "e, NULL, NULL); /* Big hack to avoid expanding a tilde inside quotes */ path_flags_t path_flags = (quote == L'\0') ? PATH_EXPAND_TILDE : 0; if (unescaped && is_potential_cd_path(unescaped_dir, working_directory, path_flags, &suggested_path)) { /* Note: this looks really wrong for strings that have an "unescapable" character in them, e.g. a \t, because parse_util_escape_string_with_quote will insert that character */ wcstring escaped_suggested_path = parse_util_escape_string_with_quote(suggested_path, quote); /* Return it */ outSuggestion = str; outSuggestion.erase(parsed_last_arg_pos); if (quote != L'\0') outSuggestion.push_back(quote); outSuggestion.append(escaped_suggested_path); if (quote != L'\0') outSuggestion.push_back(quote); } } else { /* Either an error or some other command, so we don't handle it specially */ } return result; }
bool autosuggest_validate_from_history(const history_item_t &item, file_detection_context_t &detector, const wcstring &working_directory, const env_vars_snapshot_t &vars) { ASSERT_IS_BACKGROUND_THREAD(); bool handled = false, suggestionOK = false; /* Parse the string */ wcstring parsed_command; wcstring_list_t parsed_arguments; int parsed_last_arg_pos = -1; if (! autosuggest_parse_command(item.str(), &parsed_command, &parsed_arguments, &parsed_last_arg_pos)) return false; if (parsed_command == L"cd" && ! parsed_arguments.empty()) { /* We can possibly handle this specially */ wcstring dir = parsed_arguments.back(); if (expand_one(dir, EXPAND_SKIP_CMDSUBST)) { handled = true; bool is_help = string_prefixes_string(dir, L"--help") || string_prefixes_string(dir, L"-h"); if (is_help) { suggestionOK = false; } else { wcstring path; bool can_cd = path_get_cdpath(dir, &path, working_directory.c_str(), vars); if (! can_cd) { suggestionOK = false; } else if (paths_are_same_file(working_directory, path)) { /* Don't suggest the working directory as the path! */ suggestionOK = false; } else { suggestionOK = true; } } } } /* If not handled specially, handle it here */ if (! handled) { bool cmd_ok = false; if (path_get_path(parsed_command, NULL)) { cmd_ok = true; } else if (builtin_exists(parsed_command) || function_exists_no_autoload(parsed_command, vars)) { cmd_ok = true; } if (cmd_ok) { const path_list_t &paths = item.get_required_paths(); if (paths.empty()) { suggestionOK= true; } else { detector.potential_paths = paths; suggestionOK = detector.paths_are_valid(paths); } } } return suggestionOK; }