1 //===-- CommandCompletions.cpp ----------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/lldb-python.h"
14 #if defined(__APPLE__) || defined(__linux__)
19 // Other libraries and framework includes
21 #include "lldb/Host/FileSpec.h"
22 #include "lldb/Core/FileSpecList.h"
23 #include "lldb/Core/PluginManager.h"
24 #include "lldb/Core/Module.h"
25 #include "lldb/Interpreter/Args.h"
26 #include "lldb/Interpreter/CommandCompletions.h"
27 #include "lldb/Interpreter/CommandInterpreter.h"
28 #include "lldb/Symbol/CompileUnit.h"
29 #include "lldb/Symbol/Variable.h"
30 #include "lldb/Target/Target.h"
31 #include "lldb/Utility/CleanUp.h"
33 using namespace lldb_private;
35 CommandCompletions::CommonCompletionElement
36 CommandCompletions::g_common_completions[] =
38 {eCustomCompletion, NULL},
39 {eSourceFileCompletion, CommandCompletions::SourceFiles},
40 {eDiskFileCompletion, CommandCompletions::DiskFiles},
41 {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
42 {eSymbolCompletion, CommandCompletions::Symbols},
43 {eModuleCompletion, CommandCompletions::Modules},
44 {eSettingsNameCompletion, CommandCompletions::SettingsNames},
45 {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames},
46 {eArchitectureCompletion, CommandCompletions::ArchitectureNames},
47 {eVariablePathCompletion, CommandCompletions::VariablePath},
48 {eNoCompletion, NULL} // This one has to be last in the list.
52 CommandCompletions::InvokeCommonCompletionCallbacks
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,
66 if (completion_mask & eCustomCompletion)
69 for (int i = 0; ; i++)
71 if (g_common_completions[i].type == eNoCompletion)
73 else if ((g_common_completions[i].type & completion_mask) == g_common_completions[i].type
74 && g_common_completions[i].callback != NULL)
77 g_common_completions[i].callback (interpreter,
90 CommandCompletions::SourceFiles
92 CommandInterpreter &interpreter,
93 const char *partial_file_name,
94 int match_start_point,
95 int max_return_elements,
96 SearchFilter *searcher,
101 word_complete = true;
102 // Find some way to switch "include support files..."
103 SourceFileCompleter completer (interpreter,
110 if (searcher == NULL)
112 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
113 SearchFilter null_searcher (target_sp);
114 completer.DoCompletion (&null_searcher);
118 completer.DoCompletion (searcher);
120 return matches.GetSize();
123 typedef struct DiskFilesOrDirectoriesBaton
125 const char *remainder;
126 char *partial_name_copy;
127 bool only_directories;
132 } DiskFilesOrDirectoriesBaton;
134 FileSpec::EnumerateDirectoryResult DiskFilesOrDirectoriesCallback(void *baton, FileSpec::FileType file_type, const FileSpec &spec)
136 const char *name = spec.GetFilename().AsCString();
138 const DiskFilesOrDirectoriesBaton *parameters = (DiskFilesOrDirectoriesBaton*)baton;
139 char *end_ptr = parameters->end_ptr;
140 char *partial_name_copy = parameters->partial_name_copy;
141 const char *remainder = parameters->remainder;
143 // Omit ".", ".." and any . files if the match string doesn't start with .
147 return FileSpec::eEnumerateDirectoryResultNext;
148 else if (name[1] == '.' && name[2] == '\0')
149 return FileSpec::eEnumerateDirectoryResultNext;
150 else if (remainder[0] != '.')
151 return FileSpec::eEnumerateDirectoryResultNext;
154 // If we found a directory, we put a "/" at the end of the name.
156 if (remainder[0] == '\0' || strstr(name, remainder) == name)
158 if (strlen(name) + parameters->baselen >= PATH_MAX)
159 return FileSpec::eEnumerateDirectoryResultNext;
161 strcpy(end_ptr, name);
163 bool isa_directory = false;
164 if (file_type == FileSpec::eFileTypeDirectory)
165 isa_directory = true;
166 else if (file_type == FileSpec::eFileTypeSymbolicLink)
168 struct stat stat_buf;
169 if ((stat(partial_name_copy, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode))
170 isa_directory = true;
175 *parameters->saw_directory = true;
176 size_t len = strlen(parameters->partial_name_copy);
177 partial_name_copy[len] = '/';
178 partial_name_copy[len + 1] = '\0';
180 if (parameters->only_directories && !isa_directory)
181 return FileSpec::eEnumerateDirectoryResultNext;
182 parameters->matches->AppendString(partial_name_copy);
185 return FileSpec::eEnumerateDirectoryResultNext;
189 DiskFilesOrDirectories
191 const char *partial_file_name,
192 bool only_directories,
197 // I'm going to use the "glob" function with GLOB_TILDE for user directory expansion.
198 // If it is not defined on your host system, you'll need to implement it yourself...
200 size_t partial_name_len = strlen(partial_file_name);
202 if (partial_name_len >= PATH_MAX)
203 return matches.GetSize();
205 // This copy of the string will be cut up into the directory part, and the remainder. end_ptr
206 // below will point to the place of the remainder in this string. Then when we've resolved the
207 // containing directory, and opened it, we'll read the directory contents and overwrite the
208 // partial_name_copy starting from end_ptr with each of the matches. Thus we will preserve
209 // the form the user originally typed.
211 char partial_name_copy[PATH_MAX];
212 memcpy(partial_name_copy, partial_file_name, partial_name_len);
213 partial_name_copy[partial_name_len] = '\0';
215 // We'll need to save a copy of the remainder for comparison, which we do here.
216 char remainder[PATH_MAX];
218 // end_ptr will point past the last / in partial_name_copy, or if there is no slash to the beginning of the string.
221 end_ptr = strrchr(partial_name_copy, '/');
223 // This will store the resolved form of the containing directory
224 char containing_part[PATH_MAX];
228 // There's no directory. If the thing begins with a "~" then this is a bare
230 if (*partial_name_copy == '~')
232 // Nothing here but the user name. We could just put a slash on the end,
233 // but for completeness sake we'll resolve the user name and only put a slash
234 // on the end if it exists.
235 char resolved_username[PATH_MAX];
236 size_t resolved_username_len = FileSpec::ResolveUsername (partial_name_copy, resolved_username,
237 sizeof (resolved_username));
239 // Not sure how this would happen, a username longer than PATH_MAX? Still...
240 if (resolved_username_len >= sizeof (resolved_username))
241 return matches.GetSize();
242 else if (resolved_username_len == 0)
244 // The user name didn't resolve, let's look in the password database for matches.
245 // The user name database contains duplicates, and is not in alphabetical order, so
246 // we'll use a set to manage that for us.
247 FileSpec::ResolvePartialUsername (partial_name_copy, matches);
248 if (matches.GetSize() > 0)
249 saw_directory = true;
250 return matches.GetSize();
254 //The thing exists, put a '/' on the end, and return it...
255 // FIXME: complete user names here:
256 partial_name_copy[partial_name_len] = '/';
257 partial_name_copy[partial_name_len+1] = '\0';
258 matches.AppendString(partial_name_copy);
259 saw_directory = true;
260 return matches.GetSize();
265 // The containing part is the CWD, and the whole string is the remainder.
266 containing_part[0] = '.';
267 containing_part[1] = '\0';
268 strcpy(remainder, partial_name_copy);
269 end_ptr = partial_name_copy;
274 if (end_ptr == partial_name_copy)
276 // We're completing a file or directory in the root volume.
277 containing_part[0] = '/';
278 containing_part[1] = '\0';
282 size_t len = end_ptr - partial_name_copy;
283 memcpy(containing_part, partial_name_copy, len);
284 containing_part[len] = '\0';
286 // Push end_ptr past the final "/" and set remainder.
288 strcpy(remainder, end_ptr);
291 // Look for a user name in the containing part, and if it's there, resolve it and stick the
292 // result back into the containing_part:
294 if (*partial_name_copy == '~')
296 size_t resolved_username_len = FileSpec::ResolveUsername(containing_part,
298 sizeof (containing_part));
299 // User name doesn't exist, we're not getting any further...
300 if (resolved_username_len == 0 || resolved_username_len >= sizeof (containing_part))
301 return matches.GetSize();
304 // Okay, containing_part is now the directory we want to open and look for files:
306 size_t baselen = end_ptr - partial_name_copy;
308 DiskFilesOrDirectoriesBaton parameters;
309 parameters.remainder = remainder;
310 parameters.partial_name_copy = partial_name_copy;
311 parameters.only_directories = only_directories;
312 parameters.saw_directory = &saw_directory;
313 parameters.matches = &matches;
314 parameters.end_ptr = end_ptr;
315 parameters.baselen = baselen;
317 FileSpec::EnumerateDirectory(containing_part, true, true, true, DiskFilesOrDirectoriesCallback, ¶meters);
319 return matches.GetSize();
323 CommandCompletions::DiskFiles
325 CommandInterpreter &interpreter,
326 const char *partial_file_name,
327 int match_start_point,
328 int max_return_elements,
329 SearchFilter *searcher,
335 int ret_val = DiskFilesOrDirectories (partial_file_name,
339 word_complete = !word_complete;
344 CommandCompletions::DiskDirectories
346 CommandInterpreter &interpreter,
347 const char *partial_file_name,
348 int match_start_point,
349 int max_return_elements,
350 SearchFilter *searcher,
355 int ret_val = DiskFilesOrDirectories (partial_file_name,
359 word_complete = false;
364 CommandCompletions::Modules
366 CommandInterpreter &interpreter,
367 const char *partial_file_name,
368 int match_start_point,
369 int max_return_elements,
370 SearchFilter *searcher,
375 word_complete = true;
376 ModuleCompleter completer (interpreter,
382 if (searcher == NULL)
384 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
385 SearchFilter null_searcher (target_sp);
386 completer.DoCompletion (&null_searcher);
390 completer.DoCompletion (searcher);
392 return matches.GetSize();
396 CommandCompletions::Symbols
398 CommandInterpreter &interpreter,
399 const char *partial_file_name,
400 int match_start_point,
401 int max_return_elements,
402 SearchFilter *searcher,
406 word_complete = true;
407 SymbolCompleter completer (interpreter,
413 if (searcher == NULL)
415 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
416 SearchFilter null_searcher (target_sp);
417 completer.DoCompletion (&null_searcher);
421 completer.DoCompletion (searcher);
423 return matches.GetSize();
427 CommandCompletions::SettingsNames (CommandInterpreter &interpreter,
428 const char *partial_setting_name,
429 int match_start_point,
430 int max_return_elements,
431 SearchFilter *searcher,
435 // Cache the full setting name list
436 static StringList g_property_names;
437 if (g_property_names.GetSize() == 0)
439 // Generate the full setting name list on demand
440 lldb::OptionValuePropertiesSP properties_sp (interpreter.GetDebugger().GetValueProperties());
444 properties_sp->DumpValue(NULL, strm, OptionValue::eDumpOptionName);
445 const std::string &str = strm.GetString();
446 g_property_names.SplitIntoLines(str.c_str(), str.size());
450 size_t exact_matches_idx = SIZE_MAX;
451 const size_t num_matches = g_property_names.AutoComplete (partial_setting_name, matches, exact_matches_idx);
452 word_complete = exact_matches_idx != SIZE_MAX;
458 CommandCompletions::PlatformPluginNames (CommandInterpreter &interpreter,
459 const char *partial_name,
460 int match_start_point,
461 int max_return_elements,
462 SearchFilter *searcher,
464 lldb_private::StringList &matches)
466 const uint32_t num_matches = PluginManager::AutoCompletePlatformName(partial_name, matches);
467 word_complete = num_matches == 1;
472 CommandCompletions::ArchitectureNames (CommandInterpreter &interpreter,
473 const char *partial_name,
474 int match_start_point,
475 int max_return_elements,
476 SearchFilter *searcher,
478 lldb_private::StringList &matches)
480 const uint32_t num_matches = ArchSpec::AutoComplete (partial_name, matches);
481 word_complete = num_matches == 1;
487 CommandCompletions::VariablePath (CommandInterpreter &interpreter,
488 const char *partial_name,
489 int match_start_point,
490 int max_return_elements,
491 SearchFilter *searcher,
493 lldb_private::StringList &matches)
495 return Variable::AutoComplete (interpreter.GetExecutionContext(), partial_name, matches, word_complete);
499 CommandCompletions::Completer::Completer
501 CommandInterpreter &interpreter,
502 const char *completion_str,
503 int match_start_point,
504 int max_return_elements,
507 m_interpreter (interpreter),
508 m_completion_str (completion_str),
509 m_match_start_point (match_start_point),
510 m_max_return_elements (max_return_elements),
515 CommandCompletions::Completer::~Completer ()
520 //----------------------------------------------------------------------
521 // SourceFileCompleter
522 //----------------------------------------------------------------------
524 CommandCompletions::SourceFileCompleter::SourceFileCompleter
526 CommandInterpreter &interpreter,
527 bool include_support_files,
528 const char *completion_str,
529 int match_start_point,
530 int max_return_elements,
533 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches),
534 m_include_support_files (include_support_files),
537 FileSpec partial_spec (m_completion_str.c_str(), false);
538 m_file_name = partial_spec.GetFilename().GetCString();
539 m_dir_name = partial_spec.GetDirectory().GetCString();
543 CommandCompletions::SourceFileCompleter::GetDepth()
545 return eDepthCompUnit;
548 Searcher::CallbackReturn
549 CommandCompletions::SourceFileCompleter::SearchCallback (
550 SearchFilter &filter,
551 SymbolContext &context,
556 if (context.comp_unit != NULL)
558 if (m_include_support_files)
560 FileSpecList supporting_files = context.comp_unit->GetSupportFiles();
561 for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++)
563 const FileSpec &sfile_spec = supporting_files.GetFileSpecAtIndex(sfiles);
564 const char *sfile_file_name = sfile_spec.GetFilename().GetCString();
565 const char *sfile_dir_name = sfile_spec.GetFilename().GetCString();
567 if (m_file_name && sfile_file_name
568 && strstr (sfile_file_name, m_file_name) == sfile_file_name)
570 if (match && m_dir_name && sfile_dir_name
571 && strstr (sfile_dir_name, m_dir_name) != sfile_dir_name)
576 m_matching_files.AppendIfUnique(sfile_spec);
583 const char *cur_file_name = context.comp_unit->GetFilename().GetCString();
584 const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString();
587 if (m_file_name && cur_file_name
588 && strstr (cur_file_name, m_file_name) == cur_file_name)
591 if (match && m_dir_name && cur_dir_name
592 && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
597 m_matching_files.AppendIfUnique(context.comp_unit);
601 return Searcher::eCallbackReturnContinue;
605 CommandCompletions::SourceFileCompleter::DoCompletion (SearchFilter *filter)
607 filter->Search (*this);
608 // Now convert the filelist to completions:
609 for (size_t i = 0; i < m_matching_files.GetSize(); i++)
611 m_matches.AppendString (m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
613 return m_matches.GetSize();
617 //----------------------------------------------------------------------
619 //----------------------------------------------------------------------
622 regex_chars (const char comp)
624 if (comp == '[' || comp == ']' ||
625 comp == '(' || comp == ')' ||
626 comp == '{' || comp == '}' ||
639 CommandCompletions::SymbolCompleter::SymbolCompleter
641 CommandInterpreter &interpreter,
642 const char *completion_str,
643 int match_start_point,
644 int max_return_elements,
647 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
649 std::string regex_str;
650 if (completion_str && completion_str[0])
652 regex_str.append("^");
653 regex_str.append(completion_str);
657 // Match anything since the completion string is empty
658 regex_str.append(".");
660 std::string::iterator pos = find_if(regex_str.begin() + 1, regex_str.end(), regex_chars);
661 while (pos < regex_str.end())
663 pos = regex_str.insert(pos, '\\');
664 pos = find_if(pos + 2, regex_str.end(), regex_chars);
666 m_regex.Compile(regex_str.c_str());
670 CommandCompletions::SymbolCompleter::GetDepth()
675 Searcher::CallbackReturn
676 CommandCompletions::SymbolCompleter::SearchCallback (
677 SearchFilter &filter,
678 SymbolContext &context,
683 if (context.module_sp)
685 SymbolContextList sc_list;
686 const bool include_symbols = true;
687 const bool include_inlines = true;
688 const bool append = true;
689 context.module_sp->FindFunctions (m_regex, include_symbols, include_inlines, append, sc_list);
692 // Now add the functions & symbols to the list - only add if unique:
693 for (uint32_t i = 0; i < sc_list.GetSize(); i++)
695 if (sc_list.GetContextAtIndex(i, sc))
697 ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
698 if (!func_name.IsEmpty())
699 m_match_set.insert (func_name);
703 return Searcher::eCallbackReturnContinue;
707 CommandCompletions::SymbolCompleter::DoCompletion (SearchFilter *filter)
709 filter->Search (*this);
710 collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
711 for (pos = m_match_set.begin(); pos != end; pos++)
712 m_matches.AppendString((*pos).GetCString());
714 return m_matches.GetSize();
717 //----------------------------------------------------------------------
719 //----------------------------------------------------------------------
720 CommandCompletions::ModuleCompleter::ModuleCompleter
722 CommandInterpreter &interpreter,
723 const char *completion_str,
724 int match_start_point,
725 int max_return_elements,
728 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
730 FileSpec partial_spec (m_completion_str.c_str(), false);
731 m_file_name = partial_spec.GetFilename().GetCString();
732 m_dir_name = partial_spec.GetDirectory().GetCString();
736 CommandCompletions::ModuleCompleter::GetDepth()
741 Searcher::CallbackReturn
742 CommandCompletions::ModuleCompleter::SearchCallback (
743 SearchFilter &filter,
744 SymbolContext &context,
749 if (context.module_sp)
751 const char *cur_file_name = context.module_sp->GetFileSpec().GetFilename().GetCString();
752 const char *cur_dir_name = context.module_sp->GetFileSpec().GetDirectory().GetCString();
755 if (m_file_name && cur_file_name
756 && strstr (cur_file_name, m_file_name) == cur_file_name)
759 if (match && m_dir_name && cur_dir_name
760 && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
765 m_matches.AppendString (cur_file_name);
768 return Searcher::eCallbackReturnContinue;
772 CommandCompletions::ModuleCompleter::DoCompletion (SearchFilter *filter)
774 filter->Search (*this);
775 return m_matches.GetSize();