Пример #1
0
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();
}
Пример #2
0
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;
}