blob: 138fdfe5744a183b52217fb4bd0dd981f3f31864 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- CommandCompletions.cpp ----------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Daniel Malea93a64302012-12-05 00:20:57 +000010#include "lldb/lldb-python.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000011
12// C Includes
Jim Ingham558ce122010-06-30 05:02:46 +000013#include <sys/stat.h>
Greg Claytonfd184262011-02-05 02:27:52 +000014#if defined(__APPLE__) || defined(__linux__)
Jim Ingham7cc478b2010-07-02 00:45:55 +000015#include <pwd.h>
Greg Claytonfd184262011-02-05 02:27:52 +000016#endif
Jim Ingham558ce122010-06-30 05:02:46 +000017
Chris Lattner30fdc8d2010-06-08 16:52:24 +000018// C++ Includes
19// Other libraries and framework includes
20// Project includes
Greg Clayton53239f02011-02-08 05:05:52 +000021#include "lldb/Host/FileSpec.h"
Greg Clayton9b62fd22011-02-01 05:15:22 +000022#include "lldb/Core/FileSpecList.h"
Greg Claytonab65b342011-04-13 22:47:15 +000023#include "lldb/Core/PluginManager.h"
Greg Clayton1f746072012-08-29 21:13:06 +000024#include "lldb/Core/Module.h"
Greg Clayton9b62fd22011-02-01 05:15:22 +000025#include "lldb/Interpreter/Args.h"
26#include "lldb/Interpreter/CommandCompletions.h"
27#include "lldb/Interpreter/CommandInterpreter.h"
Greg Clayton1f746072012-08-29 21:13:06 +000028#include "lldb/Symbol/CompileUnit.h"
Greg Claytonf21fead2013-05-14 23:43:18 +000029#include "lldb/Symbol/Variable.h"
Greg Clayton9b62fd22011-02-01 05:15:22 +000030#include "lldb/Target/Target.h"
31#include "lldb/Utility/CleanUp.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000032
33using namespace lldb_private;
34
35CommandCompletions::CommonCompletionElement
36CommandCompletions::g_common_completions[] =
37{
Jim Ingham558ce122010-06-30 05:02:46 +000038 {eCustomCompletion, NULL},
39 {eSourceFileCompletion, CommandCompletions::SourceFiles},
40 {eDiskFileCompletion, CommandCompletions::DiskFiles},
41 {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
42 {eSymbolCompletion, CommandCompletions::Symbols},
43 {eModuleCompletion, CommandCompletions::Modules},
Caroline Tice3df9a8d2010-09-04 00:03:46 +000044 {eSettingsNameCompletion, CommandCompletions::SettingsNames},
Greg Claytonab65b342011-04-13 22:47:15 +000045 {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames},
46 {eArchitectureCompletion, CommandCompletions::ArchitectureNames},
Greg Claytonf21fead2013-05-14 23:43:18 +000047 {eVariablePathCompletion, CommandCompletions::VariablePath},
Jim Ingham558ce122010-06-30 05:02:46 +000048 {eNoCompletion, NULL} // This one has to be last in the list.
Chris Lattner30fdc8d2010-06-08 16:52:24 +000049};
50
51bool
Greg Clayton66111032010-06-23 01:19:29 +000052CommandCompletions::InvokeCommonCompletionCallbacks
53(
54 CommandInterpreter &interpreter,
55 uint32_t completion_mask,
56 const char *completion_str,
57 int match_start_point,
58 int max_return_elements,
59 SearchFilter *searcher,
Jim Ingham558ce122010-06-30 05:02:46 +000060 bool &word_complete,
Greg Clayton66111032010-06-23 01:19:29 +000061 StringList &matches
62)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000063{
64 bool handled = false;
65
66 if (completion_mask & eCustomCompletion)
67 return false;
68
69 for (int i = 0; ; i++)
70 {
71 if (g_common_completions[i].type == eNoCompletion)
72 break;
73 else if ((g_common_completions[i].type & completion_mask) == g_common_completions[i].type
74 && g_common_completions[i].callback != NULL)
75 {
76 handled = true;
Greg Clayton66111032010-06-23 01:19:29 +000077 g_common_completions[i].callback (interpreter,
78 completion_str,
Chris Lattner30fdc8d2010-06-08 16:52:24 +000079 match_start_point,
80 max_return_elements,
Chris Lattner30fdc8d2010-06-08 16:52:24 +000081 searcher,
Jim Ingham558ce122010-06-30 05:02:46 +000082 word_complete,
Chris Lattner30fdc8d2010-06-08 16:52:24 +000083 matches);
84 }
85 }
86 return handled;
87}
88
89int
Greg Clayton66111032010-06-23 01:19:29 +000090CommandCompletions::SourceFiles
91(
92 CommandInterpreter &interpreter,
93 const char *partial_file_name,
94 int match_start_point,
95 int max_return_elements,
96 SearchFilter *searcher,
Jim Ingham558ce122010-06-30 05:02:46 +000097 bool &word_complete,
Greg Clayton66111032010-06-23 01:19:29 +000098 StringList &matches
99)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000100{
Jim Ingham558ce122010-06-30 05:02:46 +0000101 word_complete = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000102 // Find some way to switch "include support files..."
Greg Clayton66111032010-06-23 01:19:29 +0000103 SourceFileCompleter completer (interpreter,
104 false,
105 partial_file_name,
106 match_start_point,
107 max_return_elements,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000108 matches);
109
110 if (searcher == NULL)
111 {
Jim Ingham2976d002010-08-26 21:32:51 +0000112 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000113 SearchFilter null_searcher (target_sp);
114 completer.DoCompletion (&null_searcher);
115 }
116 else
117 {
118 completer.DoCompletion (searcher);
119 }
120 return matches.GetSize();
121}
122
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000123typedef struct DiskFilesOrDirectoriesBaton
124{
125 const char *remainder;
126 char *partial_name_copy;
127 bool only_directories;
128 bool *saw_directory;
129 StringList *matches;
130 char *end_ptr;
131 size_t baselen;
132};
133
134FileSpec::EnumerateDirectoryResult DiskFilesOrDirectoriesCallback(void *baton, FileSpec::FileType file_type, const FileSpec &spec)
135{
136 const char *name = spec.GetFilename().AsCString();
137
138 const DiskFilesOrDirectoriesBaton *parameters = (DiskFilesOrDirectoriesBaton*)baton;
139 char *end_ptr = parameters->end_ptr;
140 char *partial_name_copy = parameters->partial_name_copy;
141 size_t baselen = end_ptr - partial_name_copy;
142 const char *remainder = parameters->remainder;
143
144 // Omit ".", ".." and any . files if the match string doesn't start with .
145 if (name[0] == '.')
146 {
147 if (name[1] == '\0')
148 return FileSpec::eEnumerateDirectoryResultNext;
149 else if (name[1] == '.' && name[2] == '\0')
150 return FileSpec::eEnumerateDirectoryResultNext;
151 else if (remainder[0] != '.')
152 return FileSpec::eEnumerateDirectoryResultNext;
153 }
154
155 // If we found a directory, we put a "/" at the end of the name.
156
157 if (remainder[0] == '\0' || strstr(name, remainder) == name)
158 {
159 if (strlen(name) + parameters->baselen >= PATH_MAX)
160 return FileSpec::eEnumerateDirectoryResultNext;
161
162 strcpy(end_ptr, name);
163
164 bool isa_directory = false;
165 if (file_type == FileSpec::eFileTypeDirectory)
166 isa_directory = true;
167 else if (file_type == FileSpec::eFileTypeSymbolicLink)
168 {
169 struct stat stat_buf;
170 if ((stat(partial_name_copy, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode))
171 isa_directory = true;
172 }
173
174 if (isa_directory)
175 {
176 *parameters->saw_directory = true;
177 size_t len = strlen(parameters->partial_name_copy);
178 partial_name_copy[len] = '/';
179 partial_name_copy[len + 1] = '\0';
180 }
181 if (parameters->only_directories && !isa_directory)
182 return FileSpec::eEnumerateDirectoryResultNext;
183 parameters->matches->AppendString(partial_name_copy);
184 }
185
186 return FileSpec::eEnumerateDirectoryResultNext;
187}
188
Jim Ingham558ce122010-06-30 05:02:46 +0000189static int
190DiskFilesOrDirectories
191(
192 const char *partial_file_name,
193 bool only_directories,
194 bool &saw_directory,
195 StringList &matches
196)
197{
198 // I'm going to use the "glob" function with GLOB_TILDE for user directory expansion.
199 // If it is not defined on your host system, you'll need to implement it yourself...
200
Greg Claytonc7bece562013-01-25 18:06:21 +0000201 size_t partial_name_len = strlen(partial_file_name);
Jim Ingham558ce122010-06-30 05:02:46 +0000202
203 if (partial_name_len >= PATH_MAX)
204 return matches.GetSize();
205
206 // This copy of the string will be cut up into the directory part, and the remainder. end_ptr
207 // below will point to the place of the remainder in this string. Then when we've resolved the
208 // containing directory, and opened it, we'll read the directory contents and overwrite the
209 // partial_name_copy starting from end_ptr with each of the matches. Thus we will preserve
210 // the form the user originally typed.
211
212 char partial_name_copy[PATH_MAX];
Benjamin Kramer021b6052010-06-30 13:43:47 +0000213 memcpy(partial_name_copy, partial_file_name, partial_name_len);
Jim Ingham558ce122010-06-30 05:02:46 +0000214 partial_name_copy[partial_name_len] = '\0';
215
Greg Clayton710dd5a2011-01-08 20:28:42 +0000216 // We'll need to save a copy of the remainder for comparison, which we do here.
Jim Ingham558ce122010-06-30 05:02:46 +0000217 char remainder[PATH_MAX];
218
219 // end_ptr will point past the last / in partial_name_copy, or if there is no slash to the beginning of the string.
220 char *end_ptr;
221
222 end_ptr = strrchr(partial_name_copy, '/');
223
224 // This will store the resolved form of the containing directory
225 char containing_part[PATH_MAX];
226
227 if (end_ptr == NULL)
228 {
229 // There's no directory. If the thing begins with a "~" then this is a bare
230 // user name.
231 if (*partial_name_copy == '~')
232 {
233 // Nothing here but the user name. We could just put a slash on the end,
Jim Ingham7cc478b2010-07-02 00:45:55 +0000234 // but for completeness sake we'll resolve the user name and only put a slash
Jim Ingham558ce122010-06-30 05:02:46 +0000235 // on the end if it exists.
Jim Ingham7cc478b2010-07-02 00:45:55 +0000236 char resolved_username[PATH_MAX];
Greg Claytonc982c762010-07-09 20:39:50 +0000237 size_t resolved_username_len = FileSpec::ResolveUsername (partial_name_copy, resolved_username,
Jim Ingham7cc478b2010-07-02 00:45:55 +0000238 sizeof (resolved_username));
239
240 // Not sure how this would happen, a username longer than PATH_MAX? Still...
241 if (resolved_username_len >= sizeof (resolved_username))
242 return matches.GetSize();
Jim Ingham84363072011-02-08 23:24:09 +0000243 else if (resolved_username_len == 0)
Jim Ingham7cc478b2010-07-02 00:45:55 +0000244 {
245 // The user name didn't resolve, let's look in the password database for matches.
246 // The user name database contains duplicates, and is not in alphabetical order, so
247 // we'll use a set to manage that for us.
Jim Ingham84363072011-02-08 23:24:09 +0000248 FileSpec::ResolvePartialUsername (partial_name_copy, matches);
249 if (matches.GetSize() > 0)
250 saw_directory = true;
Jim Ingham7cc478b2010-07-02 00:45:55 +0000251 return matches.GetSize();
Jim Ingham84363072011-02-08 23:24:09 +0000252 }
253 else
254 {
255 //The thing exists, put a '/' on the end, and return it...
256 // FIXME: complete user names here:
257 partial_name_copy[partial_name_len] = '/';
258 partial_name_copy[partial_name_len+1] = '\0';
259 matches.AppendString(partial_name_copy);
260 saw_directory = true;
261 return matches.GetSize();
262 }
Jim Ingham558ce122010-06-30 05:02:46 +0000263 }
264 else
265 {
266 // The containing part is the CWD, and the whole string is the remainder.
267 containing_part[0] = '.';
268 containing_part[1] = '\0';
269 strcpy(remainder, partial_name_copy);
270 end_ptr = partial_name_copy;
271 }
272 }
273 else
274 {
275 if (end_ptr == partial_name_copy)
276 {
277 // We're completing a file or directory in the root volume.
278 containing_part[0] = '/';
279 containing_part[1] = '\0';
280 }
281 else
282 {
283 size_t len = end_ptr - partial_name_copy;
284 memcpy(containing_part, partial_name_copy, len);
285 containing_part[len] = '\0';
286 }
287 // Push end_ptr past the final "/" and set remainder.
288 end_ptr++;
289 strcpy(remainder, end_ptr);
290 }
291
Jim Ingham7cc478b2010-07-02 00:45:55 +0000292 // Look for a user name in the containing part, and if it's there, resolve it and stick the
Jim Ingham558ce122010-06-30 05:02:46 +0000293 // result back into the containing_part:
Greg Claytonfd184262011-02-05 02:27:52 +0000294
Jim Ingham558ce122010-06-30 05:02:46 +0000295 if (*partial_name_copy == '~')
296 {
Jim Ingham84363072011-02-08 23:24:09 +0000297 size_t resolved_username_len = FileSpec::ResolveUsername(containing_part,
298 containing_part,
299 sizeof (containing_part));
Jim Ingham558ce122010-06-30 05:02:46 +0000300 // User name doesn't exist, we're not getting any further...
Greg Claytona0807352010-07-06 16:11:44 +0000301 if (resolved_username_len == 0 || resolved_username_len >= sizeof (containing_part))
Jim Ingham558ce122010-06-30 05:02:46 +0000302 return matches.GetSize();
Jim Ingham558ce122010-06-30 05:02:46 +0000303 }
Greg Claytonfd184262011-02-05 02:27:52 +0000304
Jim Ingham558ce122010-06-30 05:02:46 +0000305 // Okay, containing_part is now the directory we want to open and look for files:
Greg Clayton9b62fd22011-02-01 05:15:22 +0000306
Jim Ingham558ce122010-06-30 05:02:46 +0000307 size_t baselen = end_ptr - partial_name_copy;
308
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000309 DiskFilesOrDirectoriesBaton parameters;
310 parameters.remainder = remainder;
311 parameters.partial_name_copy = partial_name_copy;
312 parameters.only_directories = only_directories;
313 parameters.saw_directory = &saw_directory;
314 parameters.matches = &matches;
315 parameters.end_ptr = end_ptr;
316 parameters.baselen = baselen;
317
318 FileSpec::EnumerateDirectory(containing_part, true, true, true, DiskFilesOrDirectoriesCallback, &parameters);
Jim Ingham558ce122010-06-30 05:02:46 +0000319
320 return matches.GetSize();
321}
322
323int
324CommandCompletions::DiskFiles
325(
326 CommandInterpreter &interpreter,
327 const char *partial_file_name,
328 int match_start_point,
329 int max_return_elements,
330 SearchFilter *searcher,
331 bool &word_complete,
332 StringList &matches
333)
334{
335
336 int ret_val = DiskFilesOrDirectories (partial_file_name,
337 false,
338 word_complete,
339 matches);
340 word_complete = !word_complete;
341 return ret_val;
342}
343
344int
345CommandCompletions::DiskDirectories
346(
347 CommandInterpreter &interpreter,
348 const char *partial_file_name,
349 int match_start_point,
350 int max_return_elements,
351 SearchFilter *searcher,
352 bool &word_complete,
353 StringList &matches
354)
355{
356 int ret_val = DiskFilesOrDirectories (partial_file_name,
357 true,
358 word_complete,
359 matches);
360 word_complete = false;
361 return ret_val;
362}
363
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000364int
Greg Clayton66111032010-06-23 01:19:29 +0000365CommandCompletions::Modules
366(
367 CommandInterpreter &interpreter,
368 const char *partial_file_name,
369 int match_start_point,
370 int max_return_elements,
371 SearchFilter *searcher,
Jim Ingham558ce122010-06-30 05:02:46 +0000372 bool &word_complete,
Greg Clayton66111032010-06-23 01:19:29 +0000373 StringList &matches
374)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000375{
Jim Ingham558ce122010-06-30 05:02:46 +0000376 word_complete = true;
Greg Clayton66111032010-06-23 01:19:29 +0000377 ModuleCompleter completer (interpreter,
378 partial_file_name,
379 match_start_point,
380 max_return_elements,
381 matches);
382
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000383 if (searcher == NULL)
384 {
Jim Ingham2976d002010-08-26 21:32:51 +0000385 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000386 SearchFilter null_searcher (target_sp);
387 completer.DoCompletion (&null_searcher);
388 }
389 else
390 {
391 completer.DoCompletion (searcher);
392 }
393 return matches.GetSize();
394}
395
396int
Greg Clayton66111032010-06-23 01:19:29 +0000397CommandCompletions::Symbols
398(
399 CommandInterpreter &interpreter,
400 const char *partial_file_name,
401 int match_start_point,
402 int max_return_elements,
403 SearchFilter *searcher,
Jim Ingham558ce122010-06-30 05:02:46 +0000404 bool &word_complete,
Greg Clayton66111032010-06-23 01:19:29 +0000405 StringList &matches)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000406{
Jim Ingham558ce122010-06-30 05:02:46 +0000407 word_complete = true;
Greg Clayton66111032010-06-23 01:19:29 +0000408 SymbolCompleter completer (interpreter,
409 partial_file_name,
410 match_start_point,
411 max_return_elements,
412 matches);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000413
414 if (searcher == NULL)
415 {
Jim Ingham2976d002010-08-26 21:32:51 +0000416 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000417 SearchFilter null_searcher (target_sp);
418 completer.DoCompletion (&null_searcher);
419 }
420 else
421 {
422 completer.DoCompletion (searcher);
423 }
424 return matches.GetSize();
425}
426
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000427int
428CommandCompletions::SettingsNames (CommandInterpreter &interpreter,
429 const char *partial_setting_name,
430 int match_start_point,
431 int max_return_elements,
432 SearchFilter *searcher,
433 bool &word_complete,
434 StringList &matches)
435{
Greg Clayton67cc0632012-08-22 17:17:09 +0000436 // Cache the full setting name list
437 static StringList g_property_names;
438 if (g_property_names.GetSize() == 0)
439 {
440 // Generate the full setting name list on demand
441 lldb::OptionValuePropertiesSP properties_sp (interpreter.GetDebugger().GetValueProperties());
442 if (properties_sp)
443 {
444 StreamString strm;
445 properties_sp->DumpValue(NULL, strm, OptionValue::eDumpOptionName);
446 const std::string &str = strm.GetString();
447 g_property_names.SplitIntoLines(str.c_str(), str.size());
448 }
449 }
450
451 size_t exact_matches_idx = SIZE_MAX;
452 const size_t num_matches = g_property_names.AutoComplete (partial_setting_name, matches, exact_matches_idx);
Greg Clayton67cc0632012-08-22 17:17:09 +0000453 word_complete = exact_matches_idx != SIZE_MAX;
454 return num_matches;
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000455}
456
Greg Claytonab65b342011-04-13 22:47:15 +0000457
458int
459CommandCompletions::PlatformPluginNames (CommandInterpreter &interpreter,
460 const char *partial_name,
461 int match_start_point,
462 int max_return_elements,
463 SearchFilter *searcher,
464 bool &word_complete,
465 lldb_private::StringList &matches)
466{
467 const uint32_t num_matches = PluginManager::AutoCompletePlatformName(partial_name, matches);
468 word_complete = num_matches == 1;
469 return num_matches;
470}
471
472int
473CommandCompletions::ArchitectureNames (CommandInterpreter &interpreter,
474 const char *partial_name,
475 int match_start_point,
476 int max_return_elements,
477 SearchFilter *searcher,
478 bool &word_complete,
479 lldb_private::StringList &matches)
480{
481 const uint32_t num_matches = ArchSpec::AutoComplete (partial_name, matches);
482 word_complete = num_matches == 1;
483 return num_matches;
484}
485
486
Greg Claytonf21fead2013-05-14 23:43:18 +0000487int
488CommandCompletions::VariablePath (CommandInterpreter &interpreter,
489 const char *partial_name,
490 int match_start_point,
491 int max_return_elements,
492 SearchFilter *searcher,
493 bool &word_complete,
494 lldb_private::StringList &matches)
495{
496 return Variable::AutoComplete (interpreter.GetExecutionContext(), partial_name, matches, word_complete);
497}
498
499
Greg Clayton66111032010-06-23 01:19:29 +0000500CommandCompletions::Completer::Completer
501(
502 CommandInterpreter &interpreter,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000503 const char *completion_str,
504 int match_start_point,
505 int max_return_elements,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000506 StringList &matches
507) :
Greg Clayton66111032010-06-23 01:19:29 +0000508 m_interpreter (interpreter),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000509 m_completion_str (completion_str),
510 m_match_start_point (match_start_point),
511 m_max_return_elements (max_return_elements),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000512 m_matches (matches)
513{
514}
515
516CommandCompletions::Completer::~Completer ()
517{
518
519}
520
521//----------------------------------------------------------------------
522// SourceFileCompleter
523//----------------------------------------------------------------------
524
Greg Clayton66111032010-06-23 01:19:29 +0000525CommandCompletions::SourceFileCompleter::SourceFileCompleter
526(
527 CommandInterpreter &interpreter,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000528 bool include_support_files,
529 const char *completion_str,
530 int match_start_point,
531 int max_return_elements,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000532 StringList &matches
533) :
Greg Clayton66111032010-06-23 01:19:29 +0000534 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000535 m_include_support_files (include_support_files),
536 m_matching_files()
537{
Greg Clayton274060b2010-10-20 20:54:39 +0000538 FileSpec partial_spec (m_completion_str.c_str(), false);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000539 m_file_name = partial_spec.GetFilename().GetCString();
540 m_dir_name = partial_spec.GetDirectory().GetCString();
541}
542
543Searcher::Depth
544CommandCompletions::SourceFileCompleter::GetDepth()
545{
546 return eDepthCompUnit;
547}
548
549Searcher::CallbackReturn
550CommandCompletions::SourceFileCompleter::SearchCallback (
551 SearchFilter &filter,
552 SymbolContext &context,
553 Address *addr,
554 bool complete
555)
556{
557 if (context.comp_unit != NULL)
558 {
559 if (m_include_support_files)
560 {
561 FileSpecList supporting_files = context.comp_unit->GetSupportFiles();
562 for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++)
563 {
564 const FileSpec &sfile_spec = supporting_files.GetFileSpecAtIndex(sfiles);
565 const char *sfile_file_name = sfile_spec.GetFilename().GetCString();
566 const char *sfile_dir_name = sfile_spec.GetFilename().GetCString();
567 bool match = false;
568 if (m_file_name && sfile_file_name
569 && strstr (sfile_file_name, m_file_name) == sfile_file_name)
570 match = true;
571 if (match && m_dir_name && sfile_dir_name
572 && strstr (sfile_dir_name, m_dir_name) != sfile_dir_name)
573 match = false;
574
575 if (match)
576 {
577 m_matching_files.AppendIfUnique(sfile_spec);
578 }
579 }
580
581 }
582 else
583 {
584 const char *cur_file_name = context.comp_unit->GetFilename().GetCString();
585 const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString();
586
587 bool match = false;
588 if (m_file_name && cur_file_name
589 && strstr (cur_file_name, m_file_name) == cur_file_name)
590 match = true;
591
592 if (match && m_dir_name && cur_dir_name
593 && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
594 match = false;
595
596 if (match)
597 {
598 m_matching_files.AppendIfUnique(context.comp_unit);
599 }
600 }
601 }
602 return Searcher::eCallbackReturnContinue;
603}
604
605size_t
606CommandCompletions::SourceFileCompleter::DoCompletion (SearchFilter *filter)
607{
608 filter->Search (*this);
609 // Now convert the filelist to completions:
610 for (size_t i = 0; i < m_matching_files.GetSize(); i++)
611 {
612 m_matches.AppendString (m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
613 }
614 return m_matches.GetSize();
615
616}
617
618//----------------------------------------------------------------------
619// SymbolCompleter
620//----------------------------------------------------------------------
621
622static bool
623regex_chars (const char comp)
624{
Greg Clayton649f8b92013-06-07 00:35:40 +0000625 if (comp == '[' || comp == ']' ||
626 comp == '(' || comp == ')' ||
627 comp == '{' || comp == '}' ||
628 comp == '+' ||
629 comp == '.' ||
630 comp == '*' ||
631 comp == '|' ||
632 comp == '^' ||
633 comp == '$' ||
634 comp == '\\' ||
635 comp == '?')
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000636 return true;
637 else
638 return false;
639}
Greg Clayton66111032010-06-23 01:19:29 +0000640CommandCompletions::SymbolCompleter::SymbolCompleter
641(
642 CommandInterpreter &interpreter,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000643 const char *completion_str,
644 int match_start_point,
645 int max_return_elements,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000646 StringList &matches
647) :
Greg Clayton66111032010-06-23 01:19:29 +0000648 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000649{
Greg Clayton649f8b92013-06-07 00:35:40 +0000650 std::string regex_str;
651 if (completion_str && completion_str[0])
652 {
653 regex_str.append("^");
654 regex_str.append(completion_str);
655 }
656 else
657 {
658 // Match anything since the completion string is empty
659 regex_str.append(".");
660 }
661 std::string::iterator pos = find_if(regex_str.begin() + 1, regex_str.end(), regex_chars);
662 while (pos < regex_str.end())
663 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000664 pos = regex_str.insert(pos, '\\');
Greg Clayton649f8b92013-06-07 00:35:40 +0000665 pos = find_if(pos + 2, regex_str.end(), regex_chars);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000666 }
667 m_regex.Compile(regex_str.c_str());
668}
669
670Searcher::Depth
671CommandCompletions::SymbolCompleter::GetDepth()
672{
673 return eDepthModule;
674}
675
676Searcher::CallbackReturn
677CommandCompletions::SymbolCompleter::SearchCallback (
678 SearchFilter &filter,
679 SymbolContext &context,
680 Address *addr,
681 bool complete
682)
683{
Greg Clayton931180e2011-01-27 06:44:37 +0000684 if (context.module_sp)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000685 {
Greg Clayton931180e2011-01-27 06:44:37 +0000686 SymbolContextList sc_list;
687 const bool include_symbols = true;
Sean Callanan9df05fb2012-02-10 22:52:19 +0000688 const bool include_inlines = true;
Greg Clayton931180e2011-01-27 06:44:37 +0000689 const bool append = true;
Sean Callanan9df05fb2012-02-10 22:52:19 +0000690 context.module_sp->FindFunctions (m_regex, include_symbols, include_inlines, append, sc_list);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000691
692 SymbolContext sc;
693 // Now add the functions & symbols to the list - only add if unique:
Greg Clayton931180e2011-01-27 06:44:37 +0000694 for (uint32_t i = 0; i < sc_list.GetSize(); i++)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000695 {
Greg Clayton931180e2011-01-27 06:44:37 +0000696 if (sc_list.GetContextAtIndex(i, sc))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000697 {
Jim Ingham530a4132011-09-27 19:48:20 +0000698 ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
699 if (!func_name.IsEmpty())
700 m_match_set.insert (func_name);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000701 }
702 }
703 }
704 return Searcher::eCallbackReturnContinue;
705}
706
707size_t
708CommandCompletions::SymbolCompleter::DoCompletion (SearchFilter *filter)
709{
710 filter->Search (*this);
711 collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
712 for (pos = m_match_set.begin(); pos != end; pos++)
713 m_matches.AppendString((*pos).GetCString());
714
715 return m_matches.GetSize();
716}
717
718//----------------------------------------------------------------------
719// ModuleCompleter
720//----------------------------------------------------------------------
Greg Clayton66111032010-06-23 01:19:29 +0000721CommandCompletions::ModuleCompleter::ModuleCompleter
722(
723 CommandInterpreter &interpreter,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000724 const char *completion_str,
725 int match_start_point,
726 int max_return_elements,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000727 StringList &matches
728) :
Greg Clayton66111032010-06-23 01:19:29 +0000729 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000730{
Greg Clayton274060b2010-10-20 20:54:39 +0000731 FileSpec partial_spec (m_completion_str.c_str(), false);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000732 m_file_name = partial_spec.GetFilename().GetCString();
733 m_dir_name = partial_spec.GetDirectory().GetCString();
734}
735
736Searcher::Depth
737CommandCompletions::ModuleCompleter::GetDepth()
738{
739 return eDepthModule;
740}
741
742Searcher::CallbackReturn
743CommandCompletions::ModuleCompleter::SearchCallback (
744 SearchFilter &filter,
745 SymbolContext &context,
746 Address *addr,
747 bool complete
748)
749{
Greg Clayton747bcb02011-09-17 06:21:20 +0000750 if (context.module_sp)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000751 {
752 const char *cur_file_name = context.module_sp->GetFileSpec().GetFilename().GetCString();
753 const char *cur_dir_name = context.module_sp->GetFileSpec().GetDirectory().GetCString();
754
755 bool match = false;
756 if (m_file_name && cur_file_name
757 && strstr (cur_file_name, m_file_name) == cur_file_name)
758 match = true;
759
760 if (match && m_dir_name && cur_dir_name
761 && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
762 match = false;
763
764 if (match)
765 {
766 m_matches.AppendString (cur_file_name);
767 }
768 }
769 return Searcher::eCallbackReturnContinue;
770}
771
772size_t
773CommandCompletions::ModuleCompleter::DoCompletion (SearchFilter *filter)
774{
775 filter->Search (*this);
776 return m_matches.GetSize();
777}