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.str()), m_descripton(description.str()), 56 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 /// 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. GetRawLine()120 llvm::StringRef GetRawLine() const { 121 return m_command.substr(0, 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. GetRawLineWithUnusedSuffix()130 llvm::StringRef GetRawLineWithUnusedSuffix() const { return m_command; } 131 GetRawCursorPos()132 unsigned GetRawCursorPos() const { return m_raw_cursor_pos; } 133 GetParsedLine()134 const Args &GetParsedLine() const { return m_parsed_line; } 135 GetParsedLine()136 Args &GetParsedLine() { return m_parsed_line; } 137 GetParsedArg()138 const Args::ArgEntry &GetParsedArg() { 139 return GetParsedLine()[GetCursorIndex()]; 140 } 141 142 /// Drops the first argument from the argument list. ShiftArguments()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. AppendEmptyArgument()150 void AppendEmptyArgument() { 151 m_parsed_line.AppendArgument(llvm::StringRef()); 152 m_cursor_index++; 153 m_cursor_char_position = 0; 154 } 155 GetCursorIndex()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.startswith(GetCursorArgumentPrefix())) 188 AddCompletion(completion, description, M); 189 } 190 191 /// Adds multiple possible completion strings. 192 /// 193 /// \param completions The list of completions. 194 /// 195 /// \see AddCompletion AddCompletions(const StringList & completions)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 AddCompletions(const StringList & completions,const StringList & descriptions)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(completions.GetStringAtIndex(i), 214 descriptions.GetStringAtIndex(i)); 215 } 216 GetCursorArgumentPrefix()217 llvm::StringRef GetCursorArgumentPrefix() const { 218 return GetParsedLine().GetArgumentAtIndex(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