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: Completion(llvm::StringRef completion,llvm::StringRef description,CompletionMode mode)53 Completion(llvm::StringRef completion, llvm::StringRef description, 54 CompletionMode mode) 55 : m_completion(completion.rtrim().str()), 56 m_descripton(description.rtrim().str()), m_mode(mode) {} GetCompletion()57 const std::string &GetCompletion() const { return m_completion; } GetDescription()58 const std::string &GetDescription() const { return m_descripton; } GetMode()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 GetResults()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 GetNumberOfResults()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 /// Sets the maximum number of completions that should be returned. SetMaxReturnElements(size_t max_return_elements)119 void SetMaxReturnElements(size_t max_return_elements) { 120 m_max_return_elements = max_return_elements; 121 } 122 123 /// Returns the raw user input used to create this CompletionRequest cut off 124 /// at the cursor position. The cursor will be at the end of the raw line. GetRawLine()125 llvm::StringRef GetRawLine() const { 126 return m_command.substr(0, GetRawCursorPos()); 127 } 128 129 /// Returns the full raw user input used to create this CompletionRequest. 130 /// This string is not cut off at the cursor position and will include 131 /// characters behind the cursor position. 132 /// 133 /// You should most likely *not* use this function unless the characters 134 /// behind the cursor position influence the completion. GetRawLineWithUnusedSuffix()135 llvm::StringRef GetRawLineWithUnusedSuffix() const { return m_command; } 136 GetRawCursorPos()137 unsigned GetRawCursorPos() const { return m_raw_cursor_pos; } 138 GetParsedLine()139 const Args &GetParsedLine() const { return m_parsed_line; } 140 GetParsedLine()141 Args &GetParsedLine() { return m_parsed_line; } 142 GetParsedArg()143 const Args::ArgEntry &GetParsedArg() { 144 return GetParsedLine()[GetCursorIndex()]; 145 } 146 GetCursorCharPos()147 size_t GetCursorCharPos() const { return m_cursor_char_position; } 148 149 /// Drops the first argument from the argument list. ShiftArguments()150 void ShiftArguments() { 151 m_cursor_index--; 152 m_parsed_line.Shift(); 153 } 154 155 /// Adds an empty argument at the end of the argument list and moves 156 /// the cursor to this new argument. AppendEmptyArgument()157 void AppendEmptyArgument() { 158 m_parsed_line.AppendArgument(llvm::StringRef()); 159 m_cursor_index++; 160 m_cursor_char_position = 0; 161 } 162 GetCursorIndex()163 size_t GetCursorIndex() const { return m_cursor_index; } 164 GetMaxReturnElements()165 size_t GetMaxReturnElements() const { return m_max_return_elements; } 166 167 /// Returns true if the maximum number of completions has not been reached 168 /// yet, hence we should keep adding completions. ShouldAddCompletions()169 bool ShouldAddCompletions() const { 170 return GetMaxNumberOfCompletionsToAdd() > 0; 171 } 172 173 /// Returns the maximum number of completions that need to be added 174 /// until reaching the maximum GetMaxNumberOfCompletionsToAdd()175 size_t GetMaxNumberOfCompletionsToAdd() const { 176 const size_t number_of_results = m_result.GetNumberOfResults(); 177 if (number_of_results >= m_max_return_elements) 178 return 0; 179 return m_max_return_elements - number_of_results; 180 } 181 182 /// Adds a possible completion string. If the completion was already 183 /// suggested before, it will not be added to the list of results. A copy of 184 /// the suggested completion is stored, so the given string can be free'd 185 /// afterwards. 186 /// 187 /// \param completion The suggested completion. 188 /// \param description An optional description of the completion string. The 189 /// description will be displayed to the user alongside the completion. 190 /// \param mode The CompletionMode for this completion. 191 void AddCompletion(llvm::StringRef completion, 192 llvm::StringRef description = "", 193 CompletionMode mode = CompletionMode::Normal) { 194 m_result.AddResult(completion, description, mode); 195 } 196 197 /// Adds a possible completion string if the completion would complete the 198 /// current argument. 199 /// 200 /// \param completion The suggested completion. 201 /// \param description An optional description of the completion string. The 202 /// description will be displayed to the user alongside the completion. 203 template <CompletionMode M = CompletionMode::Normal> 204 void TryCompleteCurrentArg(llvm::StringRef completion, 205 llvm::StringRef description = "") { 206 // Trying to rewrite the whole line while checking for the current 207 // argument never makes sense. Completion modes are always hardcoded, so 208 // this can be a static_assert. 209 static_assert(M != CompletionMode::RewriteLine, 210 "Shouldn't rewrite line with this function"); 211 if (completion.starts_with(GetCursorArgumentPrefix())) 212 AddCompletion(completion, description, M); 213 } 214 215 /// Adds multiple possible completion strings. 216 /// 217 /// \param completions The list of completions. 218 /// 219 /// \see AddCompletion AddCompletions(const StringList & completions)220 void AddCompletions(const StringList &completions) { 221 for (const std::string &completion : completions) 222 AddCompletion(completion); 223 } 224 225 /// Adds multiple possible completion strings alongside their descriptions. 226 /// 227 /// The number of completions and descriptions must be identical. 228 /// 229 /// \param completions The list of completions. 230 /// \param descriptions The list of descriptions. 231 /// 232 /// \see AddCompletion AddCompletions(const StringList & completions,const StringList & descriptions)233 void AddCompletions(const StringList &completions, 234 const StringList &descriptions) { 235 lldbassert(completions.GetSize() == descriptions.GetSize()); 236 for (std::size_t i = 0; i < completions.GetSize(); ++i) 237 AddCompletion(completions.GetStringAtIndex(i), 238 descriptions.GetStringAtIndex(i)); 239 } 240 GetCursorArgumentPrefix()241 llvm::StringRef GetCursorArgumentPrefix() const { 242 return GetParsedLine().GetArgumentAtIndex(GetCursorIndex()); 243 } 244 245 private: 246 /// The raw command line we are supposed to complete. 247 llvm::StringRef m_command; 248 /// The cursor position in m_command. 249 unsigned m_raw_cursor_pos; 250 /// The command line parsed as arguments. 251 Args m_parsed_line; 252 /// The index of the argument in which the completion cursor is. 253 size_t m_cursor_index; 254 /// The cursor position in the argument indexed by m_cursor_index. 255 size_t m_cursor_char_position; 256 /// The maximum number of completions that should be returned. 257 size_t m_max_return_elements = std::numeric_limits<size_t>::max(); 258 259 /// The result this request is supposed to fill out. 260 /// We keep this object private to ensure that no backend can in any way 261 /// depend on already calculated completions (which would make debugging and 262 /// testing them much more complicated). 263 CompletionResult &m_result; 264 }; 265 266 } // namespace lldb_private 267 268 #endif // LLDB_UTILITY_COMPLETIONREQUEST_H 269