blob: 5eebc787a4093bd5ea2b9b7394d377335795f005 [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 Clayton9b62fd22011-02-01 05:15:22 +000021#include "lldb/Core/FileSpecList.h"
Greg Clayton1f746072012-08-29 21:13:06 +000022#include "lldb/Core/Module.h"
Zachary Turner190fadc2016-03-22 17:58:09 +000023#include "lldb/Core/PluginManager.h"
24#include "lldb/Host/FileSpec.h"
25#include "lldb/Host/FileSystem.h"
Greg Clayton9b62fd22011-02-01 05:15:22 +000026#include "lldb/Interpreter/Args.h"
27#include "lldb/Interpreter/CommandCompletions.h"
28#include "lldb/Interpreter/CommandInterpreter.h"
Zachary Turner633a29c2015-03-04 01:58:01 +000029#include "lldb/Interpreter/OptionValueProperties.h"
Greg Clayton1f746072012-08-29 21:13:06 +000030#include "lldb/Symbol/CompileUnit.h"
Greg Claytonf21fead2013-05-14 23:43:18 +000031#include "lldb/Symbol/Variable.h"
Greg Clayton9b62fd22011-02-01 05:15:22 +000032#include "lldb/Target/Target.h"
33#include "lldb/Utility/CleanUp.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000034
Zachary Turner190fadc2016-03-22 17:58:09 +000035#include "llvm/ADT/SmallString.h"
36
Chris Lattner30fdc8d2010-06-08 16:52:24 +000037using namespace lldb_private;
38
39CommandCompletions::CommonCompletionElement
Kate Stoneb9c1b512016-09-06 20:57:50 +000040 CommandCompletions::g_common_completions[] = {
41 {eCustomCompletion, nullptr},
42 {eSourceFileCompletion, CommandCompletions::SourceFiles},
43 {eDiskFileCompletion, CommandCompletions::DiskFiles},
44 {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
45 {eSymbolCompletion, CommandCompletions::Symbols},
46 {eModuleCompletion, CommandCompletions::Modules},
47 {eSettingsNameCompletion, CommandCompletions::SettingsNames},
48 {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames},
49 {eArchitectureCompletion, CommandCompletions::ArchitectureNames},
50 {eVariablePathCompletion, CommandCompletions::VariablePath},
51 {eNoCompletion, nullptr} // This one has to be last in the list.
Chris Lattner30fdc8d2010-06-08 16:52:24 +000052};
53
Kate Stoneb9c1b512016-09-06 20:57:50 +000054bool CommandCompletions::InvokeCommonCompletionCallbacks(
55 CommandInterpreter &interpreter, uint32_t completion_mask,
56 const char *completion_str, int match_start_point, int max_return_elements,
57 SearchFilter *searcher, bool &word_complete, StringList &matches) {
58 bool handled = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000059
Kate Stoneb9c1b512016-09-06 20:57:50 +000060 if (completion_mask & eCustomCompletion)
61 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000062
Kate Stoneb9c1b512016-09-06 20:57:50 +000063 for (int i = 0;; i++) {
64 if (g_common_completions[i].type == eNoCompletion)
65 break;
66 else if ((g_common_completions[i].type & completion_mask) ==
67 g_common_completions[i].type &&
68 g_common_completions[i].callback != nullptr) {
69 handled = true;
70 g_common_completions[i].callback(interpreter, completion_str,
71 match_start_point, max_return_elements,
72 searcher, word_complete, matches);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000073 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000074 }
75 return handled;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000076}
77
Kate Stoneb9c1b512016-09-06 20:57:50 +000078int CommandCompletions::SourceFiles(CommandInterpreter &interpreter,
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +000079 const char *partial_file_name,
80 int match_start_point,
81 int max_return_elements,
Kate Stoneb9c1b512016-09-06 20:57:50 +000082 SearchFilter *searcher, bool &word_complete,
83 StringList &matches) {
84 word_complete = true;
85 // Find some way to switch "include support files..."
86 SourceFileCompleter completer(interpreter, false, partial_file_name,
87 match_start_point, max_return_elements,
88 matches);
89
90 if (searcher == nullptr) {
91 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
92 SearchFilterForUnconstrainedSearches null_searcher(target_sp);
93 completer.DoCompletion(&null_searcher);
94 } else {
95 completer.DoCompletion(searcher);
96 }
97 return matches.GetSize();
Jim Ingham558ce122010-06-30 05:02:46 +000098}
99
Kate Stoneb9c1b512016-09-06 20:57:50 +0000100typedef struct DiskFilesOrDirectoriesBaton {
101 const char *remainder;
102 char *partial_name_copy;
103 bool only_directories;
104 bool *saw_directory;
105 StringList *matches;
106 char *end_ptr;
107 size_t baselen;
108} DiskFilesOrDirectoriesBaton;
109
110FileSpec::EnumerateDirectoryResult
111DiskFilesOrDirectoriesCallback(void *baton, FileSpec::FileType file_type,
112 const FileSpec &spec) {
113 const char *name = spec.GetFilename().AsCString();
114
115 const DiskFilesOrDirectoriesBaton *parameters =
116 (DiskFilesOrDirectoriesBaton *)baton;
117 char *end_ptr = parameters->end_ptr;
118 char *partial_name_copy = parameters->partial_name_copy;
119 const char *remainder = parameters->remainder;
120
121 // Omit ".", ".." and any . files if the match string doesn't start with .
122 if (name[0] == '.') {
123 if (name[1] == '\0')
124 return FileSpec::eEnumerateDirectoryResultNext;
125 else if (name[1] == '.' && name[2] == '\0')
126 return FileSpec::eEnumerateDirectoryResultNext;
127 else if (remainder[0] != '.')
128 return FileSpec::eEnumerateDirectoryResultNext;
129 }
130
131 // If we found a directory, we put a "/" at the end of the name.
132
133 if (remainder[0] == '\0' || strstr(name, remainder) == name) {
134 if (strlen(name) + parameters->baselen >= PATH_MAX)
135 return FileSpec::eEnumerateDirectoryResultNext;
136
137 strcpy(end_ptr, name);
138
139 bool isa_directory = false;
140 if (file_type == FileSpec::eFileTypeDirectory)
141 isa_directory = true;
142 else if (file_type == FileSpec::eFileTypeSymbolicLink) {
143 if (FileSpec(partial_name_copy, false).IsDirectory())
144 isa_directory = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000145 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000146
147 if (isa_directory) {
148 *parameters->saw_directory = true;
149 size_t len = strlen(parameters->partial_name_copy);
150 partial_name_copy[len] = '/';
151 partial_name_copy[len + 1] = '\0';
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000152 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000153 if (parameters->only_directories && !isa_directory)
154 return FileSpec::eEnumerateDirectoryResultNext;
155 parameters->matches->AppendString(partial_name_copy);
156 }
157
158 return FileSpec::eEnumerateDirectoryResultNext;
159}
160
161static int DiskFilesOrDirectories(const char *partial_file_name,
162 bool only_directories, bool &saw_directory,
163 StringList &matches) {
164 // I'm going to use the "glob" function with GLOB_TILDE for user directory
165 // expansion.
166 // If it is not defined on your host system, you'll need to implement it
167 // yourself...
168
169 size_t partial_name_len = strlen(partial_file_name);
170
171 if (partial_name_len >= PATH_MAX)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000172 return matches.GetSize();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000173
Kate Stoneb9c1b512016-09-06 20:57:50 +0000174 // This copy of the string will be cut up into the directory part, and the
175 // remainder. end_ptr
176 // below will point to the place of the remainder in this string. Then when
177 // we've resolved the
178 // containing directory, and opened it, we'll read the directory contents and
179 // overwrite the
180 // partial_name_copy starting from end_ptr with each of the matches. Thus we
181 // will preserve
182 // the form the user originally typed.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000183
Kate Stoneb9c1b512016-09-06 20:57:50 +0000184 char partial_name_copy[PATH_MAX];
185 memcpy(partial_name_copy, partial_file_name, partial_name_len);
186 partial_name_copy[partial_name_len] = '\0';
187
188 // We'll need to save a copy of the remainder for comparison, which we do
189 // here.
190 char remainder[PATH_MAX];
191
192 // end_ptr will point past the last / in partial_name_copy, or if there is no
193 // slash to the beginning of the string.
194 char *end_ptr;
195
196 end_ptr = strrchr(partial_name_copy, '/');
197
198 // This will store the resolved form of the containing directory
199 llvm::SmallString<64> containing_part;
200
201 if (end_ptr == nullptr) {
202 // There's no directory. If the thing begins with a "~" then this is a bare
203 // user name.
204 if (*partial_name_copy == '~') {
205 // Nothing here but the user name. We could just put a slash on the end,
206 // but for completeness sake we'll resolve the user name and only put a
207 // slash
208 // on the end if it exists.
209 llvm::SmallString<64> resolved_username(partial_name_copy);
210 FileSpec::ResolveUsername(resolved_username);
211
212 // Not sure how this would happen, a username longer than PATH_MAX?
213 // Still...
214 if (resolved_username.size() == 0) {
215 // The user name didn't resolve, let's look in the password database for
216 // matches.
217 // The user name database contains duplicates, and is not in
218 // alphabetical order, so
219 // we'll use a set to manage that for us.
220 FileSpec::ResolvePartialUsername(partial_name_copy, matches);
221 if (matches.GetSize() > 0)
222 saw_directory = true;
223 return matches.GetSize();
224 } else {
225 // The thing exists, put a '/' on the end, and return it...
226 // FIXME: complete user names here:
227 partial_name_copy[partial_name_len] = '/';
228 partial_name_copy[partial_name_len + 1] = '\0';
229 matches.AppendString(partial_name_copy);
230 saw_directory = true;
231 return matches.GetSize();
232 }
233 } else {
234 // The containing part is the CWD, and the whole string is the remainder.
235 containing_part = ".";
236 strcpy(remainder, partial_name_copy);
237 end_ptr = partial_name_copy;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000238 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000239 } else {
240 if (end_ptr == partial_name_copy) {
241 // We're completing a file or directory in the root volume.
242 containing_part = "/";
243 } else {
244 containing_part.append(partial_name_copy, end_ptr);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000245 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000246 // Push end_ptr past the final "/" and set remainder.
247 end_ptr++;
248 strcpy(remainder, end_ptr);
249 }
250
251 // Look for a user name in the containing part, and if it's there, resolve it
252 // and stick the
253 // result back into the containing_part:
254
255 if (*partial_name_copy == '~') {
256 FileSpec::ResolveUsername(containing_part);
257 // User name doesn't exist, we're not getting any further...
258 if (containing_part.empty())
259 return matches.GetSize();
260 }
261
262 // Okay, containing_part is now the directory we want to open and look for
263 // files:
264
265 size_t baselen = end_ptr - partial_name_copy;
266
267 DiskFilesOrDirectoriesBaton parameters;
268 parameters.remainder = remainder;
269 parameters.partial_name_copy = partial_name_copy;
270 parameters.only_directories = only_directories;
271 parameters.saw_directory = &saw_directory;
272 parameters.matches = &matches;
273 parameters.end_ptr = end_ptr;
274 parameters.baselen = baselen;
275
276 FileSpec::EnumerateDirectory(containing_part.c_str(), true, true, true,
277 DiskFilesOrDirectoriesCallback, &parameters);
278
279 return matches.GetSize();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000280}
281
Kate Stoneb9c1b512016-09-06 20:57:50 +0000282int CommandCompletions::DiskFiles(CommandInterpreter &interpreter,
283 const char *partial_file_name,
Greg Claytonf21fead2013-05-14 23:43:18 +0000284 int match_start_point,
285 int max_return_elements,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000286 SearchFilter *searcher, bool &word_complete,
287 StringList &matches) {
288 int ret_val =
289 DiskFilesOrDirectories(partial_file_name, false, word_complete, matches);
290 word_complete = !word_complete;
291 return ret_val;
292}
293
294int CommandCompletions::DiskDirectories(
295 CommandInterpreter &interpreter, const char *partial_file_name,
296 int match_start_point, int max_return_elements, SearchFilter *searcher,
297 bool &word_complete, StringList &matches) {
298 int ret_val =
299 DiskFilesOrDirectories(partial_file_name, true, word_complete, matches);
300 word_complete = false;
301 return ret_val;
302}
303
304int CommandCompletions::Modules(CommandInterpreter &interpreter,
305 const char *partial_file_name,
306 int match_start_point, int max_return_elements,
307 SearchFilter *searcher, bool &word_complete,
308 StringList &matches) {
309 word_complete = true;
310 ModuleCompleter completer(interpreter, partial_file_name, match_start_point,
311 max_return_elements, matches);
312
313 if (searcher == nullptr) {
314 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
315 SearchFilterForUnconstrainedSearches null_searcher(target_sp);
316 completer.DoCompletion(&null_searcher);
317 } else {
318 completer.DoCompletion(searcher);
319 }
320 return matches.GetSize();
321}
322
323int CommandCompletions::Symbols(CommandInterpreter &interpreter,
324 const char *partial_file_name,
325 int match_start_point, int max_return_elements,
326 SearchFilter *searcher, bool &word_complete,
327 StringList &matches) {
328 word_complete = true;
329 SymbolCompleter completer(interpreter, partial_file_name, match_start_point,
330 max_return_elements, matches);
331
332 if (searcher == nullptr) {
333 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
334 SearchFilterForUnconstrainedSearches null_searcher(target_sp);
335 completer.DoCompletion(&null_searcher);
336 } else {
337 completer.DoCompletion(searcher);
338 }
339 return matches.GetSize();
340}
341
342int CommandCompletions::SettingsNames(
343 CommandInterpreter &interpreter, const char *partial_setting_name,
344 int match_start_point, int max_return_elements, SearchFilter *searcher,
345 bool &word_complete, StringList &matches) {
346 // Cache the full setting name list
347 static StringList g_property_names;
348 if (g_property_names.GetSize() == 0) {
349 // Generate the full setting name list on demand
350 lldb::OptionValuePropertiesSP properties_sp(
351 interpreter.GetDebugger().GetValueProperties());
352 if (properties_sp) {
353 StreamString strm;
354 properties_sp->DumpValue(nullptr, strm, OptionValue::eDumpOptionName);
355 const std::string &str = strm.GetString();
356 g_property_names.SplitIntoLines(str.c_str(), str.size());
357 }
358 }
359
360 size_t exact_matches_idx = SIZE_MAX;
361 const size_t num_matches = g_property_names.AutoComplete(
362 partial_setting_name, matches, exact_matches_idx);
363 word_complete = exact_matches_idx != SIZE_MAX;
364 return num_matches;
365}
366
367int CommandCompletions::PlatformPluginNames(
368 CommandInterpreter &interpreter, const char *partial_name,
369 int match_start_point, int max_return_elements, SearchFilter *searcher,
370 bool &word_complete, lldb_private::StringList &matches) {
371 const uint32_t num_matches =
372 PluginManager::AutoCompletePlatformName(partial_name, matches);
373 word_complete = num_matches == 1;
374 return num_matches;
375}
376
377int CommandCompletions::ArchitectureNames(
378 CommandInterpreter &interpreter, const char *partial_name,
379 int match_start_point, int max_return_elements, SearchFilter *searcher,
380 bool &word_complete, lldb_private::StringList &matches) {
381 const uint32_t num_matches = ArchSpec::AutoComplete(partial_name, matches);
382 word_complete = num_matches == 1;
383 return num_matches;
384}
385
386int CommandCompletions::VariablePath(
387 CommandInterpreter &interpreter, const char *partial_name,
388 int match_start_point, int max_return_elements, SearchFilter *searcher,
389 bool &word_complete, lldb_private::StringList &matches) {
390 return Variable::AutoComplete(interpreter.GetExecutionContext(), partial_name,
391 matches, word_complete);
Greg Claytonf21fead2013-05-14 23:43:18 +0000392}
393
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000394CommandCompletions::Completer::Completer(CommandInterpreter &interpreter,
395 const char *completion_str,
396 int match_start_point,
397 int max_return_elements,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000398 StringList &matches)
399 : m_interpreter(interpreter), m_completion_str(completion_str),
400 m_match_start_point(match_start_point),
401 m_max_return_elements(max_return_elements), m_matches(matches) {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000402
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000403CommandCompletions::Completer::~Completer() = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000404
405//----------------------------------------------------------------------
406// SourceFileCompleter
407//----------------------------------------------------------------------
408
Kate Stoneb9c1b512016-09-06 20:57:50 +0000409CommandCompletions::SourceFileCompleter::SourceFileCompleter(
410 CommandInterpreter &interpreter, bool include_support_files,
411 const char *completion_str, int match_start_point, int max_return_elements,
412 StringList &matches)
413 : CommandCompletions::Completer(interpreter, completion_str,
414 match_start_point, max_return_elements,
415 matches),
416 m_include_support_files(include_support_files), m_matching_files() {
417 FileSpec partial_spec(m_completion_str.c_str(), false);
418 m_file_name = partial_spec.GetFilename().GetCString();
419 m_dir_name = partial_spec.GetDirectory().GetCString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000420}
421
Kate Stoneb9c1b512016-09-06 20:57:50 +0000422Searcher::Depth CommandCompletions::SourceFileCompleter::GetDepth() {
423 return eDepthCompUnit;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000424}
425
426Searcher::CallbackReturn
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000427CommandCompletions::SourceFileCompleter::SearchCallback(SearchFilter &filter,
428 SymbolContext &context,
429 Address *addr,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000430 bool complete) {
431 if (context.comp_unit != nullptr) {
432 if (m_include_support_files) {
433 FileSpecList supporting_files = context.comp_unit->GetSupportFiles();
434 for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++) {
435 const FileSpec &sfile_spec =
436 supporting_files.GetFileSpecAtIndex(sfiles);
437 const char *sfile_file_name = sfile_spec.GetFilename().GetCString();
438 const char *sfile_dir_name = sfile_spec.GetFilename().GetCString();
439 bool match = false;
440 if (m_file_name && sfile_file_name &&
441 strstr(sfile_file_name, m_file_name) == sfile_file_name)
442 match = true;
443 if (match && m_dir_name && sfile_dir_name &&
444 strstr(sfile_dir_name, m_dir_name) != sfile_dir_name)
445 match = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000446
Kate Stoneb9c1b512016-09-06 20:57:50 +0000447 if (match) {
448 m_matching_files.AppendIfUnique(sfile_spec);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000449 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000450 }
451 } else {
452 const char *cur_file_name = context.comp_unit->GetFilename().GetCString();
453 const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000454
Kate Stoneb9c1b512016-09-06 20:57:50 +0000455 bool match = false;
456 if (m_file_name && cur_file_name &&
457 strstr(cur_file_name, m_file_name) == cur_file_name)
458 match = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000459
Kate Stoneb9c1b512016-09-06 20:57:50 +0000460 if (match && m_dir_name && cur_dir_name &&
461 strstr(cur_dir_name, m_dir_name) != cur_dir_name)
462 match = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000463
Kate Stoneb9c1b512016-09-06 20:57:50 +0000464 if (match) {
465 m_matching_files.AppendIfUnique(context.comp_unit);
466 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000467 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000468 }
469 return Searcher::eCallbackReturnContinue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000470}
471
472size_t
Kate Stoneb9c1b512016-09-06 20:57:50 +0000473CommandCompletions::SourceFileCompleter::DoCompletion(SearchFilter *filter) {
474 filter->Search(*this);
475 // Now convert the filelist to completions:
476 for (size_t i = 0; i < m_matching_files.GetSize(); i++) {
477 m_matches.AppendString(
478 m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
479 }
480 return m_matches.GetSize();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000481}
482
483//----------------------------------------------------------------------
484// SymbolCompleter
485//----------------------------------------------------------------------
486
Kate Stoneb9c1b512016-09-06 20:57:50 +0000487static bool regex_chars(const char comp) {
488 return (comp == '[' || comp == ']' || comp == '(' || comp == ')' ||
489 comp == '{' || comp == '}' || comp == '+' || comp == '.' ||
490 comp == '*' || comp == '|' || comp == '^' || comp == '$' ||
491 comp == '\\' || comp == '?');
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000492}
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000493
Kate Stoneb9c1b512016-09-06 20:57:50 +0000494CommandCompletions::SymbolCompleter::SymbolCompleter(
495 CommandInterpreter &interpreter, const char *completion_str,
496 int match_start_point, int max_return_elements, StringList &matches)
497 : CommandCompletions::Completer(interpreter, completion_str,
498 match_start_point, max_return_elements,
499 matches) {
500 std::string regex_str;
501 if (completion_str && completion_str[0]) {
502 regex_str.append("^");
503 regex_str.append(completion_str);
504 } else {
505 // Match anything since the completion string is empty
506 regex_str.append(".");
507 }
508 std::string::iterator pos =
509 find_if(regex_str.begin() + 1, regex_str.end(), regex_chars);
510 while (pos < regex_str.end()) {
511 pos = regex_str.insert(pos, '\\');
512 pos = find_if(pos + 2, regex_str.end(), regex_chars);
513 }
Zachary Turner95eae422016-09-21 16:01:28 +0000514 m_regex.Compile(regex_str);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000515}
516
Kate Stoneb9c1b512016-09-06 20:57:50 +0000517Searcher::Depth CommandCompletions::SymbolCompleter::GetDepth() {
518 return eDepthModule;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000519}
520
Kate Stoneb9c1b512016-09-06 20:57:50 +0000521Searcher::CallbackReturn CommandCompletions::SymbolCompleter::SearchCallback(
522 SearchFilter &filter, SymbolContext &context, Address *addr,
523 bool complete) {
524 if (context.module_sp) {
525 SymbolContextList sc_list;
526 const bool include_symbols = true;
527 const bool include_inlines = true;
528 const bool append = true;
529 context.module_sp->FindFunctions(m_regex, include_symbols, include_inlines,
530 append, sc_list);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000531
Kate Stoneb9c1b512016-09-06 20:57:50 +0000532 SymbolContext sc;
533 // Now add the functions & symbols to the list - only add if unique:
534 for (uint32_t i = 0; i < sc_list.GetSize(); i++) {
535 if (sc_list.GetContextAtIndex(i, sc)) {
536 ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
537 if (!func_name.IsEmpty())
538 m_match_set.insert(func_name);
539 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000540 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000541 }
542 return Searcher::eCallbackReturnContinue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000543}
544
Kate Stoneb9c1b512016-09-06 20:57:50 +0000545size_t CommandCompletions::SymbolCompleter::DoCompletion(SearchFilter *filter) {
546 filter->Search(*this);
547 collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
548 for (pos = m_match_set.begin(); pos != end; pos++)
549 m_matches.AppendString((*pos).GetCString());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000550
Kate Stoneb9c1b512016-09-06 20:57:50 +0000551 return m_matches.GetSize();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000552}
553
554//----------------------------------------------------------------------
555// ModuleCompleter
556//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000557CommandCompletions::ModuleCompleter::ModuleCompleter(
558 CommandInterpreter &interpreter, const char *completion_str,
559 int match_start_point, int max_return_elements, StringList &matches)
560 : CommandCompletions::Completer(interpreter, completion_str,
561 match_start_point, max_return_elements,
562 matches) {
563 FileSpec partial_spec(m_completion_str.c_str(), false);
564 m_file_name = partial_spec.GetFilename().GetCString();
565 m_dir_name = partial_spec.GetDirectory().GetCString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000566}
567
Kate Stoneb9c1b512016-09-06 20:57:50 +0000568Searcher::Depth CommandCompletions::ModuleCompleter::GetDepth() {
569 return eDepthModule;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000570}
571
Kate Stoneb9c1b512016-09-06 20:57:50 +0000572Searcher::CallbackReturn CommandCompletions::ModuleCompleter::SearchCallback(
573 SearchFilter &filter, SymbolContext &context, Address *addr,
574 bool complete) {
575 if (context.module_sp) {
576 const char *cur_file_name =
577 context.module_sp->GetFileSpec().GetFilename().GetCString();
578 const char *cur_dir_name =
579 context.module_sp->GetFileSpec().GetDirectory().GetCString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000580
Kate Stoneb9c1b512016-09-06 20:57:50 +0000581 bool match = false;
582 if (m_file_name && cur_file_name &&
583 strstr(cur_file_name, m_file_name) == cur_file_name)
584 match = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000585
Kate Stoneb9c1b512016-09-06 20:57:50 +0000586 if (match && m_dir_name && cur_dir_name &&
587 strstr(cur_dir_name, m_dir_name) != cur_dir_name)
588 match = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000589
Kate Stoneb9c1b512016-09-06 20:57:50 +0000590 if (match) {
591 m_matches.AppendString(cur_file_name);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000592 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000593 }
594 return Searcher::eCallbackReturnContinue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000595}
596
Kate Stoneb9c1b512016-09-06 20:57:50 +0000597size_t CommandCompletions::ModuleCompleter::DoCompletion(SearchFilter *filter) {
598 filter->Search(*this);
599 return m_matches.GetSize();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000600}