1c9af18a5SGreg Clayton //===-- CommandCompletions.cpp ----------------------------------*- C++ -*-===// 2c9af18a5SGreg Clayton // 3c9af18a5SGreg Clayton // The LLVM Compiler Infrastructure 4c9af18a5SGreg Clayton // 5c9af18a5SGreg Clayton // This file is distributed under the University of Illinois Open Source 6c9af18a5SGreg Clayton // License. See LICENSE.TXT for details. 7c9af18a5SGreg Clayton // 8c9af18a5SGreg Clayton //===----------------------------------------------------------------------===// 9c9af18a5SGreg Clayton 10c9af18a5SGreg Clayton // C Includes 11558ce124SJim Ingham #include <sys/stat.h> 12fd18426eSGreg Clayton #if defined(__APPLE__) || defined(__linux__) 137cc478b9SJim Ingham #include <pwd.h> 14fd18426eSGreg Clayton #endif 15558ce124SJim Ingham 16c9af18a5SGreg Clayton // C++ Includes 17c9af18a5SGreg Clayton // Other libraries and framework includes 18c8ecc2a9SEugene Zelenko #include "llvm/ADT/SmallString.h" 19c8ecc2a9SEugene Zelenko 20c9af18a5SGreg Clayton // Project includes 219b62fd2fSGreg Clayton #include "lldb/Core/FileSpecList.h" 221f746071SGreg Clayton #include "lldb/Core/Module.h" 23190fadcdSZachary Turner #include "lldb/Core/PluginManager.h" 24190fadcdSZachary Turner #include "lldb/Host/FileSpec.h" 25190fadcdSZachary Turner #include "lldb/Host/FileSystem.h" 269b62fd2fSGreg Clayton #include "lldb/Interpreter/Args.h" 279b62fd2fSGreg Clayton #include "lldb/Interpreter/CommandCompletions.h" 289b62fd2fSGreg Clayton #include "lldb/Interpreter/CommandInterpreter.h" 29633a29cfSZachary Turner #include "lldb/Interpreter/OptionValueProperties.h" 301f746071SGreg Clayton #include "lldb/Symbol/CompileUnit.h" 31f21feadcSGreg Clayton #include "lldb/Symbol/Variable.h" 329b62fd2fSGreg Clayton #include "lldb/Target/Target.h" 339b62fd2fSGreg Clayton #include "lldb/Utility/CleanUp.h" 34c9af18a5SGreg Clayton 35190fadcdSZachary Turner #include "llvm/ADT/SmallString.h" 36*7d86ee5aSZachary Turner #include "llvm/Support/FileSystem.h" 37190fadcdSZachary Turner 38c9af18a5SGreg Clayton using namespace lldb_private; 39c9af18a5SGreg Clayton 40c9af18a5SGreg Clayton CommandCompletions::CommonCompletionElement 41b9c1b51eSKate Stone CommandCompletions::g_common_completions[] = { 42c8ecc2a9SEugene Zelenko {eCustomCompletion, nullptr}, 43c9af18a5SGreg Clayton {eSourceFileCompletion, CommandCompletions::SourceFiles}, 44558ce124SJim Ingham {eDiskFileCompletion, CommandCompletions::DiskFiles}, 45558ce124SJim Ingham {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories}, 46c9af18a5SGreg Clayton {eSymbolCompletion, CommandCompletions::Symbols}, 47c9af18a5SGreg Clayton {eModuleCompletion, CommandCompletions::Modules}, 483df9a8dfSCaroline Tice {eSettingsNameCompletion, CommandCompletions::SettingsNames}, 49ab65b34fSGreg Clayton {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames}, 50ab65b34fSGreg Clayton {eArchitectureCompletion, CommandCompletions::ArchitectureNames}, 51f21feadcSGreg Clayton {eVariablePathCompletion, CommandCompletions::VariablePath}, 52c8ecc2a9SEugene Zelenko {eNoCompletion, nullptr} // This one has to be last in the list. 53c9af18a5SGreg Clayton }; 54c9af18a5SGreg Clayton 55b9c1b51eSKate Stone bool CommandCompletions::InvokeCommonCompletionCallbacks( 56b9c1b51eSKate Stone CommandInterpreter &interpreter, uint32_t completion_mask, 574aa8753cSZachary Turner llvm::StringRef completion_str, int match_start_point, 584aa8753cSZachary Turner int max_return_elements, SearchFilter *searcher, bool &word_complete, 594aa8753cSZachary Turner StringList &matches) { 60c9af18a5SGreg Clayton bool handled = false; 61c9af18a5SGreg Clayton 62c9af18a5SGreg Clayton if (completion_mask & eCustomCompletion) 63c9af18a5SGreg Clayton return false; 64c9af18a5SGreg Clayton 65b9c1b51eSKate Stone for (int i = 0;; i++) { 66c9af18a5SGreg Clayton if (g_common_completions[i].type == eNoCompletion) 67c9af18a5SGreg Clayton break; 68b9c1b51eSKate Stone else if ((g_common_completions[i].type & completion_mask) == 69b9c1b51eSKate Stone g_common_completions[i].type && 70b9c1b51eSKate Stone g_common_completions[i].callback != nullptr) { 71c9af18a5SGreg Clayton handled = true; 72b9c1b51eSKate Stone g_common_completions[i].callback(interpreter, completion_str, 73b9c1b51eSKate Stone match_start_point, max_return_elements, 74b9c1b51eSKate Stone searcher, word_complete, matches); 75c9af18a5SGreg Clayton } 76c9af18a5SGreg Clayton } 77c9af18a5SGreg Clayton return handled; 78c9af18a5SGreg Clayton } 79c9af18a5SGreg Clayton 80b9c1b51eSKate Stone int CommandCompletions::SourceFiles(CommandInterpreter &interpreter, 814aa8753cSZachary Turner llvm::StringRef partial_file_name, 82c9af18a5SGreg Clayton int match_start_point, 83c9af18a5SGreg Clayton int max_return_elements, 84b9c1b51eSKate Stone SearchFilter *searcher, bool &word_complete, 85b9c1b51eSKate Stone StringList &matches) { 86558ce124SJim Ingham word_complete = true; 87c9af18a5SGreg Clayton // Find some way to switch "include support files..." 88b9c1b51eSKate Stone SourceFileCompleter completer(interpreter, false, partial_file_name, 89b9c1b51eSKate Stone match_start_point, max_return_elements, 90c9af18a5SGreg Clayton matches); 91c9af18a5SGreg Clayton 92b9c1b51eSKate Stone if (searcher == nullptr) { 932976d00aSJim Ingham lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); 9433df7cd3SJim Ingham SearchFilterForUnconstrainedSearches null_searcher(target_sp); 95c9af18a5SGreg Clayton completer.DoCompletion(&null_searcher); 96b9c1b51eSKate Stone } else { 97c9af18a5SGreg Clayton completer.DoCompletion(searcher); 98c9af18a5SGreg Clayton } 99c9af18a5SGreg Clayton return matches.GetSize(); 100c9af18a5SGreg Clayton } 101c9af18a5SGreg Clayton 102b9c1b51eSKate Stone typedef struct DiskFilesOrDirectoriesBaton { 103b2f1fb29SVirgile Bello const char *remainder; 104b2f1fb29SVirgile Bello char *partial_name_copy; 105b2f1fb29SVirgile Bello bool only_directories; 106b2f1fb29SVirgile Bello bool *saw_directory; 107b2f1fb29SVirgile Bello StringList *matches; 108b2f1fb29SVirgile Bello char *end_ptr; 109b2f1fb29SVirgile Bello size_t baselen; 1100b5e5f43SMichael Sartain } DiskFilesOrDirectoriesBaton; 111b2f1fb29SVirgile Bello 112b9c1b51eSKate Stone FileSpec::EnumerateDirectoryResult 113*7d86ee5aSZachary Turner DiskFilesOrDirectoriesCallback(void *baton, llvm::sys::fs::file_type file_type, 114b9c1b51eSKate Stone const FileSpec &spec) { 115b2f1fb29SVirgile Bello const char *name = spec.GetFilename().AsCString(); 116b2f1fb29SVirgile Bello 117b9c1b51eSKate Stone const DiskFilesOrDirectoriesBaton *parameters = 118b9c1b51eSKate Stone (DiskFilesOrDirectoriesBaton *)baton; 119b2f1fb29SVirgile Bello char *end_ptr = parameters->end_ptr; 120b2f1fb29SVirgile Bello char *partial_name_copy = parameters->partial_name_copy; 121b2f1fb29SVirgile Bello const char *remainder = parameters->remainder; 122b2f1fb29SVirgile Bello 123b2f1fb29SVirgile Bello // Omit ".", ".." and any . files if the match string doesn't start with . 124b9c1b51eSKate Stone if (name[0] == '.') { 125b2f1fb29SVirgile Bello if (name[1] == '\0') 126b2f1fb29SVirgile Bello return FileSpec::eEnumerateDirectoryResultNext; 127b2f1fb29SVirgile Bello else if (name[1] == '.' && name[2] == '\0') 128b2f1fb29SVirgile Bello return FileSpec::eEnumerateDirectoryResultNext; 129b2f1fb29SVirgile Bello else if (remainder[0] != '.') 130b2f1fb29SVirgile Bello return FileSpec::eEnumerateDirectoryResultNext; 131b2f1fb29SVirgile Bello } 132b2f1fb29SVirgile Bello 133b2f1fb29SVirgile Bello // If we found a directory, we put a "/" at the end of the name. 134b2f1fb29SVirgile Bello 135b9c1b51eSKate Stone if (remainder[0] == '\0' || strstr(name, remainder) == name) { 136b2f1fb29SVirgile Bello if (strlen(name) + parameters->baselen >= PATH_MAX) 137b2f1fb29SVirgile Bello return FileSpec::eEnumerateDirectoryResultNext; 138b2f1fb29SVirgile Bello 139b2f1fb29SVirgile Bello strcpy(end_ptr, name); 140b2f1fb29SVirgile Bello 141*7d86ee5aSZachary Turner namespace fs = llvm::sys::fs; 142b2f1fb29SVirgile Bello bool isa_directory = false; 143*7d86ee5aSZachary Turner if (file_type == fs::file_type::directory_file) 144b2f1fb29SVirgile Bello isa_directory = true; 145*7d86ee5aSZachary Turner else if (file_type == fs::file_type::symlink_file) 146*7d86ee5aSZachary Turner isa_directory = fs::is_directory(partial_name_copy); 147b2f1fb29SVirgile Bello 148b9c1b51eSKate Stone if (isa_directory) { 149b2f1fb29SVirgile Bello *parameters->saw_directory = true; 150b2f1fb29SVirgile Bello size_t len = strlen(parameters->partial_name_copy); 151b2f1fb29SVirgile Bello partial_name_copy[len] = '/'; 152b2f1fb29SVirgile Bello partial_name_copy[len + 1] = '\0'; 153b2f1fb29SVirgile Bello } 154b2f1fb29SVirgile Bello if (parameters->only_directories && !isa_directory) 155b2f1fb29SVirgile Bello return FileSpec::eEnumerateDirectoryResultNext; 156b2f1fb29SVirgile Bello parameters->matches->AppendString(partial_name_copy); 157b2f1fb29SVirgile Bello } 158b2f1fb29SVirgile Bello 159b2f1fb29SVirgile Bello return FileSpec::eEnumerateDirectoryResultNext; 160b2f1fb29SVirgile Bello } 161b2f1fb29SVirgile Bello 1624aa8753cSZachary Turner static int DiskFilesOrDirectories(llvm::StringRef partial_file_name, 163b9c1b51eSKate Stone bool only_directories, bool &saw_directory, 164b9c1b51eSKate Stone StringList &matches) { 165b9c1b51eSKate Stone // I'm going to use the "glob" function with GLOB_TILDE for user directory 166b9c1b51eSKate Stone // expansion. 167b9c1b51eSKate Stone // If it is not defined on your host system, you'll need to implement it 168b9c1b51eSKate Stone // yourself... 169558ce124SJim Ingham 1704aa8753cSZachary Turner size_t partial_name_len = partial_file_name.size(); 171558ce124SJim Ingham 172558ce124SJim Ingham if (partial_name_len >= PATH_MAX) 173558ce124SJim Ingham return matches.GetSize(); 174558ce124SJim Ingham 175b9c1b51eSKate Stone // This copy of the string will be cut up into the directory part, and the 1764aa8753cSZachary Turner // remainder. end_ptr below will point to the place of the remainder in this 1774aa8753cSZachary Turner // string. Then when we've resolved the containing directory, and opened it, 1784aa8753cSZachary Turner // we'll read the directory contents and overwrite the partial_name_copy 1794aa8753cSZachary Turner // starting from end_ptr with each of the matches. Thus we will preserve the 1804aa8753cSZachary Turner // form the user originally typed. 181558ce124SJim Ingham 182558ce124SJim Ingham char partial_name_copy[PATH_MAX]; 1834aa8753cSZachary Turner memcpy(partial_name_copy, partial_file_name.data(), partial_name_len); 184558ce124SJim Ingham partial_name_copy[partial_name_len] = '\0'; 185558ce124SJim Ingham 186b9c1b51eSKate Stone // We'll need to save a copy of the remainder for comparison, which we do 187b9c1b51eSKate Stone // here. 188558ce124SJim Ingham char remainder[PATH_MAX]; 189558ce124SJim Ingham 190b9c1b51eSKate Stone // end_ptr will point past the last / in partial_name_copy, or if there is no 191b9c1b51eSKate Stone // slash to the beginning of the string. 192558ce124SJim Ingham char *end_ptr; 193558ce124SJim Ingham 194558ce124SJim Ingham end_ptr = strrchr(partial_name_copy, '/'); 195558ce124SJim Ingham 196558ce124SJim Ingham // This will store the resolved form of the containing directory 1973f559740SZachary Turner llvm::SmallString<64> containing_part; 198558ce124SJim Ingham 199b9c1b51eSKate Stone if (end_ptr == nullptr) { 200558ce124SJim Ingham // There's no directory. If the thing begins with a "~" then this is a bare 201558ce124SJim Ingham // user name. 202b9c1b51eSKate Stone if (*partial_name_copy == '~') { 203558ce124SJim Ingham // Nothing here but the user name. We could just put a slash on the end, 204b9c1b51eSKate Stone // but for completeness sake we'll resolve the user name and only put a 205b9c1b51eSKate Stone // slash 206558ce124SJim Ingham // on the end if it exists. 2073f559740SZachary Turner llvm::SmallString<64> resolved_username(partial_name_copy); 2083f559740SZachary Turner FileSpec::ResolveUsername(resolved_username); 2097cc478b9SJim Ingham 210b9c1b51eSKate Stone // Not sure how this would happen, a username longer than PATH_MAX? 211b9c1b51eSKate Stone // Still... 212b9c1b51eSKate Stone if (resolved_username.size() == 0) { 213b9c1b51eSKate Stone // The user name didn't resolve, let's look in the password database for 214b9c1b51eSKate Stone // matches. 215b9c1b51eSKate Stone // The user name database contains duplicates, and is not in 216b9c1b51eSKate Stone // alphabetical order, so 2177cc478b9SJim Ingham // we'll use a set to manage that for us. 21884363078SJim Ingham FileSpec::ResolvePartialUsername(partial_name_copy, matches); 21984363078SJim Ingham if (matches.GetSize() > 0) 2207cc478b9SJim Ingham saw_directory = true; 2217cc478b9SJim Ingham return matches.GetSize(); 222b9c1b51eSKate Stone } else { 223558ce124SJim Ingham // The thing exists, put a '/' on the end, and return it... 224558ce124SJim Ingham // FIXME: complete user names here: 225558ce124SJim Ingham partial_name_copy[partial_name_len] = '/'; 226558ce124SJim Ingham partial_name_copy[partial_name_len + 1] = '\0'; 227558ce124SJim Ingham matches.AppendString(partial_name_copy); 228021b605dSBenjamin Kramer saw_directory = true; 229558ce124SJim Ingham return matches.GetSize(); 230558ce124SJim Ingham } 231b9c1b51eSKate Stone } else { 232558ce124SJim Ingham // The containing part is the CWD, and the whole string is the remainder. 2333f559740SZachary Turner containing_part = "."; 234558ce124SJim Ingham strcpy(remainder, partial_name_copy); 235558ce124SJim Ingham end_ptr = partial_name_copy; 236558ce124SJim Ingham } 237b9c1b51eSKate Stone } else { 238b9c1b51eSKate Stone if (end_ptr == partial_name_copy) { 239558ce124SJim Ingham // We're completing a file or directory in the root volume. 2403f559740SZachary Turner containing_part = "/"; 241b9c1b51eSKate Stone } else { 2423f559740SZachary Turner containing_part.append(partial_name_copy, end_ptr); 243558ce124SJim Ingham } 244558ce124SJim Ingham // Push end_ptr past the final "/" and set remainder. 245558ce124SJim Ingham end_ptr++; 246558ce124SJim Ingham strcpy(remainder, end_ptr); 247558ce124SJim Ingham } 248558ce124SJim Ingham 249b9c1b51eSKate Stone // Look for a user name in the containing part, and if it's there, resolve it 250b9c1b51eSKate Stone // and stick the 251558ce124SJim Ingham // result back into the containing_part: 252558ce124SJim Ingham 253b9c1b51eSKate Stone if (*partial_name_copy == '~') { 2543f559740SZachary Turner FileSpec::ResolveUsername(containing_part); 255558ce124SJim Ingham // User name doesn't exist, we're not getting any further... 2563f559740SZachary Turner if (containing_part.empty()) 257558ce124SJim Ingham return matches.GetSize(); 258558ce124SJim Ingham } 259558ce124SJim Ingham 260b9c1b51eSKate Stone // Okay, containing_part is now the directory we want to open and look for 261b9c1b51eSKate Stone // files: 262558ce124SJim Ingham 263558ce124SJim Ingham size_t baselen = end_ptr - partial_name_copy; 264558ce124SJim Ingham 265b2f1fb29SVirgile Bello DiskFilesOrDirectoriesBaton parameters; 266b2f1fb29SVirgile Bello parameters.remainder = remainder; 267b2f1fb29SVirgile Bello parameters.partial_name_copy = partial_name_copy; 268b2f1fb29SVirgile Bello parameters.only_directories = only_directories; 269b2f1fb29SVirgile Bello parameters.saw_directory = &saw_directory; 270b2f1fb29SVirgile Bello parameters.matches = &matches; 271b2f1fb29SVirgile Bello parameters.end_ptr = end_ptr; 272b2f1fb29SVirgile Bello parameters.baselen = baselen; 273558ce124SJim Ingham 274b9c1b51eSKate Stone FileSpec::EnumerateDirectory(containing_part.c_str(), true, true, true, 275b9c1b51eSKate Stone DiskFilesOrDirectoriesCallback, ¶meters); 276558ce124SJim Ingham 277558ce124SJim Ingham return matches.GetSize(); 278558ce124SJim Ingham } 279558ce124SJim Ingham 280b9c1b51eSKate Stone int CommandCompletions::DiskFiles(CommandInterpreter &interpreter, 2814aa8753cSZachary Turner llvm::StringRef partial_file_name, 282558ce124SJim Ingham int match_start_point, 283558ce124SJim Ingham int max_return_elements, 284b9c1b51eSKate Stone SearchFilter *searcher, bool &word_complete, 285b9c1b51eSKate Stone StringList &matches) { 286b9c1b51eSKate Stone int ret_val = 287b9c1b51eSKate Stone DiskFilesOrDirectories(partial_file_name, false, word_complete, matches); 288558ce124SJim Ingham word_complete = !word_complete; 289558ce124SJim Ingham return ret_val; 290558ce124SJim Ingham } 291558ce124SJim Ingham 292b9c1b51eSKate Stone int CommandCompletions::DiskDirectories( 2934aa8753cSZachary Turner CommandInterpreter &interpreter, llvm::StringRef partial_file_name, 294b9c1b51eSKate Stone int match_start_point, int max_return_elements, SearchFilter *searcher, 295b9c1b51eSKate Stone bool &word_complete, StringList &matches) { 296b9c1b51eSKate Stone int ret_val = 297b9c1b51eSKate Stone DiskFilesOrDirectories(partial_file_name, true, word_complete, matches); 298558ce124SJim Ingham word_complete = false; 299558ce124SJim Ingham return ret_val; 300558ce124SJim Ingham } 301558ce124SJim Ingham 302b9c1b51eSKate Stone int CommandCompletions::Modules(CommandInterpreter &interpreter, 3034aa8753cSZachary Turner llvm::StringRef partial_file_name, 304b9c1b51eSKate Stone int match_start_point, int max_return_elements, 305b9c1b51eSKate Stone SearchFilter *searcher, bool &word_complete, 306b9c1b51eSKate Stone StringList &matches) { 307558ce124SJim Ingham word_complete = true; 308b9c1b51eSKate Stone ModuleCompleter completer(interpreter, partial_file_name, match_start_point, 309b9c1b51eSKate Stone max_return_elements, matches); 310c9af18a5SGreg Clayton 311b9c1b51eSKate Stone if (searcher == nullptr) { 3122976d00aSJim Ingham lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); 31333df7cd3SJim Ingham SearchFilterForUnconstrainedSearches null_searcher(target_sp); 314c9af18a5SGreg Clayton completer.DoCompletion(&null_searcher); 315b9c1b51eSKate Stone } else { 316c9af18a5SGreg Clayton completer.DoCompletion(searcher); 317c9af18a5SGreg Clayton } 318c9af18a5SGreg Clayton return matches.GetSize(); 319c9af18a5SGreg Clayton } 320c9af18a5SGreg Clayton 321b9c1b51eSKate Stone int CommandCompletions::Symbols(CommandInterpreter &interpreter, 3224aa8753cSZachary Turner llvm::StringRef partial_file_name, 323b9c1b51eSKate Stone int match_start_point, int max_return_elements, 324b9c1b51eSKate Stone SearchFilter *searcher, bool &word_complete, 325b9c1b51eSKate Stone StringList &matches) { 326558ce124SJim Ingham word_complete = true; 327b9c1b51eSKate Stone SymbolCompleter completer(interpreter, partial_file_name, match_start_point, 328b9c1b51eSKate Stone max_return_elements, matches); 329c9af18a5SGreg Clayton 330b9c1b51eSKate Stone if (searcher == nullptr) { 3312976d00aSJim Ingham lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); 33233df7cd3SJim Ingham SearchFilterForUnconstrainedSearches null_searcher(target_sp); 333c9af18a5SGreg Clayton completer.DoCompletion(&null_searcher); 334b9c1b51eSKate Stone } else { 335c9af18a5SGreg Clayton completer.DoCompletion(searcher); 336c9af18a5SGreg Clayton } 337c9af18a5SGreg Clayton return matches.GetSize(); 338c9af18a5SGreg Clayton } 339c9af18a5SGreg Clayton 340b9c1b51eSKate Stone int CommandCompletions::SettingsNames( 3414aa8753cSZachary Turner CommandInterpreter &interpreter, llvm::StringRef partial_setting_name, 342b9c1b51eSKate Stone int match_start_point, int max_return_elements, SearchFilter *searcher, 343b9c1b51eSKate Stone bool &word_complete, StringList &matches) { 34467cc0636SGreg Clayton // Cache the full setting name list 34567cc0636SGreg Clayton static StringList g_property_names; 346b9c1b51eSKate Stone if (g_property_names.GetSize() == 0) { 34767cc0636SGreg Clayton // Generate the full setting name list on demand 348b9c1b51eSKate Stone lldb::OptionValuePropertiesSP properties_sp( 349b9c1b51eSKate Stone interpreter.GetDebugger().GetValueProperties()); 350b9c1b51eSKate Stone if (properties_sp) { 35167cc0636SGreg Clayton StreamString strm; 352c8ecc2a9SEugene Zelenko properties_sp->DumpValue(nullptr, strm, OptionValue::eDumpOptionName); 35367cc0636SGreg Clayton const std::string &str = strm.GetString(); 35467cc0636SGreg Clayton g_property_names.SplitIntoLines(str.c_str(), str.size()); 35567cc0636SGreg Clayton } 35667cc0636SGreg Clayton } 3573df9a8dfSCaroline Tice 35867cc0636SGreg Clayton size_t exact_matches_idx = SIZE_MAX; 359b9c1b51eSKate Stone const size_t num_matches = g_property_names.AutoComplete( 360b9c1b51eSKate Stone partial_setting_name, matches, exact_matches_idx); 36167cc0636SGreg Clayton word_complete = exact_matches_idx != SIZE_MAX; 36267cc0636SGreg Clayton return num_matches; 3633df9a8dfSCaroline Tice } 3643df9a8dfSCaroline Tice 365b9c1b51eSKate Stone int CommandCompletions::PlatformPluginNames( 3664aa8753cSZachary Turner CommandInterpreter &interpreter, llvm::StringRef partial_name, 367b9c1b51eSKate Stone int match_start_point, int max_return_elements, SearchFilter *searcher, 368b9c1b51eSKate Stone bool &word_complete, lldb_private::StringList &matches) { 369b9c1b51eSKate Stone const uint32_t num_matches = 370b9c1b51eSKate Stone PluginManager::AutoCompletePlatformName(partial_name, matches); 371ab65b34fSGreg Clayton word_complete = num_matches == 1; 372ab65b34fSGreg Clayton return num_matches; 373ab65b34fSGreg Clayton } 374ab65b34fSGreg Clayton 375b9c1b51eSKate Stone int CommandCompletions::ArchitectureNames( 3764aa8753cSZachary Turner CommandInterpreter &interpreter, llvm::StringRef partial_name, 377b9c1b51eSKate Stone int match_start_point, int max_return_elements, SearchFilter *searcher, 378b9c1b51eSKate Stone bool &word_complete, lldb_private::StringList &matches) { 379ab65b34fSGreg Clayton const uint32_t num_matches = ArchSpec::AutoComplete(partial_name, matches); 380ab65b34fSGreg Clayton word_complete = num_matches == 1; 381ab65b34fSGreg Clayton return num_matches; 382ab65b34fSGreg Clayton } 383ab65b34fSGreg Clayton 384b9c1b51eSKate Stone int CommandCompletions::VariablePath( 3854aa8753cSZachary Turner CommandInterpreter &interpreter, llvm::StringRef partial_name, 386b9c1b51eSKate Stone int match_start_point, int max_return_elements, SearchFilter *searcher, 387b9c1b51eSKate Stone bool &word_complete, lldb_private::StringList &matches) { 388b9c1b51eSKate Stone return Variable::AutoComplete(interpreter.GetExecutionContext(), partial_name, 389b9c1b51eSKate Stone matches, word_complete); 390f21feadcSGreg Clayton } 391f21feadcSGreg Clayton 392c8ecc2a9SEugene Zelenko CommandCompletions::Completer::Completer(CommandInterpreter &interpreter, 3934aa8753cSZachary Turner llvm::StringRef completion_str, 394c9af18a5SGreg Clayton int match_start_point, 395c9af18a5SGreg Clayton int max_return_elements, 396b9c1b51eSKate Stone StringList &matches) 397b9c1b51eSKate Stone : m_interpreter(interpreter), m_completion_str(completion_str), 398c9af18a5SGreg Clayton m_match_start_point(match_start_point), 399b9c1b51eSKate Stone m_max_return_elements(max_return_elements), m_matches(matches) {} 400c9af18a5SGreg Clayton 401c8ecc2a9SEugene Zelenko CommandCompletions::Completer::~Completer() = default; 402c9af18a5SGreg Clayton 403c9af18a5SGreg Clayton //---------------------------------------------------------------------- 404c9af18a5SGreg Clayton // SourceFileCompleter 405c9af18a5SGreg Clayton //---------------------------------------------------------------------- 406c9af18a5SGreg Clayton 407b9c1b51eSKate Stone CommandCompletions::SourceFileCompleter::SourceFileCompleter( 408b9c1b51eSKate Stone CommandInterpreter &interpreter, bool include_support_files, 4094aa8753cSZachary Turner llvm::StringRef completion_str, int match_start_point, 4104aa8753cSZachary Turner int max_return_elements, StringList &matches) 411b9c1b51eSKate Stone : CommandCompletions::Completer(interpreter, completion_str, 412b9c1b51eSKate Stone match_start_point, max_return_elements, 413b9c1b51eSKate Stone matches), 414b9c1b51eSKate Stone m_include_support_files(include_support_files), m_matching_files() { 415771ef6d4SMalcolm Parsons FileSpec partial_spec(m_completion_str, false); 416c9af18a5SGreg Clayton m_file_name = partial_spec.GetFilename().GetCString(); 417c9af18a5SGreg Clayton m_dir_name = partial_spec.GetDirectory().GetCString(); 418c9af18a5SGreg Clayton } 419c9af18a5SGreg Clayton 420b9c1b51eSKate Stone Searcher::Depth CommandCompletions::SourceFileCompleter::GetDepth() { 421c9af18a5SGreg Clayton return eDepthCompUnit; 422c9af18a5SGreg Clayton } 423c9af18a5SGreg Clayton 424c9af18a5SGreg Clayton Searcher::CallbackReturn 425c8ecc2a9SEugene Zelenko CommandCompletions::SourceFileCompleter::SearchCallback(SearchFilter &filter, 426c9af18a5SGreg Clayton SymbolContext &context, 427c9af18a5SGreg Clayton Address *addr, 428b9c1b51eSKate Stone bool complete) { 429b9c1b51eSKate Stone if (context.comp_unit != nullptr) { 430b9c1b51eSKate Stone if (m_include_support_files) { 431c9af18a5SGreg Clayton FileSpecList supporting_files = context.comp_unit->GetSupportFiles(); 432b9c1b51eSKate Stone for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++) { 433b9c1b51eSKate Stone const FileSpec &sfile_spec = 434b9c1b51eSKate Stone supporting_files.GetFileSpecAtIndex(sfiles); 435c9af18a5SGreg Clayton const char *sfile_file_name = sfile_spec.GetFilename().GetCString(); 436c9af18a5SGreg Clayton const char *sfile_dir_name = sfile_spec.GetFilename().GetCString(); 437c9af18a5SGreg Clayton bool match = false; 438b9c1b51eSKate Stone if (m_file_name && sfile_file_name && 439b9c1b51eSKate Stone strstr(sfile_file_name, m_file_name) == sfile_file_name) 440c9af18a5SGreg Clayton match = true; 441b9c1b51eSKate Stone if (match && m_dir_name && sfile_dir_name && 442b9c1b51eSKate Stone strstr(sfile_dir_name, m_dir_name) != sfile_dir_name) 443c9af18a5SGreg Clayton match = false; 444c9af18a5SGreg Clayton 445b9c1b51eSKate Stone if (match) { 446c9af18a5SGreg Clayton m_matching_files.AppendIfUnique(sfile_spec); 447c9af18a5SGreg Clayton } 448c9af18a5SGreg Clayton } 449b9c1b51eSKate Stone } else { 450c9af18a5SGreg Clayton const char *cur_file_name = context.comp_unit->GetFilename().GetCString(); 451c9af18a5SGreg Clayton const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString(); 452c9af18a5SGreg Clayton 453c9af18a5SGreg Clayton bool match = false; 454b9c1b51eSKate Stone if (m_file_name && cur_file_name && 455b9c1b51eSKate Stone strstr(cur_file_name, m_file_name) == cur_file_name) 456c9af18a5SGreg Clayton match = true; 457c9af18a5SGreg Clayton 458b9c1b51eSKate Stone if (match && m_dir_name && cur_dir_name && 459b9c1b51eSKate Stone strstr(cur_dir_name, m_dir_name) != cur_dir_name) 460c9af18a5SGreg Clayton match = false; 461c9af18a5SGreg Clayton 462b9c1b51eSKate Stone if (match) { 463c9af18a5SGreg Clayton m_matching_files.AppendIfUnique(context.comp_unit); 464c9af18a5SGreg Clayton } 465c9af18a5SGreg Clayton } 466c9af18a5SGreg Clayton } 467c9af18a5SGreg Clayton return Searcher::eCallbackReturnContinue; 468c9af18a5SGreg Clayton } 469c9af18a5SGreg Clayton 470c9af18a5SGreg Clayton size_t 471b9c1b51eSKate Stone CommandCompletions::SourceFileCompleter::DoCompletion(SearchFilter *filter) { 472c9af18a5SGreg Clayton filter->Search(*this); 473c9af18a5SGreg Clayton // Now convert the filelist to completions: 474b9c1b51eSKate Stone for (size_t i = 0; i < m_matching_files.GetSize(); i++) { 475b9c1b51eSKate Stone m_matches.AppendString( 476b9c1b51eSKate Stone m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString()); 477c9af18a5SGreg Clayton } 478c9af18a5SGreg Clayton return m_matches.GetSize(); 479c9af18a5SGreg Clayton } 480c9af18a5SGreg Clayton 481c9af18a5SGreg Clayton //---------------------------------------------------------------------- 482c9af18a5SGreg Clayton // SymbolCompleter 483c9af18a5SGreg Clayton //---------------------------------------------------------------------- 484c9af18a5SGreg Clayton 485b9c1b51eSKate Stone static bool regex_chars(const char comp) { 486b9c1b51eSKate Stone return (comp == '[' || comp == ']' || comp == '(' || comp == ')' || 487b9c1b51eSKate Stone comp == '{' || comp == '}' || comp == '+' || comp == '.' || 488b9c1b51eSKate Stone comp == '*' || comp == '|' || comp == '^' || comp == '$' || 489b9c1b51eSKate Stone comp == '\\' || comp == '?'); 490c9af18a5SGreg Clayton } 491c8ecc2a9SEugene Zelenko 492b9c1b51eSKate Stone CommandCompletions::SymbolCompleter::SymbolCompleter( 4934aa8753cSZachary Turner CommandInterpreter &interpreter, llvm::StringRef completion_str, 494b9c1b51eSKate Stone int match_start_point, int max_return_elements, StringList &matches) 495b9c1b51eSKate Stone : CommandCompletions::Completer(interpreter, completion_str, 496b9c1b51eSKate Stone match_start_point, max_return_elements, 497b9c1b51eSKate Stone matches) { 498649f8b9bSGreg Clayton std::string regex_str; 4994aa8753cSZachary Turner if (!completion_str.empty()) { 500649f8b9bSGreg Clayton regex_str.append("^"); 501c9af18a5SGreg Clayton regex_str.append(completion_str); 502b9c1b51eSKate Stone } else { 503649f8b9bSGreg Clayton // Match anything since the completion string is empty 504649f8b9bSGreg Clayton regex_str.append("."); 505649f8b9bSGreg Clayton } 506b9c1b51eSKate Stone std::string::iterator pos = 507b9c1b51eSKate Stone find_if(regex_str.begin() + 1, regex_str.end(), regex_chars); 508b9c1b51eSKate Stone while (pos < regex_str.end()) { 509c9af18a5SGreg Clayton pos = regex_str.insert(pos, '\\'); 510649f8b9bSGreg Clayton pos = find_if(pos + 2, regex_str.end(), regex_chars); 511c9af18a5SGreg Clayton } 51295eae423SZachary Turner m_regex.Compile(regex_str); 513c9af18a5SGreg Clayton } 514c9af18a5SGreg Clayton 515b9c1b51eSKate Stone Searcher::Depth CommandCompletions::SymbolCompleter::GetDepth() { 516c9af18a5SGreg Clayton return eDepthModule; 517c9af18a5SGreg Clayton } 518c9af18a5SGreg Clayton 519b9c1b51eSKate Stone Searcher::CallbackReturn CommandCompletions::SymbolCompleter::SearchCallback( 520b9c1b51eSKate Stone SearchFilter &filter, SymbolContext &context, Address *addr, 521b9c1b51eSKate Stone bool complete) { 522b9c1b51eSKate Stone if (context.module_sp) { 523931180e6SGreg Clayton SymbolContextList sc_list; 524931180e6SGreg Clayton const bool include_symbols = true; 5259df05fbbSSean Callanan const bool include_inlines = true; 526931180e6SGreg Clayton const bool append = true; 527b9c1b51eSKate Stone context.module_sp->FindFunctions(m_regex, include_symbols, include_inlines, 528b9c1b51eSKate Stone append, sc_list); 529c9af18a5SGreg Clayton 530c9af18a5SGreg Clayton SymbolContext sc; 531c9af18a5SGreg Clayton // Now add the functions & symbols to the list - only add if unique: 532b9c1b51eSKate Stone for (uint32_t i = 0; i < sc_list.GetSize(); i++) { 533b9c1b51eSKate Stone if (sc_list.GetContextAtIndex(i, sc)) { 534530a413cSJim Ingham ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled); 535530a413cSJim Ingham if (!func_name.IsEmpty()) 536530a413cSJim Ingham m_match_set.insert(func_name); 537c9af18a5SGreg Clayton } 538c9af18a5SGreg Clayton } 539c9af18a5SGreg Clayton } 540c9af18a5SGreg Clayton return Searcher::eCallbackReturnContinue; 541c9af18a5SGreg Clayton } 542c9af18a5SGreg Clayton 543b9c1b51eSKate Stone size_t CommandCompletions::SymbolCompleter::DoCompletion(SearchFilter *filter) { 544c9af18a5SGreg Clayton filter->Search(*this); 545c9af18a5SGreg Clayton collection::iterator pos = m_match_set.begin(), end = m_match_set.end(); 546c9af18a5SGreg Clayton for (pos = m_match_set.begin(); pos != end; pos++) 547c9af18a5SGreg Clayton m_matches.AppendString((*pos).GetCString()); 548c9af18a5SGreg Clayton 549c9af18a5SGreg Clayton return m_matches.GetSize(); 550c9af18a5SGreg Clayton } 551c9af18a5SGreg Clayton 552c9af18a5SGreg Clayton //---------------------------------------------------------------------- 553c9af18a5SGreg Clayton // ModuleCompleter 554c9af18a5SGreg Clayton //---------------------------------------------------------------------- 555b9c1b51eSKate Stone CommandCompletions::ModuleCompleter::ModuleCompleter( 5564aa8753cSZachary Turner CommandInterpreter &interpreter, llvm::StringRef completion_str, 557b9c1b51eSKate Stone int match_start_point, int max_return_elements, StringList &matches) 558b9c1b51eSKate Stone : CommandCompletions::Completer(interpreter, completion_str, 559b9c1b51eSKate Stone match_start_point, max_return_elements, 560b9c1b51eSKate Stone matches) { 561771ef6d4SMalcolm Parsons FileSpec partial_spec(m_completion_str, false); 562c9af18a5SGreg Clayton m_file_name = partial_spec.GetFilename().GetCString(); 563c9af18a5SGreg Clayton m_dir_name = partial_spec.GetDirectory().GetCString(); 564c9af18a5SGreg Clayton } 565c9af18a5SGreg Clayton 566b9c1b51eSKate Stone Searcher::Depth CommandCompletions::ModuleCompleter::GetDepth() { 567c9af18a5SGreg Clayton return eDepthModule; 568c9af18a5SGreg Clayton } 569c9af18a5SGreg Clayton 570b9c1b51eSKate Stone Searcher::CallbackReturn CommandCompletions::ModuleCompleter::SearchCallback( 571b9c1b51eSKate Stone SearchFilter &filter, SymbolContext &context, Address *addr, 572b9c1b51eSKate Stone bool complete) { 573b9c1b51eSKate Stone if (context.module_sp) { 574b9c1b51eSKate Stone const char *cur_file_name = 575b9c1b51eSKate Stone context.module_sp->GetFileSpec().GetFilename().GetCString(); 576b9c1b51eSKate Stone const char *cur_dir_name = 577b9c1b51eSKate Stone context.module_sp->GetFileSpec().GetDirectory().GetCString(); 578c9af18a5SGreg Clayton 579c9af18a5SGreg Clayton bool match = false; 580b9c1b51eSKate Stone if (m_file_name && cur_file_name && 581b9c1b51eSKate Stone strstr(cur_file_name, m_file_name) == cur_file_name) 582c9af18a5SGreg Clayton match = true; 583c9af18a5SGreg Clayton 584b9c1b51eSKate Stone if (match && m_dir_name && cur_dir_name && 585b9c1b51eSKate Stone strstr(cur_dir_name, m_dir_name) != cur_dir_name) 586c9af18a5SGreg Clayton match = false; 587c9af18a5SGreg Clayton 588b9c1b51eSKate Stone if (match) { 589c9af18a5SGreg Clayton m_matches.AppendString(cur_file_name); 590c9af18a5SGreg Clayton } 591c9af18a5SGreg Clayton } 592c9af18a5SGreg Clayton return Searcher::eCallbackReturnContinue; 593c9af18a5SGreg Clayton } 594c9af18a5SGreg Clayton 595b9c1b51eSKate Stone size_t CommandCompletions::ModuleCompleter::DoCompletion(SearchFilter *filter) { 596c9af18a5SGreg Clayton filter->Search(*this); 597c9af18a5SGreg Clayton return m_matches.GetSize(); 598c9af18a5SGreg Clayton } 599