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"
36190fadcdSZachary Turner 
37c9af18a5SGreg Clayton using namespace lldb_private;
38c9af18a5SGreg Clayton 
39c9af18a5SGreg Clayton CommandCompletions::CommonCompletionElement
40b9c1b51eSKate Stone     CommandCompletions::g_common_completions[] = {
41c8ecc2a9SEugene Zelenko         {eCustomCompletion, nullptr},
42c9af18a5SGreg Clayton         {eSourceFileCompletion, CommandCompletions::SourceFiles},
43558ce124SJim Ingham         {eDiskFileCompletion, CommandCompletions::DiskFiles},
44558ce124SJim Ingham         {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
45c9af18a5SGreg Clayton         {eSymbolCompletion, CommandCompletions::Symbols},
46c9af18a5SGreg Clayton         {eModuleCompletion, CommandCompletions::Modules},
473df9a8dfSCaroline Tice         {eSettingsNameCompletion, CommandCompletions::SettingsNames},
48ab65b34fSGreg Clayton         {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames},
49ab65b34fSGreg Clayton         {eArchitectureCompletion, CommandCompletions::ArchitectureNames},
50f21feadcSGreg Clayton         {eVariablePathCompletion, CommandCompletions::VariablePath},
51c8ecc2a9SEugene Zelenko         {eNoCompletion, nullptr} // This one has to be last in the list.
52c9af18a5SGreg Clayton };
53c9af18a5SGreg Clayton 
54b9c1b51eSKate Stone bool CommandCompletions::InvokeCommonCompletionCallbacks(
55b9c1b51eSKate Stone     CommandInterpreter &interpreter, uint32_t completion_mask,
56*4aa8753cSZachary Turner     llvm::StringRef completion_str, int match_start_point,
57*4aa8753cSZachary Turner     int max_return_elements, SearchFilter *searcher, bool &word_complete,
58*4aa8753cSZachary Turner     StringList &matches) {
59c9af18a5SGreg Clayton   bool handled = false;
60c9af18a5SGreg Clayton 
61c9af18a5SGreg Clayton   if (completion_mask & eCustomCompletion)
62c9af18a5SGreg Clayton     return false;
63c9af18a5SGreg Clayton 
64b9c1b51eSKate Stone   for (int i = 0;; i++) {
65c9af18a5SGreg Clayton     if (g_common_completions[i].type == eNoCompletion)
66c9af18a5SGreg Clayton       break;
67b9c1b51eSKate Stone     else if ((g_common_completions[i].type & completion_mask) ==
68b9c1b51eSKate Stone                  g_common_completions[i].type &&
69b9c1b51eSKate Stone              g_common_completions[i].callback != nullptr) {
70c9af18a5SGreg Clayton       handled = true;
71b9c1b51eSKate Stone       g_common_completions[i].callback(interpreter, completion_str,
72b9c1b51eSKate Stone                                        match_start_point, max_return_elements,
73b9c1b51eSKate Stone                                        searcher, word_complete, matches);
74c9af18a5SGreg Clayton     }
75c9af18a5SGreg Clayton   }
76c9af18a5SGreg Clayton   return handled;
77c9af18a5SGreg Clayton }
78c9af18a5SGreg Clayton 
79b9c1b51eSKate Stone int CommandCompletions::SourceFiles(CommandInterpreter &interpreter,
80*4aa8753cSZachary Turner                                     llvm::StringRef partial_file_name,
81c9af18a5SGreg Clayton                                     int match_start_point,
82c9af18a5SGreg Clayton                                     int max_return_elements,
83b9c1b51eSKate Stone                                     SearchFilter *searcher, bool &word_complete,
84b9c1b51eSKate Stone                                     StringList &matches) {
85558ce124SJim Ingham   word_complete = true;
86c9af18a5SGreg Clayton   // Find some way to switch "include support files..."
87b9c1b51eSKate Stone   SourceFileCompleter completer(interpreter, false, partial_file_name,
88b9c1b51eSKate Stone                                 match_start_point, max_return_elements,
89c9af18a5SGreg Clayton                                 matches);
90c9af18a5SGreg Clayton 
91b9c1b51eSKate Stone   if (searcher == nullptr) {
922976d00aSJim Ingham     lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
9333df7cd3SJim Ingham     SearchFilterForUnconstrainedSearches null_searcher(target_sp);
94c9af18a5SGreg Clayton     completer.DoCompletion(&null_searcher);
95b9c1b51eSKate Stone   } else {
96c9af18a5SGreg Clayton     completer.DoCompletion(searcher);
97c9af18a5SGreg Clayton   }
98c9af18a5SGreg Clayton   return matches.GetSize();
99c9af18a5SGreg Clayton }
100c9af18a5SGreg Clayton 
101b9c1b51eSKate Stone typedef struct DiskFilesOrDirectoriesBaton {
102b2f1fb29SVirgile Bello   const char *remainder;
103b2f1fb29SVirgile Bello   char *partial_name_copy;
104b2f1fb29SVirgile Bello   bool only_directories;
105b2f1fb29SVirgile Bello   bool *saw_directory;
106b2f1fb29SVirgile Bello   StringList *matches;
107b2f1fb29SVirgile Bello   char *end_ptr;
108b2f1fb29SVirgile Bello   size_t baselen;
1090b5e5f43SMichael Sartain } DiskFilesOrDirectoriesBaton;
110b2f1fb29SVirgile Bello 
111b9c1b51eSKate Stone FileSpec::EnumerateDirectoryResult
112b9c1b51eSKate Stone DiskFilesOrDirectoriesCallback(void *baton, FileSpec::FileType file_type,
113b9c1b51eSKate Stone                                const FileSpec &spec) {
114b2f1fb29SVirgile Bello   const char *name = spec.GetFilename().AsCString();
115b2f1fb29SVirgile Bello 
116b9c1b51eSKate Stone   const DiskFilesOrDirectoriesBaton *parameters =
117b9c1b51eSKate Stone       (DiskFilesOrDirectoriesBaton *)baton;
118b2f1fb29SVirgile Bello   char *end_ptr = parameters->end_ptr;
119b2f1fb29SVirgile Bello   char *partial_name_copy = parameters->partial_name_copy;
120b2f1fb29SVirgile Bello   const char *remainder = parameters->remainder;
121b2f1fb29SVirgile Bello 
122b2f1fb29SVirgile Bello   // Omit ".", ".." and any . files if the match string doesn't start with .
123b9c1b51eSKate Stone   if (name[0] == '.') {
124b2f1fb29SVirgile Bello     if (name[1] == '\0')
125b2f1fb29SVirgile Bello       return FileSpec::eEnumerateDirectoryResultNext;
126b2f1fb29SVirgile Bello     else if (name[1] == '.' && name[2] == '\0')
127b2f1fb29SVirgile Bello       return FileSpec::eEnumerateDirectoryResultNext;
128b2f1fb29SVirgile Bello     else if (remainder[0] != '.')
129b2f1fb29SVirgile Bello       return FileSpec::eEnumerateDirectoryResultNext;
130b2f1fb29SVirgile Bello   }
131b2f1fb29SVirgile Bello 
132b2f1fb29SVirgile Bello   // If we found a directory, we put a "/" at the end of the name.
133b2f1fb29SVirgile Bello 
134b9c1b51eSKate Stone   if (remainder[0] == '\0' || strstr(name, remainder) == name) {
135b2f1fb29SVirgile Bello     if (strlen(name) + parameters->baselen >= PATH_MAX)
136b2f1fb29SVirgile Bello       return FileSpec::eEnumerateDirectoryResultNext;
137b2f1fb29SVirgile Bello 
138b2f1fb29SVirgile Bello     strcpy(end_ptr, name);
139b2f1fb29SVirgile Bello 
140b2f1fb29SVirgile Bello     bool isa_directory = false;
141b2f1fb29SVirgile Bello     if (file_type == FileSpec::eFileTypeDirectory)
142b2f1fb29SVirgile Bello       isa_directory = true;
143b9c1b51eSKate Stone     else if (file_type == FileSpec::eFileTypeSymbolicLink) {
144190fadcdSZachary Turner       if (FileSpec(partial_name_copy, false).IsDirectory())
145b2f1fb29SVirgile Bello         isa_directory = true;
146b2f1fb29SVirgile Bello     }
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 
162*4aa8753cSZachary 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 
170*4aa8753cSZachary 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
176*4aa8753cSZachary Turner   // remainder.  end_ptr below will point to the place of the remainder in this
177*4aa8753cSZachary Turner   // string.  Then when we've resolved the containing directory, and opened it,
178*4aa8753cSZachary Turner   // we'll read the directory contents and overwrite the partial_name_copy
179*4aa8753cSZachary Turner   // starting from end_ptr with each of the matches.  Thus we will preserve the
180*4aa8753cSZachary Turner   // form the user originally typed.
181558ce124SJim Ingham 
182558ce124SJim Ingham   char partial_name_copy[PATH_MAX];
183*4aa8753cSZachary 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, &parameters);
276558ce124SJim Ingham 
277558ce124SJim Ingham   return matches.GetSize();
278558ce124SJim Ingham }
279558ce124SJim Ingham 
280b9c1b51eSKate Stone int CommandCompletions::DiskFiles(CommandInterpreter &interpreter,
281*4aa8753cSZachary 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(
293*4aa8753cSZachary 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,
303*4aa8753cSZachary 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,
322*4aa8753cSZachary 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(
341*4aa8753cSZachary 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(
366*4aa8753cSZachary 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(
376*4aa8753cSZachary 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(
385*4aa8753cSZachary 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,
393*4aa8753cSZachary 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,
409*4aa8753cSZachary Turner     llvm::StringRef completion_str, int match_start_point,
410*4aa8753cSZachary 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(
493*4aa8753cSZachary 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;
499*4aa8753cSZachary 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(
556*4aa8753cSZachary 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