aboutsummaryrefslogtreecommitdiffstats
path: root/include/lldb/Utility/CompletionRequest.h
blob: 570f626ac54e86d9e6f3de6e77ed83a5ea34b2e2 (plain) (blame)
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