| //===-- CommandCompletions.cpp ----------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| |
| // C Includes |
| // C++ Includes |
| // Other libraries and framework includes |
| // Project includes |
| #include "lldb/Core/Args.h" |
| #include "lldb/Interpreter/CommandInterpreter.h" |
| #include "lldb/Core/FileSpecList.h" |
| #include "lldb/Target/Target.h" |
| #include "lldb/Interpreter/CommandCompletions.h" |
| |
| |
| using namespace lldb_private; |
| |
| CommandCompletions::CommonCompletionElement |
| CommandCompletions::g_common_completions[] = |
| { |
| {eCustomCompletion, NULL}, |
| {eSourceFileCompletion, CommandCompletions::SourceFiles}, |
| {eDiskFileCompletion, NULL}, |
| {eSymbolCompletion, CommandCompletions::Symbols}, |
| {eModuleCompletion, CommandCompletions::Modules}, |
| {eNoCompletion, NULL} // This one has to be last in the list. |
| }; |
| |
| bool |
| CommandCompletions::InvokeCommonCompletionCallbacks (uint32_t completion_mask, |
| const char *completion_str, |
| int match_start_point, |
| int max_return_elements, |
| lldb_private::CommandInterpreter *interpreter, |
| SearchFilter *searcher, |
| lldb_private::StringList &matches) |
| { |
| bool handled = false; |
| |
| if (completion_mask & eCustomCompletion) |
| return false; |
| |
| for (int i = 0; ; i++) |
| { |
| if (g_common_completions[i].type == eNoCompletion) |
| break; |
| else if ((g_common_completions[i].type & completion_mask) == g_common_completions[i].type |
| && g_common_completions[i].callback != NULL) |
| { |
| handled = true; |
| g_common_completions[i].callback (completion_str, |
| match_start_point, |
| max_return_elements, |
| interpreter, |
| searcher, |
| matches); |
| } |
| } |
| return handled; |
| } |
| |
| int |
| CommandCompletions::SourceFiles (const char *partial_file_name, |
| int match_start_point, |
| int max_return_elements, |
| lldb_private::CommandInterpreter *interpreter, |
| SearchFilter *searcher, |
| lldb_private::StringList &matches) |
| { |
| // Find some way to switch "include support files..." |
| SourceFileCompleter completer (false, partial_file_name, match_start_point, max_return_elements, interpreter, |
| matches); |
| |
| if (searcher == NULL) |
| { |
| lldb::TargetSP target_sp = interpreter->Context()->GetTarget()->GetSP(); |
| SearchFilter null_searcher (target_sp); |
| completer.DoCompletion (&null_searcher); |
| } |
| else |
| { |
| completer.DoCompletion (searcher); |
| } |
| return matches.GetSize(); |
| } |
| |
| int |
| CommandCompletions::Modules (const char *partial_file_name, |
| int match_start_point, |
| int max_return_elements, |
| lldb_private::CommandInterpreter *interpreter, |
| SearchFilter *searcher, |
| lldb_private::StringList &matches) |
| { |
| ModuleCompleter completer(partial_file_name, match_start_point, max_return_elements, interpreter, matches); |
| |
| if (searcher == NULL) |
| { |
| lldb::TargetSP target_sp = interpreter->Context()->GetTarget()->GetSP(); |
| SearchFilter null_searcher (target_sp); |
| completer.DoCompletion (&null_searcher); |
| } |
| else |
| { |
| completer.DoCompletion (searcher); |
| } |
| return matches.GetSize(); |
| } |
| |
| int |
| CommandCompletions::Symbols (const char *partial_file_name, |
| int match_start_point, |
| int max_return_elements, |
| lldb_private::CommandInterpreter *interpreter, |
| SearchFilter *searcher, |
| lldb_private::StringList &matches) |
| { |
| SymbolCompleter completer(partial_file_name, match_start_point, max_return_elements, interpreter, matches); |
| |
| if (searcher == NULL) |
| { |
| lldb::TargetSP target_sp = interpreter->Context()->GetTarget()->GetSP(); |
| SearchFilter null_searcher (target_sp); |
| completer.DoCompletion (&null_searcher); |
| } |
| else |
| { |
| completer.DoCompletion (searcher); |
| } |
| return matches.GetSize(); |
| } |
| |
| CommandCompletions::Completer::Completer ( |
| const char *completion_str, |
| int match_start_point, |
| int max_return_elements, |
| CommandInterpreter *interpreter, |
| StringList &matches |
| ) : |
| m_completion_str (completion_str), |
| m_match_start_point (match_start_point), |
| m_max_return_elements (max_return_elements), |
| m_interpreter (interpreter), |
| m_matches (matches) |
| { |
| } |
| |
| CommandCompletions::Completer::~Completer () |
| { |
| |
| } |
| |
| //---------------------------------------------------------------------- |
| // SourceFileCompleter |
| //---------------------------------------------------------------------- |
| |
| CommandCompletions::SourceFileCompleter::SourceFileCompleter ( |
| bool include_support_files, |
| const char *completion_str, |
| int match_start_point, |
| int max_return_elements, |
| CommandInterpreter *interpreter, |
| StringList &matches |
| ) : |
| CommandCompletions::Completer (completion_str, match_start_point, max_return_elements, interpreter, matches), |
| m_include_support_files (include_support_files), |
| m_matching_files() |
| { |
| FileSpec partial_spec (m_completion_str.c_str()); |
| m_file_name = partial_spec.GetFilename().GetCString(); |
| m_dir_name = partial_spec.GetDirectory().GetCString(); |
| } |
| |
| Searcher::Depth |
| CommandCompletions::SourceFileCompleter::GetDepth() |
| { |
| return eDepthCompUnit; |
| } |
| |
| Searcher::CallbackReturn |
| CommandCompletions::SourceFileCompleter::SearchCallback ( |
| SearchFilter &filter, |
| SymbolContext &context, |
| Address *addr, |
| bool complete |
| ) |
| { |
| if (context.comp_unit != NULL) |
| { |
| if (m_include_support_files) |
| { |
| FileSpecList supporting_files = context.comp_unit->GetSupportFiles(); |
| for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++) |
| { |
| const FileSpec &sfile_spec = supporting_files.GetFileSpecAtIndex(sfiles); |
| const char *sfile_file_name = sfile_spec.GetFilename().GetCString(); |
| const char *sfile_dir_name = sfile_spec.GetFilename().GetCString(); |
| bool match = false; |
| if (m_file_name && sfile_file_name |
| && strstr (sfile_file_name, m_file_name) == sfile_file_name) |
| match = true; |
| if (match && m_dir_name && sfile_dir_name |
| && strstr (sfile_dir_name, m_dir_name) != sfile_dir_name) |
| match = false; |
| |
| if (match) |
| { |
| m_matching_files.AppendIfUnique(sfile_spec); |
| } |
| } |
| |
| } |
| else |
| { |
| const char *cur_file_name = context.comp_unit->GetFilename().GetCString(); |
| const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString(); |
| |
| bool match = false; |
| if (m_file_name && cur_file_name |
| && strstr (cur_file_name, m_file_name) == cur_file_name) |
| match = true; |
| |
| if (match && m_dir_name && cur_dir_name |
| && strstr (cur_dir_name, m_dir_name) != cur_dir_name) |
| match = false; |
| |
| if (match) |
| { |
| m_matching_files.AppendIfUnique(context.comp_unit); |
| } |
| } |
| } |
| return Searcher::eCallbackReturnContinue; |
| } |
| |
| size_t |
| CommandCompletions::SourceFileCompleter::DoCompletion (SearchFilter *filter) |
| { |
| filter->Search (*this); |
| // Now convert the filelist to completions: |
| for (size_t i = 0; i < m_matching_files.GetSize(); i++) |
| { |
| m_matches.AppendString (m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString()); |
| } |
| return m_matches.GetSize(); |
| |
| } |
| |
| //---------------------------------------------------------------------- |
| // SymbolCompleter |
| //---------------------------------------------------------------------- |
| |
| static bool |
| regex_chars (const char comp) |
| { |
| if (comp == '[' || comp == ']' || comp == '(' || comp == ')') |
| return true; |
| else |
| return false; |
| } |
| CommandCompletions::SymbolCompleter::SymbolCompleter ( |
| const char *completion_str, |
| int match_start_point, |
| int max_return_elements, |
| CommandInterpreter *interpreter, |
| StringList &matches |
| ) : |
| CommandCompletions::Completer (completion_str, match_start_point, max_return_elements, interpreter, matches) |
| { |
| std::string regex_str ("^"); |
| regex_str.append(completion_str); |
| regex_str.append(".*"); |
| std::string::iterator pos; |
| |
| pos = find_if(regex_str.begin(), regex_str.end(), regex_chars); |
| while (pos < regex_str.end()) { |
| pos = regex_str.insert(pos, '\\'); |
| pos += 2; |
| pos = find_if(pos, regex_str.end(), regex_chars); |
| } |
| m_regex.Compile(regex_str.c_str()); |
| } |
| |
| Searcher::Depth |
| CommandCompletions::SymbolCompleter::GetDepth() |
| { |
| return eDepthModule; |
| } |
| |
| Searcher::CallbackReturn |
| CommandCompletions::SymbolCompleter::SearchCallback ( |
| SearchFilter &filter, |
| SymbolContext &context, |
| Address *addr, |
| bool complete |
| ) |
| { |
| SymbolContextList func_list; |
| SymbolContextList sym_list; |
| |
| if (context.module_sp != NULL) |
| { |
| if (context.module_sp) |
| { |
| context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, lldb::eSymbolTypeCode, sym_list); |
| context.module_sp->FindFunctions (m_regex, true, func_list); |
| } |
| |
| SymbolContext sc; |
| // Now add the functions & symbols to the list - only add if unique: |
| for (int i = 0; i < func_list.GetSize(); i++) |
| { |
| if (func_list.GetContextAtIndex(i, sc)) |
| { |
| if (sc.function) |
| { |
| m_match_set.insert (sc.function->GetMangled().GetDemangledName()); |
| } |
| } |
| } |
| |
| for (int i = 0; i < sym_list.GetSize(); i++) |
| { |
| if (sym_list.GetContextAtIndex(i, sc)) |
| { |
| if (sc.symbol && sc.symbol->GetAddressRangePtr()) |
| { |
| m_match_set.insert (sc.symbol->GetMangled().GetDemangledName()); |
| } |
| } |
| } |
| } |
| return Searcher::eCallbackReturnContinue; |
| } |
| |
| size_t |
| CommandCompletions::SymbolCompleter::DoCompletion (SearchFilter *filter) |
| { |
| filter->Search (*this); |
| collection::iterator pos = m_match_set.begin(), end = m_match_set.end(); |
| for (pos = m_match_set.begin(); pos != end; pos++) |
| m_matches.AppendString((*pos).GetCString()); |
| |
| return m_matches.GetSize(); |
| } |
| |
| //---------------------------------------------------------------------- |
| // ModuleCompleter |
| //---------------------------------------------------------------------- |
| CommandCompletions::ModuleCompleter::ModuleCompleter ( |
| const char *completion_str, |
| int match_start_point, |
| int max_return_elements, |
| CommandInterpreter *interpreter, |
| StringList &matches |
| ) : |
| CommandCompletions::Completer (completion_str, match_start_point, max_return_elements, interpreter, matches) |
| { |
| FileSpec partial_spec (m_completion_str.c_str()); |
| m_file_name = partial_spec.GetFilename().GetCString(); |
| m_dir_name = partial_spec.GetDirectory().GetCString(); |
| } |
| |
| Searcher::Depth |
| CommandCompletions::ModuleCompleter::GetDepth() |
| { |
| return eDepthModule; |
| } |
| |
| Searcher::CallbackReturn |
| CommandCompletions::ModuleCompleter::SearchCallback ( |
| SearchFilter &filter, |
| SymbolContext &context, |
| Address *addr, |
| bool complete |
| ) |
| { |
| if (context.module_sp != NULL) |
| { |
| const char *cur_file_name = context.module_sp->GetFileSpec().GetFilename().GetCString(); |
| const char *cur_dir_name = context.module_sp->GetFileSpec().GetDirectory().GetCString(); |
| |
| bool match = false; |
| if (m_file_name && cur_file_name |
| && strstr (cur_file_name, m_file_name) == cur_file_name) |
| match = true; |
| |
| if (match && m_dir_name && cur_dir_name |
| && strstr (cur_dir_name, m_dir_name) != cur_dir_name) |
| match = false; |
| |
| if (match) |
| { |
| m_matches.AppendString (cur_file_name); |
| } |
| } |
| return Searcher::eCallbackReturnContinue; |
| } |
| |
| size_t |
| CommandCompletions::ModuleCompleter::DoCompletion (SearchFilter *filter) |
| { |
| filter->Search (*this); |
| return m_matches.GetSize(); |
| } |
| |
| |
| |