reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
//===-- CompletionRequest.h -------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_UTILITY_COMPLETIONREQUEST_H
#define LLDB_UTILITY_COMPLETIONREQUEST_H

#include "lldb/Utility/Args.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/StringList.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"

namespace lldb_private {
enum class CompletionMode {
  // The current token has been completed.
  Normal,
  // The current token has been partially completed. This means that we found
  // a completion, but that the completed token is still incomplete. Examples
  // for this are file paths, where we want to complete "/bi" to "/bin/", but
  // the file path token is still incomplete after the completion. Clients
  // should not indicate to the user that this is a full completion (e.g. by
  // not inserting the usual trailing space after a successful completion).
  Partial,
  // The full line has been rewritten by the completion.
  RewriteLine,
};

class CompletionResult {
public:
  /// A single completion and all associated data.
  class Completion {

    std::string m_completion;
    std::string m_descripton;
    CompletionMode m_mode;

  public:
    Completion(llvm::StringRef completion, llvm::StringRef description,
               CompletionMode mode)
        : m_completion(completion.str()), m_descripton(description.str()),
          m_mode(mode) {}
    const std::string &GetCompletion() const { return m_completion; }
    const std::string &GetDescription() const { return m_descripton; }
    CompletionMode GetMode() const { return m_mode; }

    /// Generates a string that uniquely identifies this completion result.
    std::string GetUniqueKey() const;
  };

private:
  std::vector<Completion> m_results;

  /// List of added completions so far. Used to filter out duplicates.
  llvm::StringSet<> m_added_values;

public:
  void AddResult(llvm::StringRef completion, llvm::StringRef description,
                 CompletionMode mode);

  llvm::ArrayRef<Completion> GetResults() const { return m_results; }

  /// Adds all collected completion matches to the given list.
  /// The list will be cleared before the results are added. The number of
  /// results here is guaranteed to be equal to GetNumberOfResults().
  void GetMatches(StringList &matches) const;

  /// Adds all collected completion descriptions to the given list.
  /// The list will be cleared before the results are added. The number of
  /// results here is guaranteed to be equal to GetNumberOfResults().
  void GetDescriptions(StringList &descriptions) const;

  std::size_t GetNumberOfResults() const { return m_results.size(); }
};

/// \class CompletionRequest CompletionRequest.h
///   "lldb/Utility/ArgCompletionRequest.h"
///
/// Contains all information necessary to complete an incomplete command
/// for the user. Will be filled with the generated completions by the different
/// completions functions.
///
class CompletionRequest {
public:
  /// Constructs a completion request.
  ///
  /// \param [in] command_line
  ///     The command line the user has typed at this point.
  ///
  /// \param [in] raw_cursor_pos
  ///     The position of the cursor in the command line string. Index 0 means
  ///     the cursor is at the start of the line. The completion starts from
  ///     this cursor position.
  ///
  /// \param [out] result
  ///     The CompletionResult that will be filled with the results after this
  ///     request has been handled.
  CompletionRequest(llvm::StringRef command_line, unsigned raw_cursor_pos,
                    CompletionResult &result);

  llvm::StringRef GetRawLine() const { return m_command; }

  unsigned GetRawCursorPos() const { return m_raw_cursor_pos; }

  const Args &GetParsedLine() const { return m_parsed_line; }

  Args &GetParsedLine() { return m_parsed_line; }

  const Args::ArgEntry &GetParsedArg() {
    return GetParsedLine()[GetCursorIndex()];
  }

  /// Drops the first argument from the argument list.
  void ShiftArguments() {
    m_cursor_index--;
    m_parsed_line.Shift();
  }

  /// Adds an empty argument at the end of the argument list and moves
  /// the cursor to this new argument.
  void AppendEmptyArgument() {
    m_parsed_line.AppendArgument(llvm::StringRef());
    m_cursor_index++;
    m_cursor_char_position = 0;
  }

  size_t GetCursorIndex() const { return m_cursor_index; }

  /// Adds a possible completion string. If the completion was already
  /// suggested before, it will not be added to the list of results. A copy of
  /// the suggested completion is stored, so the given string can be free'd
  /// afterwards.
  ///
  /// \param match The suggested completion.
  /// \param completion An optional description of the completion string. The
  ///     description will be displayed to the user alongside the completion.
  /// \param mode The CompletionMode for this completion.
  void AddCompletion(llvm::StringRef completion,
                     llvm::StringRef description = "",
                     CompletionMode mode = CompletionMode::Normal) {
    m_result.AddResult(completion, description, mode);
  }

  /// Adds a possible completion string if the completion would complete the
  /// current argument.
  ///
  /// \param match The suggested completion.
  /// \param description An optional description of the completion string. The
  ///     description will be displayed to the user alongside the completion.
  template <CompletionMode M = CompletionMode::Normal>
  void TryCompleteCurrentArg(llvm::StringRef completion,
                             llvm::StringRef description = "") {
    // Trying to rewrite the whole line while checking for the current
    // argument never makes sense. Completion modes are always hardcoded, so
    // this can be a static_assert.
    static_assert(M != CompletionMode::RewriteLine,
                  "Shouldn't rewrite line with this function");
    if (completion.startswith(GetCursorArgumentPrefix()))
      AddCompletion(completion, description, M);
  }

  /// Adds multiple possible completion strings.
  ///
  /// \param completions The list of completions.
  ///
  /// \see AddCompletion
  void AddCompletions(const StringList &completions) {
    for (const std::string &completion : completions)
      AddCompletion(completion);
  }

  /// Adds multiple possible completion strings alongside their descriptions.
  ///
  /// The number of completions and descriptions must be identical.
  ///
  /// \param completions The list of completions.
  /// \param completions The list of descriptions.
  ///
  /// \see AddCompletion
  void AddCompletions(const StringList &completions,
                      const StringList &descriptions) {
    lldbassert(completions.GetSize() == descriptions.GetSize());
    for (std::size_t i = 0; i < completions.GetSize(); ++i)
      AddCompletion(completions.GetStringAtIndex(i),
                    descriptions.GetStringAtIndex(i));
  }

  llvm::StringRef GetCursorArgumentPrefix() const {
    return GetParsedLine().GetArgumentAtIndex(GetCursorIndex());
  }

private:
  /// The raw command line we are supposed to complete.
  llvm::StringRef m_command;
  /// The cursor position in m_command.
  unsigned m_raw_cursor_pos;
  /// The command line parsed as arguments.
  Args m_parsed_line;
  /// The index of the argument in which the completion cursor is.
  size_t m_cursor_index;
  /// The cursor position in the argument indexed by m_cursor_index.
  size_t m_cursor_char_position;

  /// The result this request is supposed to fill out.
  /// We keep this object private to ensure that no backend can in any way
  /// depend on already calculated completions (which would make debugging and
  /// testing them much more complicated).
  CompletionResult &m_result;
};

} // namespace lldb_private

#endif // LLDB_UTILITY_COMPLETIONREQUEST_H