blob: 919b18fdaefffdd00ee8a1f01deda20e89781a54 [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
Chris Lattner30fdc8d2010-06-08 16:52:24 +000010// C Includes
Jim Ingham558ce122010-06-30 05:02:46 +000011#include <sys/stat.h>
Greg Claytonfd184262011-02-05 02:27:52 +000012#if defined(__APPLE__) || defined(__linux__)
Jim Ingham7cc478b2010-07-02 00:45:55 +000013#include <pwd.h>
Greg Claytonfd184262011-02-05 02:27:52 +000014#endif
Jim Ingham558ce122010-06-30 05:02:46 +000015
Chris Lattner30fdc8d2010-06-08 16:52:24 +000016// C++ Includes
17// Other libraries and framework includes
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +000018#include "llvm/ADT/SmallString.h"
19
Chris Lattner30fdc8d2010-06-08 16:52:24 +000020// 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"
Zachary Turner633a29c2015-03-04 01:58:01 +000028#include "lldb/Interpreter/OptionValueProperties.h"
Greg Clayton1f746072012-08-29 21:13:06 +000029#include "lldb/Symbol/CompileUnit.h"
Greg Claytonf21fead2013-05-14 23:43:18 +000030#include "lldb/Symbol/Variable.h"
Greg Clayton9b62fd22011-02-01 05:15:22 +000031#include "lldb/Target/Target.h"
32#include "lldb/Utility/CleanUp.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000033
34using namespace lldb_private;
35
36CommandCompletions::CommonCompletionElement
37CommandCompletions::g_common_completions[] =
38{
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +000039 {eCustomCompletion, nullptr},
Jim Ingham558ce122010-06-30 05:02:46 +000040 {eSourceFileCompletion, CommandCompletions::SourceFiles},
41 {eDiskFileCompletion, CommandCompletions::DiskFiles},
42 {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
43 {eSymbolCompletion, CommandCompletions::Symbols},
44 {eModuleCompletion, CommandCompletions::Modules},
Caroline Tice3df9a8d2010-09-04 00:03:46 +000045 {eSettingsNameCompletion, CommandCompletions::SettingsNames},
Greg Claytonab65b342011-04-13 22:47:15 +000046 {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames},
47 {eArchitectureCompletion, CommandCompletions::ArchitectureNames},
Greg Claytonf21fead2013-05-14 23:43:18 +000048 {eVariablePathCompletion, CommandCompletions::VariablePath},
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +000049 {eNoCompletion, nullptr} // This one has to be last in the list.
Chris Lattner30fdc8d2010-06-08 16:52:24 +000050};
51
52bool
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +000053CommandCompletions::InvokeCommonCompletionCallbacks(CommandInterpreter &interpreter,
54 uint32_t completion_mask,
55 const char *completion_str,
56 int match_start_point,
57 int max_return_elements,
58 SearchFilter *searcher,
59 bool &word_complete,
60 StringList &matches)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000061{
62 bool handled = false;
63
64 if (completion_mask & eCustomCompletion)
65 return false;
66
67 for (int i = 0; ; i++)
68 {
69 if (g_common_completions[i].type == eNoCompletion)
70 break;
71 else if ((g_common_completions[i].type & completion_mask) == g_common_completions[i].type
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +000072 && g_common_completions[i].callback != nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000073 {
74 handled = true;
Greg Clayton66111032010-06-23 01:19:29 +000075 g_common_completions[i].callback (interpreter,
76 completion_str,
Chris Lattner30fdc8d2010-06-08 16:52:24 +000077 match_start_point,
78 max_return_elements,
Chris Lattner30fdc8d2010-06-08 16:52:24 +000079 searcher,
Jim Ingham558ce122010-06-30 05:02:46 +000080 word_complete,
Chris Lattner30fdc8d2010-06-08 16:52:24 +000081 matches);
82 }
83 }
84 return handled;
85}
86
87int
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +000088CommandCompletions::SourceFiles(CommandInterpreter &interpreter,
89 const char *partial_file_name,
90 int match_start_point,
91 int max_return_elements,
92 SearchFilter *searcher,
93 bool &word_complete,
94 StringList &matches)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000095{
Jim Ingham558ce122010-06-30 05:02:46 +000096 word_complete = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000097 // Find some way to switch "include support files..."
Greg Clayton66111032010-06-23 01:19:29 +000098 SourceFileCompleter completer (interpreter,
99 false,
100 partial_file_name,
101 match_start_point,
102 max_return_elements,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000103 matches);
104
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000105 if (searcher == nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000106 {
Jim Ingham2976d002010-08-26 21:32:51 +0000107 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
Jim Ingham33df7cd2014-12-06 01:28:03 +0000108 SearchFilterForUnconstrainedSearches null_searcher (target_sp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000109 completer.DoCompletion (&null_searcher);
110 }
111 else
112 {
113 completer.DoCompletion (searcher);
114 }
115 return matches.GetSize();
116}
117
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000118typedef struct DiskFilesOrDirectoriesBaton
119{
120 const char *remainder;
121 char *partial_name_copy;
122 bool only_directories;
123 bool *saw_directory;
124 StringList *matches;
125 char *end_ptr;
126 size_t baselen;
Michael Sartain0b5e5f42013-08-26 17:07:34 +0000127} DiskFilesOrDirectoriesBaton;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000128
129FileSpec::EnumerateDirectoryResult DiskFilesOrDirectoriesCallback(void *baton, FileSpec::FileType file_type, const FileSpec &spec)
130{
131 const char *name = spec.GetFilename().AsCString();
132
133 const DiskFilesOrDirectoriesBaton *parameters = (DiskFilesOrDirectoriesBaton*)baton;
134 char *end_ptr = parameters->end_ptr;
135 char *partial_name_copy = parameters->partial_name_copy;
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000136 const char *remainder = parameters->remainder;
137
138 // Omit ".", ".." and any . files if the match string doesn't start with .
139 if (name[0] == '.')
140 {
141 if (name[1] == '\0')
142 return FileSpec::eEnumerateDirectoryResultNext;
143 else if (name[1] == '.' && name[2] == '\0')
144 return FileSpec::eEnumerateDirectoryResultNext;
145 else if (remainder[0] != '.')
146 return FileSpec::eEnumerateDirectoryResultNext;
147 }
148
149 // If we found a directory, we put a "/" at the end of the name.
150
151 if (remainder[0] == '\0' || strstr(name, remainder) == name)
152 {
153 if (strlen(name) + parameters->baselen >= PATH_MAX)
154 return FileSpec::eEnumerateDirectoryResultNext;
155
156 strcpy(end_ptr, name);
157
158 bool isa_directory = false;
159 if (file_type == FileSpec::eFileTypeDirectory)
160 isa_directory = true;
161 else if (file_type == FileSpec::eFileTypeSymbolicLink)
162 {
163 struct stat stat_buf;
164 if ((stat(partial_name_copy, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode))
165 isa_directory = true;
166 }
167
168 if (isa_directory)
169 {
170 *parameters->saw_directory = true;
171 size_t len = strlen(parameters->partial_name_copy);
172 partial_name_copy[len] = '/';
173 partial_name_copy[len + 1] = '\0';
174 }
175 if (parameters->only_directories && !isa_directory)
176 return FileSpec::eEnumerateDirectoryResultNext;
177 parameters->matches->AppendString(partial_name_copy);
178 }
179
180 return FileSpec::eEnumerateDirectoryResultNext;
181}
182
Jim Ingham558ce122010-06-30 05:02:46 +0000183static int
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000184DiskFilesOrDirectories(const char *partial_file_name,
185 bool only_directories,
186 bool &saw_directory,
187 StringList &matches)
Jim Ingham558ce122010-06-30 05:02:46 +0000188{
189 // I'm going to use the "glob" function with GLOB_TILDE for user directory expansion.
190 // If it is not defined on your host system, you'll need to implement it yourself...
191
Greg Claytonc7bece562013-01-25 18:06:21 +0000192 size_t partial_name_len = strlen(partial_file_name);
Jim Ingham558ce122010-06-30 05:02:46 +0000193
194 if (partial_name_len >= PATH_MAX)
195 return matches.GetSize();
196
197 // This copy of the string will be cut up into the directory part, and the remainder. end_ptr
198 // below will point to the place of the remainder in this string. Then when we've resolved the
199 // containing directory, and opened it, we'll read the directory contents and overwrite the
200 // partial_name_copy starting from end_ptr with each of the matches. Thus we will preserve
201 // the form the user originally typed.
202
203 char partial_name_copy[PATH_MAX];
Benjamin Kramer021b6052010-06-30 13:43:47 +0000204 memcpy(partial_name_copy, partial_file_name, partial_name_len);
Jim Ingham558ce122010-06-30 05:02:46 +0000205 partial_name_copy[partial_name_len] = '\0';
206
Greg Clayton710dd5a2011-01-08 20:28:42 +0000207 // We'll need to save a copy of the remainder for comparison, which we do here.
Jim Ingham558ce122010-06-30 05:02:46 +0000208 char remainder[PATH_MAX];
209
210 // end_ptr will point past the last / in partial_name_copy, or if there is no slash to the beginning of the string.
211 char *end_ptr;
212
213 end_ptr = strrchr(partial_name_copy, '/');
214
215 // This will store the resolved form of the containing directory
Zachary Turner3f559742014-08-07 17:33:36 +0000216 llvm::SmallString<64> containing_part;
Jim Ingham558ce122010-06-30 05:02:46 +0000217
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000218 if (end_ptr == nullptr)
Jim Ingham558ce122010-06-30 05:02:46 +0000219 {
220 // There's no directory. If the thing begins with a "~" then this is a bare
221 // user name.
222 if (*partial_name_copy == '~')
223 {
224 // Nothing here but the user name. We could just put a slash on the end,
Jim Ingham7cc478b2010-07-02 00:45:55 +0000225 // but for completeness sake we'll resolve the user name and only put a slash
Jim Ingham558ce122010-06-30 05:02:46 +0000226 // on the end if it exists.
Zachary Turner3f559742014-08-07 17:33:36 +0000227 llvm::SmallString<64> resolved_username(partial_name_copy);
228 FileSpec::ResolveUsername (resolved_username);
Jim Ingham7cc478b2010-07-02 00:45:55 +0000229
230 // Not sure how this would happen, a username longer than PATH_MAX? Still...
Zachary Turner3f559742014-08-07 17:33:36 +0000231 if (resolved_username.size() == 0)
Jim Ingham7cc478b2010-07-02 00:45:55 +0000232 {
233 // The user name didn't resolve, let's look in the password database for matches.
234 // The user name database contains duplicates, and is not in alphabetical order, so
235 // we'll use a set to manage that for us.
Jim Ingham84363072011-02-08 23:24:09 +0000236 FileSpec::ResolvePartialUsername (partial_name_copy, matches);
237 if (matches.GetSize() > 0)
238 saw_directory = true;
Jim Ingham7cc478b2010-07-02 00:45:55 +0000239 return matches.GetSize();
Jim Ingham84363072011-02-08 23:24:09 +0000240 }
241 else
242 {
243 //The thing exists, put a '/' on the end, and return it...
244 // FIXME: complete user names here:
245 partial_name_copy[partial_name_len] = '/';
246 partial_name_copy[partial_name_len+1] = '\0';
247 matches.AppendString(partial_name_copy);
248 saw_directory = true;
249 return matches.GetSize();
250 }
Jim Ingham558ce122010-06-30 05:02:46 +0000251 }
252 else
253 {
254 // The containing part is the CWD, and the whole string is the remainder.
Zachary Turner3f559742014-08-07 17:33:36 +0000255 containing_part = ".";
Jim Ingham558ce122010-06-30 05:02:46 +0000256 strcpy(remainder, partial_name_copy);
257 end_ptr = partial_name_copy;
258 }
259 }
260 else
261 {
262 if (end_ptr == partial_name_copy)
263 {
264 // We're completing a file or directory in the root volume.
Zachary Turner3f559742014-08-07 17:33:36 +0000265 containing_part = "/";
Jim Ingham558ce122010-06-30 05:02:46 +0000266 }
267 else
268 {
Zachary Turner3f559742014-08-07 17:33:36 +0000269 containing_part.append(partial_name_copy, end_ptr);
Jim Ingham558ce122010-06-30 05:02:46 +0000270 }
271 // Push end_ptr past the final "/" and set remainder.
272 end_ptr++;
273 strcpy(remainder, end_ptr);
274 }
275
Jim Ingham7cc478b2010-07-02 00:45:55 +0000276 // 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 +0000277 // result back into the containing_part:
Greg Claytonfd184262011-02-05 02:27:52 +0000278
Jim Ingham558ce122010-06-30 05:02:46 +0000279 if (*partial_name_copy == '~')
280 {
Zachary Turner3f559742014-08-07 17:33:36 +0000281 FileSpec::ResolveUsername(containing_part);
Jim Ingham558ce122010-06-30 05:02:46 +0000282 // User name doesn't exist, we're not getting any further...
Zachary Turner3f559742014-08-07 17:33:36 +0000283 if (containing_part.empty())
Jim Ingham558ce122010-06-30 05:02:46 +0000284 return matches.GetSize();
Jim Ingham558ce122010-06-30 05:02:46 +0000285 }
Greg Claytonfd184262011-02-05 02:27:52 +0000286
Jim Ingham558ce122010-06-30 05:02:46 +0000287 // Okay, containing_part is now the directory we want to open and look for files:
Greg Clayton9b62fd22011-02-01 05:15:22 +0000288
Jim Ingham558ce122010-06-30 05:02:46 +0000289 size_t baselen = end_ptr - partial_name_copy;
290
Virgile Bellob2f1fb22013-08-23 12:44:05 +0000291 DiskFilesOrDirectoriesBaton parameters;
292 parameters.remainder = remainder;
293 parameters.partial_name_copy = partial_name_copy;
294 parameters.only_directories = only_directories;
295 parameters.saw_directory = &saw_directory;
296 parameters.matches = &matches;
297 parameters.end_ptr = end_ptr;
298 parameters.baselen = baselen;
299
Zachary Turner3f559742014-08-07 17:33:36 +0000300 FileSpec::EnumerateDirectory(containing_part.c_str(), true, true, true, DiskFilesOrDirectoriesCallback, &parameters);
Jim Ingham558ce122010-06-30 05:02:46 +0000301
302 return matches.GetSize();
303}
304
305int
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000306CommandCompletions::DiskFiles(CommandInterpreter &interpreter,
307 const char *partial_file_name,
308 int match_start_point,
309 int max_return_elements,
310 SearchFilter *searcher,
311 bool &word_complete,
312 StringList &matches)
Jim Ingham558ce122010-06-30 05:02:46 +0000313{
Jim Ingham558ce122010-06-30 05:02:46 +0000314 int ret_val = DiskFilesOrDirectories (partial_file_name,
315 false,
316 word_complete,
317 matches);
318 word_complete = !word_complete;
319 return ret_val;
320}
321
322int
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000323CommandCompletions::DiskDirectories(CommandInterpreter &interpreter,
324 const char *partial_file_name,
325 int match_start_point,
326 int max_return_elements,
327 SearchFilter *searcher,
328 bool &word_complete,
329 StringList &matches)
Jim Ingham558ce122010-06-30 05:02:46 +0000330{
331 int ret_val = DiskFilesOrDirectories (partial_file_name,
332 true,
333 word_complete,
334 matches);
335 word_complete = false;
336 return ret_val;
337}
338
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000339int
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000340CommandCompletions::Modules(CommandInterpreter &interpreter,
341 const char *partial_file_name,
342 int match_start_point,
343 int max_return_elements,
344 SearchFilter *searcher,
345 bool &word_complete,
346 StringList &matches)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000347{
Jim Ingham558ce122010-06-30 05:02:46 +0000348 word_complete = true;
Greg Clayton66111032010-06-23 01:19:29 +0000349 ModuleCompleter completer (interpreter,
350 partial_file_name,
351 match_start_point,
352 max_return_elements,
353 matches);
354
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000355 if (searcher == nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000356 {
Jim Ingham2976d002010-08-26 21:32:51 +0000357 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
Jim Ingham33df7cd2014-12-06 01:28:03 +0000358 SearchFilterForUnconstrainedSearches null_searcher (target_sp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000359 completer.DoCompletion (&null_searcher);
360 }
361 else
362 {
363 completer.DoCompletion (searcher);
364 }
365 return matches.GetSize();
366}
367
368int
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000369CommandCompletions::Symbols(CommandInterpreter &interpreter,
370 const char *partial_file_name,
371 int match_start_point,
372 int max_return_elements,
373 SearchFilter *searcher,
374 bool &word_complete,
375 StringList &matches)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000376{
Jim Ingham558ce122010-06-30 05:02:46 +0000377 word_complete = true;
Greg Clayton66111032010-06-23 01:19:29 +0000378 SymbolCompleter completer (interpreter,
379 partial_file_name,
380 match_start_point,
381 max_return_elements,
382 matches);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000383
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000384 if (searcher == nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000385 {
Jim Ingham2976d002010-08-26 21:32:51 +0000386 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
Jim Ingham33df7cd2014-12-06 01:28:03 +0000387 SearchFilterForUnconstrainedSearches null_searcher (target_sp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000388 completer.DoCompletion (&null_searcher);
389 }
390 else
391 {
392 completer.DoCompletion (searcher);
393 }
394 return matches.GetSize();
395}
396
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000397int
398CommandCompletions::SettingsNames (CommandInterpreter &interpreter,
399 const char *partial_setting_name,
400 int match_start_point,
401 int max_return_elements,
402 SearchFilter *searcher,
403 bool &word_complete,
404 StringList &matches)
405{
Greg Clayton67cc0632012-08-22 17:17:09 +0000406 // Cache the full setting name list
407 static StringList g_property_names;
408 if (g_property_names.GetSize() == 0)
409 {
410 // Generate the full setting name list on demand
411 lldb::OptionValuePropertiesSP properties_sp (interpreter.GetDebugger().GetValueProperties());
412 if (properties_sp)
413 {
414 StreamString strm;
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000415 properties_sp->DumpValue(nullptr, strm, OptionValue::eDumpOptionName);
Greg Clayton67cc0632012-08-22 17:17:09 +0000416 const std::string &str = strm.GetString();
417 g_property_names.SplitIntoLines(str.c_str(), str.size());
418 }
419 }
420
421 size_t exact_matches_idx = SIZE_MAX;
422 const size_t num_matches = g_property_names.AutoComplete (partial_setting_name, matches, exact_matches_idx);
Greg Clayton67cc0632012-08-22 17:17:09 +0000423 word_complete = exact_matches_idx != SIZE_MAX;
424 return num_matches;
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000425}
426
Greg Claytonab65b342011-04-13 22:47:15 +0000427int
428CommandCompletions::PlatformPluginNames (CommandInterpreter &interpreter,
429 const char *partial_name,
430 int match_start_point,
431 int max_return_elements,
432 SearchFilter *searcher,
433 bool &word_complete,
434 lldb_private::StringList &matches)
435{
436 const uint32_t num_matches = PluginManager::AutoCompletePlatformName(partial_name, matches);
437 word_complete = num_matches == 1;
438 return num_matches;
439}
440
441int
442CommandCompletions::ArchitectureNames (CommandInterpreter &interpreter,
443 const char *partial_name,
444 int match_start_point,
445 int max_return_elements,
446 SearchFilter *searcher,
447 bool &word_complete,
448 lldb_private::StringList &matches)
449{
450 const uint32_t num_matches = ArchSpec::AutoComplete (partial_name, matches);
451 word_complete = num_matches == 1;
452 return num_matches;
453}
454
Greg Claytonf21fead2013-05-14 23:43:18 +0000455int
456CommandCompletions::VariablePath (CommandInterpreter &interpreter,
457 const char *partial_name,
458 int match_start_point,
459 int max_return_elements,
460 SearchFilter *searcher,
461 bool &word_complete,
462 lldb_private::StringList &matches)
463{
464 return Variable::AutoComplete (interpreter.GetExecutionContext(), partial_name, matches, word_complete);
465}
466
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000467CommandCompletions::Completer::Completer(CommandInterpreter &interpreter,
468 const char *completion_str,
469 int match_start_point,
470 int max_return_elements,
471 StringList &matches) :
Greg Clayton66111032010-06-23 01:19:29 +0000472 m_interpreter (interpreter),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000473 m_completion_str (completion_str),
474 m_match_start_point (match_start_point),
475 m_max_return_elements (max_return_elements),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000476 m_matches (matches)
477{
478}
479
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000480CommandCompletions::Completer::~Completer() = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000481
482//----------------------------------------------------------------------
483// SourceFileCompleter
484//----------------------------------------------------------------------
485
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000486CommandCompletions::SourceFileCompleter::SourceFileCompleter(CommandInterpreter &interpreter,
487 bool include_support_files,
488 const char *completion_str,
489 int match_start_point,
490 int max_return_elements,
491 StringList &matches) :
Greg Clayton66111032010-06-23 01:19:29 +0000492 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000493 m_include_support_files (include_support_files),
494 m_matching_files()
495{
Greg Clayton274060b2010-10-20 20:54:39 +0000496 FileSpec partial_spec (m_completion_str.c_str(), false);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000497 m_file_name = partial_spec.GetFilename().GetCString();
498 m_dir_name = partial_spec.GetDirectory().GetCString();
499}
500
501Searcher::Depth
502CommandCompletions::SourceFileCompleter::GetDepth()
503{
504 return eDepthCompUnit;
505}
506
507Searcher::CallbackReturn
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000508CommandCompletions::SourceFileCompleter::SearchCallback(SearchFilter &filter,
509 SymbolContext &context,
510 Address *addr,
511 bool complete)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000512{
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000513 if (context.comp_unit != nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000514 {
515 if (m_include_support_files)
516 {
517 FileSpecList supporting_files = context.comp_unit->GetSupportFiles();
518 for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++)
519 {
520 const FileSpec &sfile_spec = supporting_files.GetFileSpecAtIndex(sfiles);
521 const char *sfile_file_name = sfile_spec.GetFilename().GetCString();
522 const char *sfile_dir_name = sfile_spec.GetFilename().GetCString();
523 bool match = false;
524 if (m_file_name && sfile_file_name
525 && strstr (sfile_file_name, m_file_name) == sfile_file_name)
526 match = true;
527 if (match && m_dir_name && sfile_dir_name
528 && strstr (sfile_dir_name, m_dir_name) != sfile_dir_name)
529 match = false;
530
531 if (match)
532 {
533 m_matching_files.AppendIfUnique(sfile_spec);
534 }
535 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000536 }
537 else
538 {
539 const char *cur_file_name = context.comp_unit->GetFilename().GetCString();
540 const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString();
541
542 bool match = false;
543 if (m_file_name && cur_file_name
544 && strstr (cur_file_name, m_file_name) == cur_file_name)
545 match = true;
546
547 if (match && m_dir_name && cur_dir_name
548 && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
549 match = false;
550
551 if (match)
552 {
553 m_matching_files.AppendIfUnique(context.comp_unit);
554 }
555 }
556 }
557 return Searcher::eCallbackReturnContinue;
558}
559
560size_t
561CommandCompletions::SourceFileCompleter::DoCompletion (SearchFilter *filter)
562{
563 filter->Search (*this);
564 // Now convert the filelist to completions:
565 for (size_t i = 0; i < m_matching_files.GetSize(); i++)
566 {
567 m_matches.AppendString (m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
568 }
569 return m_matches.GetSize();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000570}
571
572//----------------------------------------------------------------------
573// SymbolCompleter
574//----------------------------------------------------------------------
575
576static bool
577regex_chars (const char comp)
578{
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000579 return (comp == '[' || comp == ']' ||
580 comp == '(' || comp == ')' ||
581 comp == '{' || comp == '}' ||
582 comp == '+' ||
583 comp == '.' ||
584 comp == '*' ||
585 comp == '|' ||
586 comp == '^' ||
587 comp == '$' ||
588 comp == '\\' ||
589 comp == '?');
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000590}
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000591
592CommandCompletions::SymbolCompleter::SymbolCompleter(CommandInterpreter &interpreter,
593 const char *completion_str,
594 int match_start_point,
595 int max_return_elements,
596 StringList &matches) :
Greg Clayton66111032010-06-23 01:19:29 +0000597 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000598{
Greg Clayton649f8b92013-06-07 00:35:40 +0000599 std::string regex_str;
600 if (completion_str && completion_str[0])
601 {
602 regex_str.append("^");
603 regex_str.append(completion_str);
604 }
605 else
606 {
607 // Match anything since the completion string is empty
608 regex_str.append(".");
609 }
610 std::string::iterator pos = find_if(regex_str.begin() + 1, regex_str.end(), regex_chars);
611 while (pos < regex_str.end())
612 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000613 pos = regex_str.insert(pos, '\\');
Greg Clayton649f8b92013-06-07 00:35:40 +0000614 pos = find_if(pos + 2, regex_str.end(), regex_chars);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000615 }
616 m_regex.Compile(regex_str.c_str());
617}
618
619Searcher::Depth
620CommandCompletions::SymbolCompleter::GetDepth()
621{
622 return eDepthModule;
623}
624
625Searcher::CallbackReturn
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000626CommandCompletions::SymbolCompleter::SearchCallback(SearchFilter &filter,
627 SymbolContext &context,
628 Address *addr,
629 bool complete)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000630{
Greg Clayton931180e2011-01-27 06:44:37 +0000631 if (context.module_sp)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000632 {
Greg Clayton931180e2011-01-27 06:44:37 +0000633 SymbolContextList sc_list;
634 const bool include_symbols = true;
Sean Callanan9df05fb2012-02-10 22:52:19 +0000635 const bool include_inlines = true;
Greg Clayton931180e2011-01-27 06:44:37 +0000636 const bool append = true;
Sean Callanan9df05fb2012-02-10 22:52:19 +0000637 context.module_sp->FindFunctions (m_regex, include_symbols, include_inlines, append, sc_list);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000638
639 SymbolContext sc;
640 // Now add the functions & symbols to the list - only add if unique:
Greg Clayton931180e2011-01-27 06:44:37 +0000641 for (uint32_t i = 0; i < sc_list.GetSize(); i++)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000642 {
Greg Clayton931180e2011-01-27 06:44:37 +0000643 if (sc_list.GetContextAtIndex(i, sc))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000644 {
Jim Ingham530a4132011-09-27 19:48:20 +0000645 ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
646 if (!func_name.IsEmpty())
647 m_match_set.insert (func_name);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000648 }
649 }
650 }
651 return Searcher::eCallbackReturnContinue;
652}
653
654size_t
655CommandCompletions::SymbolCompleter::DoCompletion (SearchFilter *filter)
656{
657 filter->Search (*this);
658 collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
659 for (pos = m_match_set.begin(); pos != end; pos++)
660 m_matches.AppendString((*pos).GetCString());
661
662 return m_matches.GetSize();
663}
664
665//----------------------------------------------------------------------
666// ModuleCompleter
667//----------------------------------------------------------------------
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000668CommandCompletions::ModuleCompleter::ModuleCompleter(CommandInterpreter &interpreter,
669 const char *completion_str,
670 int match_start_point,
671 int max_return_elements,
672 StringList &matches) :
Greg Clayton66111032010-06-23 01:19:29 +0000673 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000674{
Greg Clayton274060b2010-10-20 20:54:39 +0000675 FileSpec partial_spec (m_completion_str.c_str(), false);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000676 m_file_name = partial_spec.GetFilename().GetCString();
677 m_dir_name = partial_spec.GetDirectory().GetCString();
678}
679
680Searcher::Depth
681CommandCompletions::ModuleCompleter::GetDepth()
682{
683 return eDepthModule;
684}
685
686Searcher::CallbackReturn
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000687CommandCompletions::ModuleCompleter::SearchCallback(SearchFilter &filter,
688 SymbolContext &context,
689 Address *addr,
690 bool complete)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000691{
Greg Clayton747bcb02011-09-17 06:21:20 +0000692 if (context.module_sp)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000693 {
694 const char *cur_file_name = context.module_sp->GetFileSpec().GetFilename().GetCString();
695 const char *cur_dir_name = context.module_sp->GetFileSpec().GetDirectory().GetCString();
696
697 bool match = false;
698 if (m_file_name && cur_file_name
699 && strstr (cur_file_name, m_file_name) == cur_file_name)
700 match = true;
701
702 if (match && m_dir_name && cur_dir_name
703 && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
704 match = false;
705
706 if (match)
707 {
708 m_matches.AppendString (cur_file_name);
709 }
710 }
711 return Searcher::eCallbackReturnContinue;
712}
713
714size_t
715CommandCompletions::ModuleCompleter::DoCompletion (SearchFilter *filter)
716{
717 filter->Search (*this);
718 return m_matches.GetSize();
719}