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.
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 
33 class CompletionResult {
34 public:
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 
55 private:
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 
61 public:
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 ///
87 class CompletionRequest {
88 public:
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 
196 private:
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