示例#1
0
文件: Options.cpp 项目: kraj/lldb
bool Options::HandleOptionArgumentCompletion(
    Args &input, int cursor_index, int char_pos,
    OptionElementVector &opt_element_vector, int opt_element_index,
    int match_start_point, int max_return_elements,
    CommandInterpreter &interpreter, bool &word_complete,
    lldb_private::StringList &matches) {
  auto opt_defs = GetDefinitions();
  std::unique_ptr<SearchFilter> filter_ap;

  int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
  int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;

  // See if this is an enumeration type option, and if so complete it here:

  OptionEnumValueElement *enum_values = opt_defs[opt_defs_index].enum_values;
  if (enum_values != nullptr) {
    bool return_value = false;
    std::string match_string(input.GetArgumentAtIndex(opt_arg_pos),
                             input.GetArgumentAtIndex(opt_arg_pos) + char_pos);
    for (int i = 0; enum_values[i].string_value != nullptr; i++) {
      if (strstr(enum_values[i].string_value, match_string.c_str()) ==
          enum_values[i].string_value) {
        matches.AppendString(enum_values[i].string_value);
        return_value = true;
      }
    }
    return return_value;
  }

  // If this is a source file or symbol type completion, and  there is a
  // -shlib option somewhere in the supplied arguments, then make a search
  // filter
  // for that shared library.
  // FIXME: Do we want to also have an "OptionType" so we don't have to match
  // string names?

  uint32_t completion_mask = opt_defs[opt_defs_index].completion_type;

  if (completion_mask == 0) {
    lldb::CommandArgumentType option_arg_type =
        opt_defs[opt_defs_index].argument_type;
    if (option_arg_type != eArgTypeNone) {
      const CommandObject::ArgumentTableEntry *arg_entry =
          CommandObject::FindArgumentDataByType(
              opt_defs[opt_defs_index].argument_type);
      if (arg_entry)
        completion_mask = arg_entry->completion_type;
    }
  }

  if (completion_mask & CommandCompletions::eSourceFileCompletion ||
      completion_mask & CommandCompletions::eSymbolCompletion) {
    for (size_t i = 0; i < opt_element_vector.size(); i++) {
      int cur_defs_index = opt_element_vector[i].opt_defs_index;

      // trying to use <0 indices will definitely cause problems
      if (cur_defs_index == OptionArgElement::eUnrecognizedArg ||
          cur_defs_index == OptionArgElement::eBareDash ||
          cur_defs_index == OptionArgElement::eBareDoubleDash)
        continue;

      int cur_arg_pos = opt_element_vector[i].opt_arg_pos;
      const char *cur_opt_name = opt_defs[cur_defs_index].long_option;

      // If this is the "shlib" option and there was an argument provided,
      // restrict it to that shared library.
      if (cur_opt_name && strcmp(cur_opt_name, "shlib") == 0 &&
          cur_arg_pos != -1) {
        const char *module_name = input.GetArgumentAtIndex(cur_arg_pos);
        if (module_name) {
          FileSpec module_spec(module_name, false);
          lldb::TargetSP target_sp =
              interpreter.GetDebugger().GetSelectedTarget();
          // Search filters require a target...
          if (target_sp)
            filter_ap.reset(new SearchFilterByModule(target_sp, module_spec));
        }
        break;
      }
    }
  }

  return CommandCompletions::InvokeCommonCompletionCallbacks(
      interpreter, completion_mask, input.GetArgumentAtIndex(opt_arg_pos),
      match_start_point, max_return_elements, filter_ap.get(), word_complete,
      matches);
}
int
SwiftREPL::CompleteCode(const std::string &current_code,
                        lldb_private::StringList &matches)
{
    //----------------------------------------------------------------------g
    // If we use the target's SwiftASTContext for completion, it reaaallly
    // slows down subsequent expressions. The compiler team doesn't have time
    // to fix this issue currently, so we need to work around it by making
    // our own copy of the AST and using this separate AST for completion.
    //----------------------------------------------------------------------
    Error error;
#define USE_SEPARATE_AST_FOR_COMPLETION
#if defined(USE_SEPARATE_AST_FOR_COMPLETION)
    if (!m_swift_ast_sp)
    {
        SwiftASTContext *target_swift_ast = m_target.GetScratchSwiftASTContext(error);
        if (target_swift_ast)
            m_swift_ast_sp.reset (new SwiftASTContext(*target_swift_ast));
    }
    SwiftASTContext *swift_ast = m_swift_ast_sp.get();
#else
    SwiftASTContext *swift_ast = m_target.GetScratchSwiftASTContext(error);
#endif
    
    if (swift_ast)
    {
        swift::ASTContext *ast = swift_ast->GetASTContext();
        swift::REPLCompletions completions;
        static ConstString g_repl_module_name("repl");
        swift::ModuleDecl *repl_module = swift_ast->GetModule (g_repl_module_name, error);
        if (repl_module == NULL)
        {
            repl_module = swift_ast->CreateModule(g_repl_module_name, error);
            const swift::SourceFile::ImplicitModuleImportKind implicit_import_kind = swift::SourceFile::ImplicitModuleImportKind::Stdlib;
            llvm::Optional<unsigned> bufferID;
            swift::SourceFile *repl_source_file = new (*ast) swift::SourceFile(*repl_module,
                                                                               swift::SourceFileKind::REPL,
                                                                               bufferID,
                                                                               implicit_import_kind);
            repl_module->addFile(*repl_source_file);
        }
        if (repl_module)
        {
            swift::SourceFile &repl_source_file = repl_module->getMainSourceFile(swift::SourceFileKind::REPL);
            
            llvm::StringRef current_code_ref(current_code);
            completions.populate(repl_source_file, current_code_ref);
            llvm::StringRef root = completions.getRoot();
            if (!root.empty())
            {
                matches.AppendString(root.data(), root.size());
                return 1;
            }
            //                    llvm::StringRef prev_stem = completions.getPreviousStem();
            //                    llvm::StringRef next_stem = completions.getNextStem();
            //                    printf ("\nroot: '%*s'", (int)root.size(), root.data());
            //                    printf ("\nprev_stem: '%*s'", (int)prev_stem.size(), prev_stem.data());
            //                    printf ("\nnext_stem: '%*s'", (int)next_stem.size(), next_stem.data());
            //                    printf ("\nvalid: %i", completions.isValid());
            //                    printf ("\nempty: %i", completions.isEmpty());
            //                    printf ("\nunique: %i", completions.isUnique());
            
            // Otherwise, advance through the completion state machine.
            const swift::CompletionState completion_state = completions.getState();
            switch (completion_state)
            {
                case swift::CompletionState::CompletedRoot:
                {
                    // We completed the root. Next step is to display the completion list.
                    matches.AppendString(""); // Empty string to indicate no completion,
                    // just display other strings that come after it
                    llvm::ArrayRef<llvm::StringRef> llvm_matches = completions.getCompletionList();
                    for (const auto &llvm_match : llvm_matches)
                    {
                        if (!llvm_match.empty())
                            matches.AppendString(llvm_match.data(), llvm_match.size());
                    }
                    // Don't include the empty string we appended above or we will display one
                    // too many we need to return the magical value of one less than our actual matches.
                    // TODO: modify all IOHandlerDelegate::IOHandlerComplete() to use a CompletionMatches
                    // class that wraps up the "StringList matches;" along with other smarts so we don't
                    // have to return magic values and incorrect sizes.
                    return matches.GetSize() - 1;
                }
                    break;
                    
                case swift::CompletionState::DisplayedCompletionList:
                {
                    // Complete the next completion stem in the cycle.
                    llvm::StringRef stem = completions.getPreviousStem().InsertableString;
                    matches.AppendString(stem.data(), stem.size());
                }
                    break;
                    
                case swift::CompletionState::Empty:
                case swift::CompletionState::Unique:
                    // We already provided a definitive completion--nothing else to do.
                    break;
                    
                case swift::CompletionState::Invalid:
                    llvm_unreachable("got an invalid completion set?!");
            }
        }
    }
    
    return matches.GetSize();
}
示例#3
0
文件: Options.cpp 项目: kraj/lldb
bool Options::HandleOptionCompletion(
    Args &input, OptionElementVector &opt_element_vector, int cursor_index,
    int char_pos, int match_start_point, int max_return_elements,
    CommandInterpreter &interpreter, bool &word_complete,
    lldb_private::StringList &matches) {
  word_complete = true;

  // For now we just scan the completions to see if the cursor position is in
  // an option or its argument.  Otherwise we'll call HandleArgumentCompletion.
  // In the future we can use completion to validate options as well if we want.

  auto opt_defs = GetDefinitions();

  std::string cur_opt_std_str(input.GetArgumentAtIndex(cursor_index));
  cur_opt_std_str.erase(char_pos);
  const char *cur_opt_str = cur_opt_std_str.c_str();

  for (size_t i = 0; i < opt_element_vector.size(); i++) {
    int opt_pos = opt_element_vector[i].opt_pos;
    int opt_arg_pos = opt_element_vector[i].opt_arg_pos;
    int opt_defs_index = opt_element_vector[i].opt_defs_index;
    if (opt_pos == cursor_index) {
      // We're completing the option itself.

      if (opt_defs_index == OptionArgElement::eBareDash) {
        // We're completing a bare dash.  That means all options are open.
        // FIXME: We should scan the other options provided and only complete
        // options
        // within the option group they belong to.
        char opt_str[3] = {'-', 'a', '\0'};

        for (auto &def : opt_defs) {
          if (!def.short_option)
            continue;
          opt_str[1] = def.short_option;
          matches.AppendString(opt_str);
        }

        return true;
      } else if (opt_defs_index == OptionArgElement::eBareDoubleDash) {
        std::string full_name("--");
        for (auto &def : opt_defs) {
          if (!def.short_option)
            continue;

          full_name.erase(full_name.begin() + 2, full_name.end());
          full_name.append(def.long_option);
          matches.AppendString(full_name.c_str());
        }
        return true;
      } else if (opt_defs_index != OptionArgElement::eUnrecognizedArg) {
        // We recognized it, if it an incomplete long option, complete it anyway
        // (getopt_long_only is
        // happy with shortest unique string, but it's still a nice thing to
        // do.)  Otherwise return
        // The string so the upper level code will know this is a full match and
        // add the " ".
        if (cur_opt_str && strlen(cur_opt_str) > 2 && cur_opt_str[0] == '-' &&
            cur_opt_str[1] == '-' &&
            strcmp(opt_defs[opt_defs_index].long_option, cur_opt_str) != 0) {
          std::string full_name("--");
          full_name.append(opt_defs[opt_defs_index].long_option);
          matches.AppendString(full_name.c_str());
          return true;
        } else {
          matches.AppendString(input.GetArgumentAtIndex(cursor_index));
          return true;
        }
      } else {
        // FIXME - not handling wrong options yet:
        // Check to see if they are writing a long option & complete it.
        // I think we will only get in here if the long option table has two
        // elements
        // that are not unique up to this point.  getopt_long_only does shortest
        // unique match
        // for long options already.

        if (cur_opt_str && strlen(cur_opt_str) > 2 && cur_opt_str[0] == '-' &&
            cur_opt_str[1] == '-') {
          for (auto &def : opt_defs) {
            if (!def.long_option)
              continue;

            if (strstr(def.long_option, cur_opt_str + 2) == def.long_option) {
              std::string full_name("--");
              full_name.append(def.long_option);
              // The options definitions table has duplicates because of the
              // way the grouping information is stored, so only add once.
              bool duplicate = false;
              for (size_t k = 0; k < matches.GetSize(); k++) {
                if (matches.GetStringAtIndex(k) == full_name) {
                  duplicate = true;
                  break;
                }
              }
              if (!duplicate)
                matches.AppendString(full_name.c_str());
            }
          }
        }
        return true;
      }

    } else if (opt_arg_pos == cursor_index) {
      // Okay the cursor is on the completion of an argument.
      // See if it has a completion, otherwise return no matches.

      if (opt_defs_index != -1) {
        HandleOptionArgumentCompletion(
            input, cursor_index, strlen(input.GetArgumentAtIndex(cursor_index)),
            opt_element_vector, i, match_start_point, max_return_elements,
            interpreter, word_complete, matches);
        return true;
      } else {
        // No completion callback means no completions...
        return true;
      }

    } else {
      // Not the last element, keep going.
      continue;
    }
  }
  return false;
}