1//===-- CompletionRequest.h -------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLDB_UTILITY_COMPLETIONREQUEST_H
10#define LLDB_UTILITY_COMPLETIONREQUEST_H
11
12#include "lldb/Utility/Args.h"
13#include "lldb/Utility/LLDBAssert.h"
14#include "lldb/Utility/StringList.h"
15#include "llvm/ADT/StringRef.h"
16#include "llvm/ADT/StringSet.h"
17
18namespace lldb_private {
19enum class CompletionMode {
20  // The current token has been completed.
21  Normal,
22  // The current token has been partially completed. This means that we found
23  // a completion, but that the completed token is still incomplete. Examples
24  // for this are file paths, where we want to complete "/bi" to "/bin/", but
25  // the file path token is still incomplete after the completion. Clients
26  // should not indicate to the user that this is a full completion (e.g. by
27  // not inserting the usual trailing space after a successful completion).
28  Partial,
29  // The full line has been rewritten by the completion.
30  RewriteLine,
31};
32
33class CompletionResult {
34public:
35  /// A single completion and all associated data.
36  class Completion {
37
38    std::string m_completion;
39    std::string m_descripton;
40    CompletionMode m_mode;
41
42  public:
43    Completion(llvm::StringRef completion, llvm::StringRef description,
44               CompletionMode mode)
45        : m_completion(completion.str()), m_descripton(description.str()),
46          m_mode(mode) {}
47    const std::string &GetCompletion() const { return m_completion; }
48    const std::string &GetDescription() const { return m_descripton; }
49    CompletionMode GetMode() const { return m_mode; }
50
51    /// Generates a string that uniquely identifies this completion result.
52    std::string GetUniqueKey() const;
53  };
54
55private:
56  std::vector<Completion> m_results;
57
58  /// List of added completions so far. Used to filter out duplicates.
59  llvm::StringSet<> m_added_values;
60
61public:
62  void AddResult(llvm::StringRef completion, llvm::StringRef description,
63                 CompletionMode mode);
64
65  llvm::ArrayRef<Completion> GetResults() const { return m_results; }
66
67  /// Adds all collected completion matches to the given list.
68  /// The list will be cleared before the results are added. The number of
69  /// results here is guaranteed to be equal to GetNumberOfResults().
70  void GetMatches(StringList &matches) const;
71
72  /// Adds all collected completion descriptions to the given list.
73  /// The list will be cleared before the results are added. The number of
74  /// results here is guaranteed to be equal to GetNumberOfResults().
75  void GetDescriptions(StringList &descriptions) const;
76
77  std::size_t GetNumberOfResults() const { return m_results.size(); }
78};
79
80/// \class CompletionRequest CompletionRequest.h
81///   "lldb/Utility/ArgCompletionRequest.h"
82///
83/// Contains all information necessary to complete an incomplete command
84/// for the user. Will be filled with the generated completions by the different
85/// completions functions.
86///
87class CompletionRequest {
88public:
89  /// Constructs a completion request.
90  ///
91  /// \param [in] command_line
92  ///     The command line the user has typed at this point.
93  ///
94  /// \param [in] raw_cursor_pos
95  ///     The position of the cursor in the command line string. Index 0 means
96  ///     the cursor is at the start of the line. The completion starts from
97  ///     this cursor position.
98  ///
99  /// \param [out] result
100  ///     The CompletionResult that will be filled with the results after this
101  ///     request has been handled.
102  CompletionRequest(llvm::StringRef command_line, unsigned raw_cursor_pos,
103                    CompletionResult &result);
104
105  llvm::StringRef GetRawLine() const { return m_command; }
106
107  unsigned GetRawCursorPos() const { return m_raw_cursor_pos; }
108
109  const Args &GetParsedLine() const { return m_parsed_line; }
110
111  Args &GetParsedLine() { return m_parsed_line; }
112
113  const Args::ArgEntry &GetParsedArg() {
114    return GetParsedLine()[GetCursorIndex()];
115  }
116
117  /// Drops the first argument from the argument list.
118  void ShiftArguments() {
119    m_cursor_index--;
120    m_parsed_line.Shift();
121  }
122
123  /// Adds an empty argument at the end of the argument list and moves
124  /// the cursor to this new argument.
125  void AppendEmptyArgument() {
126    m_parsed_line.AppendArgument(llvm::StringRef());
127    m_cursor_index++;
128    m_cursor_char_position = 0;
129  }
130
131  size_t GetCursorIndex() const { return m_cursor_index; }
132
133  /// Adds a possible completion string. If the completion was already
134  /// suggested before, it will not be added to the list of results. A copy of
135  /// the suggested completion is stored, so the given string can be free'd
136  /// afterwards.
137  ///
138  /// \param match The suggested completion.
139  /// \param completion An optional description of the completion string. The
140  ///     description will be displayed to the user alongside the completion.
141  /// \param mode The CompletionMode for this completion.
142  void AddCompletion(llvm::StringRef completion,
143                     llvm::StringRef description = "",
144                     CompletionMode mode = CompletionMode::Normal) {
145    m_result.AddResult(completion, description, mode);
146  }
147
148  /// Adds a possible completion string if the completion would complete the
149  /// current argument.
150  ///
151  /// \param match The suggested completion.
152  /// \param description An optional description of the completion string. The
153  ///     description will be displayed to the user alongside the completion.
154  template <CompletionMode M = CompletionMode::Normal>
155  void TryCompleteCurrentArg(llvm::StringRef completion,
156                             llvm::StringRef description = "") {
157    // Trying to rewrite the whole line while checking for the current
158    // argument never makes sense. Completion modes are always hardcoded, so
159    // this can be a static_assert.
160    static_assert(M != CompletionMode::RewriteLine,
161                  "Shouldn't rewrite line with this function");
162    if (completion.startswith(GetCursorArgumentPrefix()))
163      AddCompletion(completion, description, M);
164  }
165
166  /// Adds multiple possible completion strings.
167  ///
168  /// \param completions The list of completions.
169  ///
170  /// \see AddCompletion
171  void AddCompletions(const StringList &completions) {
172    for (const std::string &completion : completions)
173      AddCompletion(completion);
174  }
175
176  /// Adds multiple possible completion strings alongside their descriptions.
177  ///
178  /// The number of completions and descriptions must be identical.
179  ///
180  /// \param completions The list of completions.
181  /// \param completions The list of descriptions.
182  ///
183  /// \see AddCompletion
184  void AddCompletions(const StringList &completions,
185                      const StringList &descriptions) {
186    lldbassert(completions.GetSize() == descriptions.GetSize());
187    for (std::size_t i = 0; i < completions.GetSize(); ++i)
188      AddCompletion(completions.GetStringAtIndex(i),
189                    descriptions.GetStringAtIndex(i));
190  }
191
192  llvm::StringRef GetCursorArgumentPrefix() const {
193    return GetParsedLine().GetArgumentAtIndex(GetCursorIndex());
194  }
195
196private:
197  /// The raw command line we are supposed to complete.
198  llvm::StringRef m_command;
199  /// The cursor position in m_command.
200  unsigned m_raw_cursor_pos;
201  /// The command line parsed as arguments.
202  Args m_parsed_line;
203  /// The index of the argument in which the completion cursor is.
204  size_t m_cursor_index;
205  /// The cursor position in the argument indexed by m_cursor_index.
206  size_t m_cursor_char_position;
207
208  /// The result this request is supposed to fill out.
209  /// We keep this object private to ensure that no backend can in any way
210  /// depend on already calculated completions (which would make debugging and
211  /// testing them much more complicated).
212  CompletionResult &m_result;
213};
214
215} // namespace lldb_private
216
217#endif // LLDB_UTILITY_COMPLETIONREQUEST_H
218