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
40*b9c1b51eSKate 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 
54*b9c1b51eSKate Stone bool CommandCompletions::InvokeCommonCompletionCallbacks(
55*b9c1b51eSKate Stone     CommandInterpreter &interpreter, uint32_t completion_mask,
56*b9c1b51eSKate Stone     const char *completion_str, int match_start_point, int max_return_elements,
57*b9c1b51eSKate Stone     SearchFilter *searcher, bool &word_complete, StringList &matches) {
58c9af18a5SGreg Clayton   bool handled = false;
59c9af18a5SGreg Clayton 
60c9af18a5SGreg Clayton   if (completion_mask & eCustomCompletion)
61c9af18a5SGreg Clayton     return false;
62c9af18a5SGreg Clayton 
63*b9c1b51eSKate Stone   for (int i = 0;; i++) {
64c9af18a5SGreg Clayton     if (g_common_completions[i].type == eNoCompletion)
65c9af18a5SGreg Clayton       break;
66*b9c1b51eSKate Stone     else if ((g_common_completions[i].type & completion_mask) ==
67*b9c1b51eSKate Stone                  g_common_completions[i].type &&
68*b9c1b51eSKate Stone              g_common_completions[i].callback != nullptr) {
69c9af18a5SGreg Clayton       handled = true;
70*b9c1b51eSKate Stone       g_common_completions[i].callback(interpreter, completion_str,
71*b9c1b51eSKate Stone                                        match_start_point, max_return_elements,
72*b9c1b51eSKate Stone                                        searcher, word_complete, matches);
73c9af18a5SGreg Clayton     }
74c9af18a5SGreg Clayton   }
75c9af18a5SGreg Clayton   return handled;
76c9af18a5SGreg Clayton }
77c9af18a5SGreg Clayton 
78*b9c1b51eSKate Stone int CommandCompletions::SourceFiles(CommandInterpreter &interpreter,
796611103cSGreg Clayton                                     const char *partial_file_name,
80c9af18a5SGreg Clayton                                     int match_start_point,
81c9af18a5SGreg Clayton                                     int max_return_elements,
82*b9c1b51eSKate Stone                                     SearchFilter *searcher, bool &word_complete,
83*b9c1b51eSKate Stone                                     StringList &matches) {
84558ce124SJim Ingham   word_complete = true;
85c9af18a5SGreg Clayton   // Find some way to switch "include support files..."
86*b9c1b51eSKate Stone   SourceFileCompleter completer(interpreter, false, partial_file_name,
87*b9c1b51eSKate Stone                                 match_start_point, max_return_elements,
88c9af18a5SGreg Clayton                                 matches);
89c9af18a5SGreg Clayton 
90*b9c1b51eSKate Stone   if (searcher == nullptr) {
912976d00aSJim Ingham     lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
9233df7cd3SJim Ingham     SearchFilterForUnconstrainedSearches null_searcher(target_sp);
93c9af18a5SGreg Clayton     completer.DoCompletion(&null_searcher);
94*b9c1b51eSKate Stone   } else {
95c9af18a5SGreg Clayton     completer.DoCompletion(searcher);
96c9af18a5SGreg Clayton   }
97c9af18a5SGreg Clayton   return matches.GetSize();
98c9af18a5SGreg Clayton }
99c9af18a5SGreg Clayton 
100*b9c1b51eSKate Stone typedef struct DiskFilesOrDirectoriesBaton {
101b2f1fb29SVirgile Bello   const char *remainder;
102b2f1fb29SVirgile Bello   char *partial_name_copy;
103b2f1fb29SVirgile Bello   bool only_directories;
104b2f1fb29SVirgile Bello   bool *saw_directory;
105b2f1fb29SVirgile Bello   StringList *matches;
106b2f1fb29SVirgile Bello   char *end_ptr;
107b2f1fb29SVirgile Bello   size_t baselen;
1080b5e5f43SMichael Sartain } DiskFilesOrDirectoriesBaton;
109b2f1fb29SVirgile Bello 
110*b9c1b51eSKate Stone FileSpec::EnumerateDirectoryResult
111*b9c1b51eSKate Stone DiskFilesOrDirectoriesCallback(void *baton, FileSpec::FileType file_type,
112*b9c1b51eSKate Stone                                const FileSpec &spec) {
113b2f1fb29SVirgile Bello   const char *name = spec.GetFilename().AsCString();
114b2f1fb29SVirgile Bello 
115*b9c1b51eSKate Stone   const DiskFilesOrDirectoriesBaton *parameters =
116*b9c1b51eSKate Stone       (DiskFilesOrDirectoriesBaton *)baton;
117b2f1fb29SVirgile Bello   char *end_ptr = parameters->end_ptr;
118b2f1fb29SVirgile Bello   char *partial_name_copy = parameters->partial_name_copy;
119b2f1fb29SVirgile Bello   const char *remainder = parameters->remainder;
120b2f1fb29SVirgile Bello 
121b2f1fb29SVirgile Bello   // Omit ".", ".." and any . files if the match string doesn't start with .
122*b9c1b51eSKate Stone   if (name[0] == '.') {
123b2f1fb29SVirgile Bello     if (name[1] == '\0')
124b2f1fb29SVirgile Bello       return FileSpec::eEnumerateDirectoryResultNext;
125b2f1fb29SVirgile Bello     else if (name[1] == '.' && name[2] == '\0')
126b2f1fb29SVirgile Bello       return FileSpec::eEnumerateDirectoryResultNext;
127b2f1fb29SVirgile Bello     else if (remainder[0] != '.')
128b2f1fb29SVirgile Bello       return FileSpec::eEnumerateDirectoryResultNext;
129b2f1fb29SVirgile Bello   }
130b2f1fb29SVirgile Bello 
131b2f1fb29SVirgile Bello   // If we found a directory, we put a "/" at the end of the name.
132b2f1fb29SVirgile Bello 
133*b9c1b51eSKate Stone   if (remainder[0] == '\0' || strstr(name, remainder) == name) {
134b2f1fb29SVirgile Bello     if (strlen(name) + parameters->baselen >= PATH_MAX)
135b2f1fb29SVirgile Bello       return FileSpec::eEnumerateDirectoryResultNext;
136b2f1fb29SVirgile Bello 
137b2f1fb29SVirgile Bello     strcpy(end_ptr, name);
138b2f1fb29SVirgile Bello 
139b2f1fb29SVirgile Bello     bool isa_directory = false;
140b2f1fb29SVirgile Bello     if (file_type == FileSpec::eFileTypeDirectory)
141b2f1fb29SVirgile Bello       isa_directory = true;
142*b9c1b51eSKate Stone     else if (file_type == FileSpec::eFileTypeSymbolicLink) {
143190fadcdSZachary Turner       if (FileSpec(partial_name_copy, false).IsDirectory())
144b2f1fb29SVirgile Bello         isa_directory = true;
145b2f1fb29SVirgile Bello     }
146b2f1fb29SVirgile Bello 
147*b9c1b51eSKate Stone     if (isa_directory) {
148b2f1fb29SVirgile Bello       *parameters->saw_directory = true;
149b2f1fb29SVirgile Bello       size_t len = strlen(parameters->partial_name_copy);
150b2f1fb29SVirgile Bello       partial_name_copy[len] = '/';
151b2f1fb29SVirgile Bello       partial_name_copy[len + 1] = '\0';
152b2f1fb29SVirgile Bello     }
153b2f1fb29SVirgile Bello     if (parameters->only_directories && !isa_directory)
154b2f1fb29SVirgile Bello       return FileSpec::eEnumerateDirectoryResultNext;
155b2f1fb29SVirgile Bello     parameters->matches->AppendString(partial_name_copy);
156b2f1fb29SVirgile Bello   }
157b2f1fb29SVirgile Bello 
158b2f1fb29SVirgile Bello   return FileSpec::eEnumerateDirectoryResultNext;
159b2f1fb29SVirgile Bello }
160b2f1fb29SVirgile Bello 
161*b9c1b51eSKate Stone static int DiskFilesOrDirectories(const char *partial_file_name,
162*b9c1b51eSKate Stone                                   bool only_directories, bool &saw_directory,
163*b9c1b51eSKate Stone                                   StringList &matches) {
164*b9c1b51eSKate Stone   // I'm going to  use the "glob" function with GLOB_TILDE for user directory
165*b9c1b51eSKate Stone   // expansion.
166*b9c1b51eSKate Stone   // If it is not defined on your host system, you'll need to implement it
167*b9c1b51eSKate Stone   // yourself...
168558ce124SJim Ingham 
169c7bece56SGreg Clayton   size_t partial_name_len = strlen(partial_file_name);
170558ce124SJim Ingham 
171558ce124SJim Ingham   if (partial_name_len >= PATH_MAX)
172558ce124SJim Ingham     return matches.GetSize();
173558ce124SJim Ingham 
174*b9c1b51eSKate Stone   // This copy of the string will be cut up into the directory part, and the
175*b9c1b51eSKate Stone   // remainder.  end_ptr
176*b9c1b51eSKate Stone   // below will point to the place of the remainder in this string.  Then when
177*b9c1b51eSKate Stone   // we've resolved the
178*b9c1b51eSKate Stone   // containing directory, and opened it, we'll read the directory contents and
179*b9c1b51eSKate Stone   // overwrite the
180*b9c1b51eSKate Stone   // partial_name_copy starting from end_ptr with each of the matches.  Thus we
181*b9c1b51eSKate Stone   // will preserve
182558ce124SJim Ingham   // the form the user originally typed.
183558ce124SJim Ingham 
184558ce124SJim Ingham   char partial_name_copy[PATH_MAX];
185021b605dSBenjamin Kramer   memcpy(partial_name_copy, partial_file_name, partial_name_len);
186558ce124SJim Ingham   partial_name_copy[partial_name_len] = '\0';
187558ce124SJim Ingham 
188*b9c1b51eSKate Stone   // We'll need to save a copy of the remainder for comparison, which we do
189*b9c1b51eSKate Stone   // here.
190558ce124SJim Ingham   char remainder[PATH_MAX];
191558ce124SJim Ingham 
192*b9c1b51eSKate Stone   // end_ptr will point past the last / in partial_name_copy, or if there is no
193*b9c1b51eSKate Stone   // slash to the beginning of the string.
194558ce124SJim Ingham   char *end_ptr;
195558ce124SJim Ingham 
196558ce124SJim Ingham   end_ptr = strrchr(partial_name_copy, '/');
197558ce124SJim Ingham 
198558ce124SJim Ingham   // This will store the resolved form of the containing directory
1993f559740SZachary Turner   llvm::SmallString<64> containing_part;
200558ce124SJim Ingham 
201*b9c1b51eSKate Stone   if (end_ptr == nullptr) {
202558ce124SJim Ingham     // There's no directory.  If the thing begins with a "~" then this is a bare
203558ce124SJim Ingham     // user name.
204*b9c1b51eSKate Stone     if (*partial_name_copy == '~') {
205558ce124SJim Ingham       // Nothing here but the user name.  We could just put a slash on the end,
206*b9c1b51eSKate Stone       // but for completeness sake we'll resolve the user name and only put a
207*b9c1b51eSKate Stone       // slash
208558ce124SJim Ingham       // on the end if it exists.
2093f559740SZachary Turner       llvm::SmallString<64> resolved_username(partial_name_copy);
2103f559740SZachary Turner       FileSpec::ResolveUsername(resolved_username);
2117cc478b9SJim Ingham 
212*b9c1b51eSKate Stone       // Not sure how this would happen, a username longer than PATH_MAX?
213*b9c1b51eSKate Stone       // Still...
214*b9c1b51eSKate Stone       if (resolved_username.size() == 0) {
215*b9c1b51eSKate Stone         // The user name didn't resolve, let's look in the password database for
216*b9c1b51eSKate Stone         // matches.
217*b9c1b51eSKate Stone         // The user name database contains duplicates, and is not in
218*b9c1b51eSKate Stone         // alphabetical order, so
2197cc478b9SJim Ingham         // we'll use a set to manage that for us.
22084363078SJim Ingham         FileSpec::ResolvePartialUsername(partial_name_copy, matches);
22184363078SJim Ingham         if (matches.GetSize() > 0)
2227cc478b9SJim Ingham           saw_directory = true;
2237cc478b9SJim Ingham         return matches.GetSize();
224*b9c1b51eSKate Stone       } else {
225558ce124SJim Ingham         // The thing exists, put a '/' on the end, and return it...
226558ce124SJim Ingham         // FIXME: complete user names here:
227558ce124SJim Ingham         partial_name_copy[partial_name_len] = '/';
228558ce124SJim Ingham         partial_name_copy[partial_name_len + 1] = '\0';
229558ce124SJim Ingham         matches.AppendString(partial_name_copy);
230021b605dSBenjamin Kramer         saw_directory = true;
231558ce124SJim Ingham         return matches.GetSize();
232558ce124SJim Ingham       }
233*b9c1b51eSKate Stone     } else {
234558ce124SJim Ingham       // The containing part is the CWD, and the whole string is the remainder.
2353f559740SZachary Turner       containing_part = ".";
236558ce124SJim Ingham       strcpy(remainder, partial_name_copy);
237558ce124SJim Ingham       end_ptr = partial_name_copy;
238558ce124SJim Ingham     }
239*b9c1b51eSKate Stone   } else {
240*b9c1b51eSKate Stone     if (end_ptr == partial_name_copy) {
241558ce124SJim Ingham       // We're completing a file or directory in the root volume.
2423f559740SZachary Turner       containing_part = "/";
243*b9c1b51eSKate Stone     } else {
2443f559740SZachary Turner       containing_part.append(partial_name_copy, end_ptr);
245558ce124SJim Ingham     }
246558ce124SJim Ingham     // Push end_ptr past the final "/" and set remainder.
247558ce124SJim Ingham     end_ptr++;
248558ce124SJim Ingham     strcpy(remainder, end_ptr);
249558ce124SJim Ingham   }
250558ce124SJim Ingham 
251*b9c1b51eSKate Stone   // Look for a user name in the containing part, and if it's there, resolve it
252*b9c1b51eSKate Stone   // and stick the
253558ce124SJim Ingham   // result back into the containing_part:
254558ce124SJim Ingham 
255*b9c1b51eSKate Stone   if (*partial_name_copy == '~') {
2563f559740SZachary Turner     FileSpec::ResolveUsername(containing_part);
257558ce124SJim Ingham     // User name doesn't exist, we're not getting any further...
2583f559740SZachary Turner     if (containing_part.empty())
259558ce124SJim Ingham       return matches.GetSize();
260558ce124SJim Ingham   }
261558ce124SJim Ingham 
262*b9c1b51eSKate Stone   // Okay, containing_part is now the directory we want to open and look for
263*b9c1b51eSKate Stone   // files:
264558ce124SJim Ingham 
265558ce124SJim Ingham   size_t baselen = end_ptr - partial_name_copy;
266558ce124SJim Ingham 
267b2f1fb29SVirgile Bello   DiskFilesOrDirectoriesBaton parameters;
268b2f1fb29SVirgile Bello   parameters.remainder = remainder;
269b2f1fb29SVirgile Bello   parameters.partial_name_copy = partial_name_copy;
270b2f1fb29SVirgile Bello   parameters.only_directories = only_directories;
271b2f1fb29SVirgile Bello   parameters.saw_directory = &saw_directory;
272b2f1fb29SVirgile Bello   parameters.matches = &matches;
273b2f1fb29SVirgile Bello   parameters.end_ptr = end_ptr;
274b2f1fb29SVirgile Bello   parameters.baselen = baselen;
275558ce124SJim Ingham 
276*b9c1b51eSKate Stone   FileSpec::EnumerateDirectory(containing_part.c_str(), true, true, true,
277*b9c1b51eSKate Stone                                DiskFilesOrDirectoriesCallback, &parameters);
278558ce124SJim Ingham 
279558ce124SJim Ingham   return matches.GetSize();
280558ce124SJim Ingham }
281558ce124SJim Ingham 
282*b9c1b51eSKate Stone int CommandCompletions::DiskFiles(CommandInterpreter &interpreter,
283558ce124SJim Ingham                                   const char *partial_file_name,
284558ce124SJim Ingham                                   int match_start_point,
285558ce124SJim Ingham                                   int max_return_elements,
286*b9c1b51eSKate Stone                                   SearchFilter *searcher, bool &word_complete,
287*b9c1b51eSKate Stone                                   StringList &matches) {
288*b9c1b51eSKate Stone   int ret_val =
289*b9c1b51eSKate Stone       DiskFilesOrDirectories(partial_file_name, false, word_complete, matches);
290558ce124SJim Ingham   word_complete = !word_complete;
291558ce124SJim Ingham   return ret_val;
292558ce124SJim Ingham }
293558ce124SJim Ingham 
294*b9c1b51eSKate Stone int CommandCompletions::DiskDirectories(
295*b9c1b51eSKate Stone     CommandInterpreter &interpreter, const char *partial_file_name,
296*b9c1b51eSKate Stone     int match_start_point, int max_return_elements, SearchFilter *searcher,
297*b9c1b51eSKate Stone     bool &word_complete, StringList &matches) {
298*b9c1b51eSKate Stone   int ret_val =
299*b9c1b51eSKate Stone       DiskFilesOrDirectories(partial_file_name, true, word_complete, matches);
300558ce124SJim Ingham   word_complete = false;
301558ce124SJim Ingham   return ret_val;
302558ce124SJim Ingham }
303558ce124SJim Ingham 
304*b9c1b51eSKate Stone int CommandCompletions::Modules(CommandInterpreter &interpreter,
3056611103cSGreg Clayton                                 const char *partial_file_name,
306*b9c1b51eSKate Stone                                 int match_start_point, int max_return_elements,
307*b9c1b51eSKate Stone                                 SearchFilter *searcher, bool &word_complete,
308*b9c1b51eSKate Stone                                 StringList &matches) {
309558ce124SJim Ingham   word_complete = true;
310*b9c1b51eSKate Stone   ModuleCompleter completer(interpreter, partial_file_name, match_start_point,
311*b9c1b51eSKate Stone                             max_return_elements, matches);
312c9af18a5SGreg Clayton 
313*b9c1b51eSKate Stone   if (searcher == nullptr) {
3142976d00aSJim Ingham     lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
31533df7cd3SJim Ingham     SearchFilterForUnconstrainedSearches null_searcher(target_sp);
316c9af18a5SGreg Clayton     completer.DoCompletion(&null_searcher);
317*b9c1b51eSKate Stone   } else {
318c9af18a5SGreg Clayton     completer.DoCompletion(searcher);
319c9af18a5SGreg Clayton   }
320c9af18a5SGreg Clayton   return matches.GetSize();
321c9af18a5SGreg Clayton }
322c9af18a5SGreg Clayton 
323*b9c1b51eSKate Stone int CommandCompletions::Symbols(CommandInterpreter &interpreter,
3246611103cSGreg Clayton                                 const char *partial_file_name,
325*b9c1b51eSKate Stone                                 int match_start_point, int max_return_elements,
326*b9c1b51eSKate Stone                                 SearchFilter *searcher, bool &word_complete,
327*b9c1b51eSKate Stone                                 StringList &matches) {
328558ce124SJim Ingham   word_complete = true;
329*b9c1b51eSKate Stone   SymbolCompleter completer(interpreter, partial_file_name, match_start_point,
330*b9c1b51eSKate Stone                             max_return_elements, matches);
331c9af18a5SGreg Clayton 
332*b9c1b51eSKate Stone   if (searcher == nullptr) {
3332976d00aSJim Ingham     lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
33433df7cd3SJim Ingham     SearchFilterForUnconstrainedSearches null_searcher(target_sp);
335c9af18a5SGreg Clayton     completer.DoCompletion(&null_searcher);
336*b9c1b51eSKate Stone   } else {
337c9af18a5SGreg Clayton     completer.DoCompletion(searcher);
338c9af18a5SGreg Clayton   }
339c9af18a5SGreg Clayton   return matches.GetSize();
340c9af18a5SGreg Clayton }
341c9af18a5SGreg Clayton 
342*b9c1b51eSKate Stone int CommandCompletions::SettingsNames(
343*b9c1b51eSKate Stone     CommandInterpreter &interpreter, const char *partial_setting_name,
344*b9c1b51eSKate Stone     int match_start_point, int max_return_elements, SearchFilter *searcher,
345*b9c1b51eSKate Stone     bool &word_complete, StringList &matches) {
34667cc0636SGreg Clayton   // Cache the full setting name list
34767cc0636SGreg Clayton   static StringList g_property_names;
348*b9c1b51eSKate Stone   if (g_property_names.GetSize() == 0) {
34967cc0636SGreg Clayton     // Generate the full setting name list on demand
350*b9c1b51eSKate Stone     lldb::OptionValuePropertiesSP properties_sp(
351*b9c1b51eSKate Stone         interpreter.GetDebugger().GetValueProperties());
352*b9c1b51eSKate Stone     if (properties_sp) {
35367cc0636SGreg Clayton       StreamString strm;
354c8ecc2a9SEugene Zelenko       properties_sp->DumpValue(nullptr, strm, OptionValue::eDumpOptionName);
35567cc0636SGreg Clayton       const std::string &str = strm.GetString();
35667cc0636SGreg Clayton       g_property_names.SplitIntoLines(str.c_str(), str.size());
35767cc0636SGreg Clayton     }
35867cc0636SGreg Clayton   }
3593df9a8dfSCaroline Tice 
36067cc0636SGreg Clayton   size_t exact_matches_idx = SIZE_MAX;
361*b9c1b51eSKate Stone   const size_t num_matches = g_property_names.AutoComplete(
362*b9c1b51eSKate Stone       partial_setting_name, matches, exact_matches_idx);
36367cc0636SGreg Clayton   word_complete = exact_matches_idx != SIZE_MAX;
36467cc0636SGreg Clayton   return num_matches;
3653df9a8dfSCaroline Tice }
3663df9a8dfSCaroline Tice 
367*b9c1b51eSKate Stone int CommandCompletions::PlatformPluginNames(
368*b9c1b51eSKate Stone     CommandInterpreter &interpreter, const char *partial_name,
369*b9c1b51eSKate Stone     int match_start_point, int max_return_elements, SearchFilter *searcher,
370*b9c1b51eSKate Stone     bool &word_complete, lldb_private::StringList &matches) {
371*b9c1b51eSKate Stone   const uint32_t num_matches =
372*b9c1b51eSKate Stone       PluginManager::AutoCompletePlatformName(partial_name, matches);
373ab65b34fSGreg Clayton   word_complete = num_matches == 1;
374ab65b34fSGreg Clayton   return num_matches;
375ab65b34fSGreg Clayton }
376ab65b34fSGreg Clayton 
377*b9c1b51eSKate Stone int CommandCompletions::ArchitectureNames(
378*b9c1b51eSKate Stone     CommandInterpreter &interpreter, const char *partial_name,
379*b9c1b51eSKate Stone     int match_start_point, int max_return_elements, SearchFilter *searcher,
380*b9c1b51eSKate Stone     bool &word_complete, lldb_private::StringList &matches) {
381ab65b34fSGreg Clayton   const uint32_t num_matches = ArchSpec::AutoComplete(partial_name, matches);
382ab65b34fSGreg Clayton   word_complete = num_matches == 1;
383ab65b34fSGreg Clayton   return num_matches;
384ab65b34fSGreg Clayton }
385ab65b34fSGreg Clayton 
386*b9c1b51eSKate Stone int CommandCompletions::VariablePath(
387*b9c1b51eSKate Stone     CommandInterpreter &interpreter, const char *partial_name,
388*b9c1b51eSKate Stone     int match_start_point, int max_return_elements, SearchFilter *searcher,
389*b9c1b51eSKate Stone     bool &word_complete, lldb_private::StringList &matches) {
390*b9c1b51eSKate Stone   return Variable::AutoComplete(interpreter.GetExecutionContext(), partial_name,
391*b9c1b51eSKate Stone                                 matches, word_complete);
392f21feadcSGreg Clayton }
393f21feadcSGreg Clayton 
394c8ecc2a9SEugene Zelenko CommandCompletions::Completer::Completer(CommandInterpreter &interpreter,
395c9af18a5SGreg Clayton                                          const char *completion_str,
396c9af18a5SGreg Clayton                                          int match_start_point,
397c9af18a5SGreg Clayton                                          int max_return_elements,
398*b9c1b51eSKate Stone                                          StringList &matches)
399*b9c1b51eSKate Stone     : m_interpreter(interpreter), m_completion_str(completion_str),
400c9af18a5SGreg Clayton       m_match_start_point(match_start_point),
401*b9c1b51eSKate Stone       m_max_return_elements(max_return_elements), m_matches(matches) {}
402c9af18a5SGreg Clayton 
403c8ecc2a9SEugene Zelenko CommandCompletions::Completer::~Completer() = default;
404c9af18a5SGreg Clayton 
405c9af18a5SGreg Clayton //----------------------------------------------------------------------
406c9af18a5SGreg Clayton // SourceFileCompleter
407c9af18a5SGreg Clayton //----------------------------------------------------------------------
408c9af18a5SGreg Clayton 
409*b9c1b51eSKate Stone CommandCompletions::SourceFileCompleter::SourceFileCompleter(
410*b9c1b51eSKate Stone     CommandInterpreter &interpreter, bool include_support_files,
411*b9c1b51eSKate Stone     const char *completion_str, int match_start_point, int max_return_elements,
412*b9c1b51eSKate Stone     StringList &matches)
413*b9c1b51eSKate Stone     : CommandCompletions::Completer(interpreter, completion_str,
414*b9c1b51eSKate Stone                                     match_start_point, max_return_elements,
415*b9c1b51eSKate Stone                                     matches),
416*b9c1b51eSKate Stone       m_include_support_files(include_support_files), m_matching_files() {
417274060b6SGreg Clayton   FileSpec partial_spec(m_completion_str.c_str(), false);
418c9af18a5SGreg Clayton   m_file_name = partial_spec.GetFilename().GetCString();
419c9af18a5SGreg Clayton   m_dir_name = partial_spec.GetDirectory().GetCString();
420c9af18a5SGreg Clayton }
421c9af18a5SGreg Clayton 
422*b9c1b51eSKate Stone Searcher::Depth CommandCompletions::SourceFileCompleter::GetDepth() {
423c9af18a5SGreg Clayton   return eDepthCompUnit;
424c9af18a5SGreg Clayton }
425c9af18a5SGreg Clayton 
426c9af18a5SGreg Clayton Searcher::CallbackReturn
427c8ecc2a9SEugene Zelenko CommandCompletions::SourceFileCompleter::SearchCallback(SearchFilter &filter,
428c9af18a5SGreg Clayton                                                         SymbolContext &context,
429c9af18a5SGreg Clayton                                                         Address *addr,
430*b9c1b51eSKate Stone                                                         bool complete) {
431*b9c1b51eSKate Stone   if (context.comp_unit != nullptr) {
432*b9c1b51eSKate Stone     if (m_include_support_files) {
433c9af18a5SGreg Clayton       FileSpecList supporting_files = context.comp_unit->GetSupportFiles();
434*b9c1b51eSKate Stone       for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++) {
435*b9c1b51eSKate Stone         const FileSpec &sfile_spec =
436*b9c1b51eSKate Stone             supporting_files.GetFileSpecAtIndex(sfiles);
437c9af18a5SGreg Clayton         const char *sfile_file_name = sfile_spec.GetFilename().GetCString();
438c9af18a5SGreg Clayton         const char *sfile_dir_name = sfile_spec.GetFilename().GetCString();
439c9af18a5SGreg Clayton         bool match = false;
440*b9c1b51eSKate Stone         if (m_file_name && sfile_file_name &&
441*b9c1b51eSKate Stone             strstr(sfile_file_name, m_file_name) == sfile_file_name)
442c9af18a5SGreg Clayton           match = true;
443*b9c1b51eSKate Stone         if (match && m_dir_name && sfile_dir_name &&
444*b9c1b51eSKate Stone             strstr(sfile_dir_name, m_dir_name) != sfile_dir_name)
445c9af18a5SGreg Clayton           match = false;
446c9af18a5SGreg Clayton 
447*b9c1b51eSKate Stone         if (match) {
448c9af18a5SGreg Clayton           m_matching_files.AppendIfUnique(sfile_spec);
449c9af18a5SGreg Clayton         }
450c9af18a5SGreg Clayton       }
451*b9c1b51eSKate Stone     } else {
452c9af18a5SGreg Clayton       const char *cur_file_name = context.comp_unit->GetFilename().GetCString();
453c9af18a5SGreg Clayton       const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString();
454c9af18a5SGreg Clayton 
455c9af18a5SGreg Clayton       bool match = false;
456*b9c1b51eSKate Stone       if (m_file_name && cur_file_name &&
457*b9c1b51eSKate Stone           strstr(cur_file_name, m_file_name) == cur_file_name)
458c9af18a5SGreg Clayton         match = true;
459c9af18a5SGreg Clayton 
460*b9c1b51eSKate Stone       if (match && m_dir_name && cur_dir_name &&
461*b9c1b51eSKate Stone           strstr(cur_dir_name, m_dir_name) != cur_dir_name)
462c9af18a5SGreg Clayton         match = false;
463c9af18a5SGreg Clayton 
464*b9c1b51eSKate Stone       if (match) {
465c9af18a5SGreg Clayton         m_matching_files.AppendIfUnique(context.comp_unit);
466c9af18a5SGreg Clayton       }
467c9af18a5SGreg Clayton     }
468c9af18a5SGreg Clayton   }
469c9af18a5SGreg Clayton   return Searcher::eCallbackReturnContinue;
470c9af18a5SGreg Clayton }
471c9af18a5SGreg Clayton 
472c9af18a5SGreg Clayton size_t
473*b9c1b51eSKate Stone CommandCompletions::SourceFileCompleter::DoCompletion(SearchFilter *filter) {
474c9af18a5SGreg Clayton   filter->Search(*this);
475c9af18a5SGreg Clayton   // Now convert the filelist to completions:
476*b9c1b51eSKate Stone   for (size_t i = 0; i < m_matching_files.GetSize(); i++) {
477*b9c1b51eSKate Stone     m_matches.AppendString(
478*b9c1b51eSKate Stone         m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
479c9af18a5SGreg Clayton   }
480c9af18a5SGreg Clayton   return m_matches.GetSize();
481c9af18a5SGreg Clayton }
482c9af18a5SGreg Clayton 
483c9af18a5SGreg Clayton //----------------------------------------------------------------------
484c9af18a5SGreg Clayton // SymbolCompleter
485c9af18a5SGreg Clayton //----------------------------------------------------------------------
486c9af18a5SGreg Clayton 
487*b9c1b51eSKate Stone static bool regex_chars(const char comp) {
488*b9c1b51eSKate Stone   return (comp == '[' || comp == ']' || comp == '(' || comp == ')' ||
489*b9c1b51eSKate Stone           comp == '{' || comp == '}' || comp == '+' || comp == '.' ||
490*b9c1b51eSKate Stone           comp == '*' || comp == '|' || comp == '^' || comp == '$' ||
491*b9c1b51eSKate Stone           comp == '\\' || comp == '?');
492c9af18a5SGreg Clayton }
493c8ecc2a9SEugene Zelenko 
494*b9c1b51eSKate Stone CommandCompletions::SymbolCompleter::SymbolCompleter(
495*b9c1b51eSKate Stone     CommandInterpreter &interpreter, const char *completion_str,
496*b9c1b51eSKate Stone     int match_start_point, int max_return_elements, StringList &matches)
497*b9c1b51eSKate Stone     : CommandCompletions::Completer(interpreter, completion_str,
498*b9c1b51eSKate Stone                                     match_start_point, max_return_elements,
499*b9c1b51eSKate Stone                                     matches) {
500649f8b9bSGreg Clayton   std::string regex_str;
501*b9c1b51eSKate Stone   if (completion_str && completion_str[0]) {
502649f8b9bSGreg Clayton     regex_str.append("^");
503c9af18a5SGreg Clayton     regex_str.append(completion_str);
504*b9c1b51eSKate Stone   } else {
505649f8b9bSGreg Clayton     // Match anything since the completion string is empty
506649f8b9bSGreg Clayton     regex_str.append(".");
507649f8b9bSGreg Clayton   }
508*b9c1b51eSKate Stone   std::string::iterator pos =
509*b9c1b51eSKate Stone       find_if(regex_str.begin() + 1, regex_str.end(), regex_chars);
510*b9c1b51eSKate Stone   while (pos < regex_str.end()) {
511c9af18a5SGreg Clayton     pos = regex_str.insert(pos, '\\');
512649f8b9bSGreg Clayton     pos = find_if(pos + 2, regex_str.end(), regex_chars);
513c9af18a5SGreg Clayton   }
514c9af18a5SGreg Clayton   m_regex.Compile(regex_str.c_str());
515c9af18a5SGreg Clayton }
516c9af18a5SGreg Clayton 
517*b9c1b51eSKate Stone Searcher::Depth CommandCompletions::SymbolCompleter::GetDepth() {
518c9af18a5SGreg Clayton   return eDepthModule;
519c9af18a5SGreg Clayton }
520c9af18a5SGreg Clayton 
521*b9c1b51eSKate Stone Searcher::CallbackReturn CommandCompletions::SymbolCompleter::SearchCallback(
522*b9c1b51eSKate Stone     SearchFilter &filter, SymbolContext &context, Address *addr,
523*b9c1b51eSKate Stone     bool complete) {
524*b9c1b51eSKate Stone   if (context.module_sp) {
525931180e6SGreg Clayton     SymbolContextList sc_list;
526931180e6SGreg Clayton     const bool include_symbols = true;
5279df05fbbSSean Callanan     const bool include_inlines = true;
528931180e6SGreg Clayton     const bool append = true;
529*b9c1b51eSKate Stone     context.module_sp->FindFunctions(m_regex, include_symbols, include_inlines,
530*b9c1b51eSKate Stone                                      append, sc_list);
531c9af18a5SGreg Clayton 
532c9af18a5SGreg Clayton     SymbolContext sc;
533c9af18a5SGreg Clayton     // Now add the functions & symbols to the list - only add if unique:
534*b9c1b51eSKate Stone     for (uint32_t i = 0; i < sc_list.GetSize(); i++) {
535*b9c1b51eSKate Stone       if (sc_list.GetContextAtIndex(i, sc)) {
536530a413cSJim Ingham         ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
537530a413cSJim Ingham         if (!func_name.IsEmpty())
538530a413cSJim Ingham           m_match_set.insert(func_name);
539c9af18a5SGreg Clayton       }
540c9af18a5SGreg Clayton     }
541c9af18a5SGreg Clayton   }
542c9af18a5SGreg Clayton   return Searcher::eCallbackReturnContinue;
543c9af18a5SGreg Clayton }
544c9af18a5SGreg Clayton 
545*b9c1b51eSKate Stone size_t CommandCompletions::SymbolCompleter::DoCompletion(SearchFilter *filter) {
546c9af18a5SGreg Clayton   filter->Search(*this);
547c9af18a5SGreg Clayton   collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
548c9af18a5SGreg Clayton   for (pos = m_match_set.begin(); pos != end; pos++)
549c9af18a5SGreg Clayton     m_matches.AppendString((*pos).GetCString());
550c9af18a5SGreg Clayton 
551c9af18a5SGreg Clayton   return m_matches.GetSize();
552c9af18a5SGreg Clayton }
553c9af18a5SGreg Clayton 
554c9af18a5SGreg Clayton //----------------------------------------------------------------------
555c9af18a5SGreg Clayton // ModuleCompleter
556c9af18a5SGreg Clayton //----------------------------------------------------------------------
557*b9c1b51eSKate Stone CommandCompletions::ModuleCompleter::ModuleCompleter(
558*b9c1b51eSKate Stone     CommandInterpreter &interpreter, const char *completion_str,
559*b9c1b51eSKate Stone     int match_start_point, int max_return_elements, StringList &matches)
560*b9c1b51eSKate Stone     : CommandCompletions::Completer(interpreter, completion_str,
561*b9c1b51eSKate Stone                                     match_start_point, max_return_elements,
562*b9c1b51eSKate Stone                                     matches) {
563274060b6SGreg Clayton   FileSpec partial_spec(m_completion_str.c_str(), false);
564c9af18a5SGreg Clayton   m_file_name = partial_spec.GetFilename().GetCString();
565c9af18a5SGreg Clayton   m_dir_name = partial_spec.GetDirectory().GetCString();
566c9af18a5SGreg Clayton }
567c9af18a5SGreg Clayton 
568*b9c1b51eSKate Stone Searcher::Depth CommandCompletions::ModuleCompleter::GetDepth() {
569c9af18a5SGreg Clayton   return eDepthModule;
570c9af18a5SGreg Clayton }
571c9af18a5SGreg Clayton 
572*b9c1b51eSKate Stone Searcher::CallbackReturn CommandCompletions::ModuleCompleter::SearchCallback(
573*b9c1b51eSKate Stone     SearchFilter &filter, SymbolContext &context, Address *addr,
574*b9c1b51eSKate Stone     bool complete) {
575*b9c1b51eSKate Stone   if (context.module_sp) {
576*b9c1b51eSKate Stone     const char *cur_file_name =
577*b9c1b51eSKate Stone         context.module_sp->GetFileSpec().GetFilename().GetCString();
578*b9c1b51eSKate Stone     const char *cur_dir_name =
579*b9c1b51eSKate Stone         context.module_sp->GetFileSpec().GetDirectory().GetCString();
580c9af18a5SGreg Clayton 
581c9af18a5SGreg Clayton     bool match = false;
582*b9c1b51eSKate Stone     if (m_file_name && cur_file_name &&
583*b9c1b51eSKate Stone         strstr(cur_file_name, m_file_name) == cur_file_name)
584c9af18a5SGreg Clayton       match = true;
585c9af18a5SGreg Clayton 
586*b9c1b51eSKate Stone     if (match && m_dir_name && cur_dir_name &&
587*b9c1b51eSKate Stone         strstr(cur_dir_name, m_dir_name) != cur_dir_name)
588c9af18a5SGreg Clayton       match = false;
589c9af18a5SGreg Clayton 
590*b9c1b51eSKate Stone     if (match) {
591c9af18a5SGreg Clayton       m_matches.AppendString(cur_file_name);
592c9af18a5SGreg Clayton     }
593c9af18a5SGreg Clayton   }
594c9af18a5SGreg Clayton   return Searcher::eCallbackReturnContinue;
595c9af18a5SGreg Clayton }
596c9af18a5SGreg Clayton 
597*b9c1b51eSKate Stone size_t CommandCompletions::ModuleCompleter::DoCompletion(SearchFilter *filter) {
598c9af18a5SGreg Clayton   filter->Search(*this);
599c9af18a5SGreg Clayton   return m_matches.GetSize();
600c9af18a5SGreg Clayton }
601