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"
367d86ee5aSZachary 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 
102*0734e6a5SZachary Turner typedef struct DiskFilesOrDirectoriesBaton {
103*0734e6a5SZachary Turner   const char *remainder;
104*0734e6a5SZachary Turner   char *partial_name_copy;
105*0734e6a5SZachary Turner   bool only_directories;
106*0734e6a5SZachary Turner   bool *saw_directory;
107*0734e6a5SZachary Turner   StringList *matches;
108*0734e6a5SZachary Turner   char *end_ptr;
109*0734e6a5SZachary Turner   size_t baselen;
110*0734e6a5SZachary Turner } DiskFilesOrDirectoriesBaton;
111b2f1fb29SVirgile Bello 
112*0734e6a5SZachary Turner FileSpec::EnumerateDirectoryResult
113*0734e6a5SZachary Turner DiskFilesOrDirectoriesCallback(void *baton, llvm::sys::fs::file_type file_type,
114*0734e6a5SZachary Turner                                const FileSpec &spec) {
115*0734e6a5SZachary Turner   const char *name = spec.GetFilename().AsCString();
116b2f1fb29SVirgile Bello 
117*0734e6a5SZachary Turner   const DiskFilesOrDirectoriesBaton *parameters =
118*0734e6a5SZachary Turner       (DiskFilesOrDirectoriesBaton *)baton;
119*0734e6a5SZachary Turner   char *end_ptr = parameters->end_ptr;
120*0734e6a5SZachary Turner   char *partial_name_copy = parameters->partial_name_copy;
121*0734e6a5SZachary Turner   const char *remainder = parameters->remainder;
122*0734e6a5SZachary Turner 
123*0734e6a5SZachary Turner   // Omit ".", ".." and any . files if the match string doesn't start with .
124*0734e6a5SZachary Turner   if (name[0] == '.') {
125*0734e6a5SZachary Turner     if (name[1] == '\0')
126*0734e6a5SZachary Turner       return FileSpec::eEnumerateDirectoryResultNext;
127*0734e6a5SZachary Turner     else if (name[1] == '.' && name[2] == '\0')
128*0734e6a5SZachary Turner       return FileSpec::eEnumerateDirectoryResultNext;
129*0734e6a5SZachary Turner     else if (remainder[0] != '.')
130*0734e6a5SZachary Turner       return FileSpec::eEnumerateDirectoryResultNext;
131*0734e6a5SZachary Turner   }
132*0734e6a5SZachary Turner 
133*0734e6a5SZachary Turner   // If we found a directory, we put a "/" at the end of the name.
134*0734e6a5SZachary Turner 
135*0734e6a5SZachary Turner   if (remainder[0] == '\0' || strstr(name, remainder) == name) {
136*0734e6a5SZachary Turner     if (strlen(name) + parameters->baselen >= PATH_MAX)
137*0734e6a5SZachary Turner       return FileSpec::eEnumerateDirectoryResultNext;
138*0734e6a5SZachary Turner 
139*0734e6a5SZachary Turner     strcpy(end_ptr, name);
140b2f1fb29SVirgile Bello 
1417d86ee5aSZachary Turner     namespace fs = llvm::sys::fs;
142*0734e6a5SZachary Turner     bool isa_directory = false;
143*0734e6a5SZachary Turner     if (file_type == fs::file_type::directory_file)
144*0734e6a5SZachary Turner       isa_directory = true;
145*0734e6a5SZachary Turner     else if (file_type == fs::file_type::symlink_file)
146*0734e6a5SZachary Turner       isa_directory = fs::is_directory(partial_name_copy);
147b2f1fb29SVirgile Bello 
148*0734e6a5SZachary Turner     if (isa_directory) {
149*0734e6a5SZachary Turner       *parameters->saw_directory = true;
150*0734e6a5SZachary Turner       size_t len = strlen(parameters->partial_name_copy);
151*0734e6a5SZachary Turner       partial_name_copy[len] = '/';
152*0734e6a5SZachary Turner       partial_name_copy[len + 1] = '\0';
153b2f1fb29SVirgile Bello     }
154*0734e6a5SZachary Turner     if (parameters->only_directories && !isa_directory)
155*0734e6a5SZachary Turner       return FileSpec::eEnumerateDirectoryResultNext;
156*0734e6a5SZachary Turner     parameters->matches->AppendString(partial_name_copy);
157b2f1fb29SVirgile Bello   }
158*0734e6a5SZachary Turner 
159*0734e6a5SZachary Turner   return FileSpec::eEnumerateDirectoryResultNext;
160*0734e6a5SZachary Turner }
161*0734e6a5SZachary Turner 
162*0734e6a5SZachary Turner static int DiskFilesOrDirectories(llvm::StringRef partial_file_name,
163*0734e6a5SZachary Turner                                   bool only_directories, bool &saw_directory,
164*0734e6a5SZachary Turner                                   StringList &matches) {
165*0734e6a5SZachary Turner   // I'm going to  use the "glob" function with GLOB_TILDE for user directory
166*0734e6a5SZachary Turner   // expansion.
167*0734e6a5SZachary Turner   // If it is not defined on your host system, you'll need to implement it
168*0734e6a5SZachary Turner   // yourself...
169*0734e6a5SZachary Turner 
170*0734e6a5SZachary Turner   size_t partial_name_len = partial_file_name.size();
171*0734e6a5SZachary Turner 
172*0734e6a5SZachary Turner   if (partial_name_len >= PATH_MAX)
173*0734e6a5SZachary Turner     return matches.GetSize();
174*0734e6a5SZachary Turner 
175*0734e6a5SZachary Turner   // This copy of the string will be cut up into the directory part, and the
176*0734e6a5SZachary Turner   // remainder.  end_ptr below will point to the place of the remainder in this
177*0734e6a5SZachary Turner   // string.  Then when we've resolved the containing directory, and opened it,
178*0734e6a5SZachary Turner   // we'll read the directory contents and overwrite the partial_name_copy
179*0734e6a5SZachary Turner   // starting from end_ptr with each of the matches.  Thus we will preserve the
180*0734e6a5SZachary Turner   // form the user originally typed.
181*0734e6a5SZachary Turner 
182*0734e6a5SZachary Turner   char partial_name_copy[PATH_MAX];
183*0734e6a5SZachary Turner   memcpy(partial_name_copy, partial_file_name.data(), partial_name_len);
184*0734e6a5SZachary Turner   partial_name_copy[partial_name_len] = '\0';
185*0734e6a5SZachary Turner 
186*0734e6a5SZachary Turner   // We'll need to save a copy of the remainder for comparison, which we do
187*0734e6a5SZachary Turner   // here.
188*0734e6a5SZachary Turner   char remainder[PATH_MAX];
189*0734e6a5SZachary Turner 
190*0734e6a5SZachary Turner   // end_ptr will point past the last / in partial_name_copy, or if there is no
191*0734e6a5SZachary Turner   // slash to the beginning of the string.
192*0734e6a5SZachary Turner   char *end_ptr;
193*0734e6a5SZachary Turner 
194*0734e6a5SZachary Turner   end_ptr = strrchr(partial_name_copy, '/');
195*0734e6a5SZachary Turner 
196*0734e6a5SZachary Turner   // This will store the resolved form of the containing directory
197*0734e6a5SZachary Turner   llvm::SmallString<64> containing_part;
198*0734e6a5SZachary Turner 
199*0734e6a5SZachary Turner   if (end_ptr == nullptr) {
200*0734e6a5SZachary Turner     // There's no directory.  If the thing begins with a "~" then this is a bare
201*0734e6a5SZachary Turner     // user name.
202*0734e6a5SZachary Turner     if (*partial_name_copy == '~') {
203*0734e6a5SZachary Turner       // Nothing here but the user name.  We could just put a slash on the end,
204*0734e6a5SZachary Turner       // but for completeness sake we'll resolve the user name and only put a
205*0734e6a5SZachary Turner       // slash
206*0734e6a5SZachary Turner       // on the end if it exists.
207*0734e6a5SZachary Turner       llvm::SmallString<64> resolved_username(partial_name_copy);
208*0734e6a5SZachary Turner       FileSpec::ResolveUsername(resolved_username);
209*0734e6a5SZachary Turner 
210*0734e6a5SZachary Turner       // Not sure how this would happen, a username longer than PATH_MAX?
211*0734e6a5SZachary Turner       // Still...
212*0734e6a5SZachary Turner       if (resolved_username.size() == 0) {
213*0734e6a5SZachary Turner         // The user name didn't resolve, let's look in the password database for
214*0734e6a5SZachary Turner         // matches.
215*0734e6a5SZachary Turner         // The user name database contains duplicates, and is not in
216*0734e6a5SZachary Turner         // alphabetical order, so
217*0734e6a5SZachary Turner         // we'll use a set to manage that for us.
218*0734e6a5SZachary Turner         FileSpec::ResolvePartialUsername(partial_name_copy, matches);
219*0734e6a5SZachary Turner         if (matches.GetSize() > 0)
220*0734e6a5SZachary Turner           saw_directory = true;
221*0734e6a5SZachary Turner         return matches.GetSize();
222*0734e6a5SZachary Turner       } else {
223*0734e6a5SZachary Turner         // The thing exists, put a '/' on the end, and return it...
224*0734e6a5SZachary Turner         // FIXME: complete user names here:
225*0734e6a5SZachary Turner         partial_name_copy[partial_name_len] = '/';
226*0734e6a5SZachary Turner         partial_name_copy[partial_name_len + 1] = '\0';
227*0734e6a5SZachary Turner         matches.AppendString(partial_name_copy);
228*0734e6a5SZachary Turner         saw_directory = true;
229*0734e6a5SZachary Turner         return matches.GetSize();
230*0734e6a5SZachary Turner       }
231*0734e6a5SZachary Turner     } else {
232*0734e6a5SZachary Turner       // The containing part is the CWD, and the whole string is the remainder.
233*0734e6a5SZachary Turner       containing_part = ".";
234*0734e6a5SZachary Turner       strcpy(remainder, partial_name_copy);
235*0734e6a5SZachary Turner       end_ptr = partial_name_copy;
236*0734e6a5SZachary Turner     }
237*0734e6a5SZachary Turner   } else {
238*0734e6a5SZachary Turner     if (end_ptr == partial_name_copy) {
239*0734e6a5SZachary Turner       // We're completing a file or directory in the root volume.
240*0734e6a5SZachary Turner       containing_part = "/";
241*0734e6a5SZachary Turner     } else {
242*0734e6a5SZachary Turner       containing_part.append(partial_name_copy, end_ptr);
243*0734e6a5SZachary Turner     }
244*0734e6a5SZachary Turner     // Push end_ptr past the final "/" and set remainder.
245*0734e6a5SZachary Turner     end_ptr++;
246*0734e6a5SZachary Turner     strcpy(remainder, end_ptr);
247*0734e6a5SZachary Turner   }
248*0734e6a5SZachary Turner 
249*0734e6a5SZachary Turner   // Look for a user name in the containing part, and if it's there, resolve it
250*0734e6a5SZachary Turner   // and stick the
251*0734e6a5SZachary Turner   // result back into the containing_part:
252*0734e6a5SZachary Turner 
253*0734e6a5SZachary Turner   if (*partial_name_copy == '~') {
254*0734e6a5SZachary Turner     FileSpec::ResolveUsername(containing_part);
255*0734e6a5SZachary Turner     // User name doesn't exist, we're not getting any further...
256*0734e6a5SZachary Turner     if (containing_part.empty())
257558ce124SJim Ingham       return matches.GetSize();
258d5bd3a1eSZachary Turner   }
259558ce124SJim Ingham 
260*0734e6a5SZachary Turner   // Okay, containing_part is now the directory we want to open and look for
261*0734e6a5SZachary Turner   // files:
262d5bd3a1eSZachary Turner 
263*0734e6a5SZachary Turner   size_t baselen = end_ptr - partial_name_copy;
264d5bd3a1eSZachary Turner 
265*0734e6a5SZachary Turner   DiskFilesOrDirectoriesBaton parameters;
266*0734e6a5SZachary Turner   parameters.remainder = remainder;
267*0734e6a5SZachary Turner   parameters.partial_name_copy = partial_name_copy;
268*0734e6a5SZachary Turner   parameters.only_directories = only_directories;
269*0734e6a5SZachary Turner   parameters.saw_directory = &saw_directory;
270*0734e6a5SZachary Turner   parameters.matches = &matches;
271*0734e6a5SZachary Turner   parameters.end_ptr = end_ptr;
272*0734e6a5SZachary Turner   parameters.baselen = baselen;
273d5bd3a1eSZachary Turner 
274*0734e6a5SZachary Turner   FileSpec::EnumerateDirectory(containing_part.c_str(), true, true, true,
275*0734e6a5SZachary Turner                                DiskFilesOrDirectoriesCallback, &parameters);
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) {
286*0734e6a5SZachary Turner   int ret_val =
287*0734e6a5SZachary Turner       DiskFilesOrDirectories(partial_file_name, false, word_complete, matches);
288*0734e6a5SZachary Turner   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) {
296*0734e6a5SZachary Turner   int ret_val =
297*0734e6a5SZachary Turner       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