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