| //===-- CompletionRequest.h -------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLDB_UTILITY_COMPLETIONREQUEST_H |
| #define LLDB_UTILITY_COMPLETIONREQUEST_H |
| |
| #include "lldb/Utility/Args.h" |
| #include "lldb/Utility/LLDBAssert.h" |
| #include "lldb/Utility/StringList.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ADT/StringSet.h" |
| |
| namespace lldb_private { |
| enum class CompletionMode { |
| /// The current token has been completed. The client should indicate this |
| /// to the user (usually this is done by adding a trailing space behind the |
| /// token). |
| /// Example: "command sub" -> "command subcommand " (note the trailing space). |
| Normal, |
| /// The current token has been partially completed. This means that we found |
| /// a completion, but that the token is still incomplete. Examples |
| /// for this are file paths, where we want to complete "/bi" to "/bin/", but |
| /// the file path token is still incomplete after the completion. Clients |
| /// should not indicate to the user that this is a full completion (e.g. by |
| /// not inserting the usual trailing space after a successful completion). |
| /// Example: "file /us" -> "file /usr/" (note the missing trailing space). |
| Partial, |
| /// The full line has been rewritten by the completion. |
| /// Example: "alias name" -> "other_command full_name". |
| RewriteLine, |
| }; |
| |
| class CompletionResult { |
| public: |
| /// A single completion and all associated data. |
| class Completion { |
| |
| /// The actual text that should be completed. The meaning of this text |
| /// is defined by the CompletionMode. |
| /// \see m_mode |
| std::string m_completion; |
| /// The description that should be displayed to the user alongside the |
| /// completion text. |
| std::string m_descripton; |
| CompletionMode m_mode; |
| |
| public: |
| Completion(llvm::StringRef completion, llvm::StringRef description, |
| CompletionMode mode) |
| : m_completion(completion.str()), m_descripton(description.str()), |
| m_mode(mode) {} |
| const std::string &GetCompletion() const { return m_completion; } |
| const std::string &GetDescription() const { return m_descripton; } |
| CompletionMode GetMode() const { return m_mode; } |
| |
| /// Generates a string that uniquely identifies this completion result. |
| std::string GetUniqueKey() const; |
| }; |
| |
| private: |
| /// List of found completions. |
| std::vector<Completion> m_results; |
| |
| /// A set of the unique keys of all found completions so far. Used to filter |
| /// out duplicates. |
| /// \see CompletionResult::Completion::GetUniqueKey |
| llvm::StringSet<> m_added_values; |
| |
| public: |
| void AddResult(llvm::StringRef completion, llvm::StringRef description, |
| CompletionMode mode); |
| |
| llvm::ArrayRef<Completion> GetResults() const { return m_results; } |
| |
| /// Adds all collected completion matches to the given list. |
| /// The list will be cleared before the results are added. The number of |
| /// results here is guaranteed to be equal to GetNumberOfResults(). |
| void GetMatches(StringList &matches) const; |
| |
| /// Adds all collected completion descriptions to the given list. |
| /// The list will be cleared before the results are added. The number of |
| /// results here is guaranteed to be equal to GetNumberOfResults(). |
| void GetDescriptions(StringList &descriptions) const; |
| |
| std::size_t GetNumberOfResults() const { return m_results.size(); } |
| }; |
| |
| /// \class CompletionRequest CompletionRequest.h |
| /// "lldb/Utility/ArgCompletionRequest.h" |
| /// |
| /// Contains all information necessary to complete an incomplete command |
| /// for the user. Will be filled with the generated completions by the different |
| /// completions functions. |
| /// |
| class CompletionRequest { |
| public: |
| /// Constructs a completion request. |
| /// |
| /// \param [in] command_line |
| /// The command line the user has typed at this point. |
| /// |
| /// \param [in] raw_cursor_pos |
| /// The position of the cursor in the command line string. Index 0 means |
| /// the cursor is at the start of the line. The completion starts from |
| /// this cursor position. |
| /// |
| /// \param [out] result |
| /// The CompletionResult that will be filled with the results after this |
| /// request has been handled. |
| CompletionRequest(llvm::StringRef command_line, unsigned raw_cursor_pos, |
| CompletionResult &result); |
| |
| /// Returns the raw user input used to create this CompletionRequest cut off |
| /// at the cursor position. The cursor will be at the end of the raw line. |
| llvm::StringRef GetRawLine() const { |
| return m_command.substr(0, GetRawCursorPos()); |
| } |
| |
| /// Returns the full raw user input used to create this CompletionRequest. |
| /// This string is not cut off at the cursor position and will include |
| /// characters behind the cursor position. |
| /// |
| /// You should most likely *not* use this function unless the characters |
| /// behind the cursor position influence the completion. |
| llvm::StringRef GetRawLineWithUnusedSuffix() const { return m_command; } |
| |
| unsigned GetRawCursorPos() const { return m_raw_cursor_pos; } |
| |
| const Args &GetParsedLine() const { return m_parsed_line; } |
| |
| Args &GetParsedLine() { return m_parsed_line; } |
| |
| const Args::ArgEntry &GetParsedArg() { |
| return GetParsedLine()[GetCursorIndex()]; |
| } |
| |
| /// Drops the first argument from the argument list. |
| void ShiftArguments() { |
| m_cursor_index--; |
| m_parsed_line.Shift(); |
| } |
| |
| /// Adds an empty argument at the end of the argument list and moves |
| /// the cursor to this new argument. |
| void AppendEmptyArgument() { |
| m_parsed_line.AppendArgument(llvm::StringRef()); |
| m_cursor_index++; |
| m_cursor_char_position = 0; |
| } |
| |
| size_t GetCursorIndex() const { return m_cursor_index; } |
| |
| /// Adds a possible completion string. If the completion was already |
| /// suggested before, it will not be added to the list of results. A copy of |
| /// the suggested completion is stored, so the given string can be free'd |
| /// afterwards. |
| /// |
| /// \param match The suggested completion. |
| /// \param completion An optional description of the completion string. The |
| /// description will be displayed to the user alongside the completion. |
| /// \param mode The CompletionMode for this completion. |
| void AddCompletion(llvm::StringRef completion, |
| llvm::StringRef description = "", |
| CompletionMode mode = CompletionMode::Normal) { |
| m_result.AddResult(completion, description, mode); |
| } |
| |
| /// Adds a possible completion string if the completion would complete the |
| /// current argument. |
| /// |
| /// \param match The suggested completion. |
| /// \param description An optional description of the completion string. The |
| /// description will be displayed to the user alongside the completion. |
| template <CompletionMode M = CompletionMode::Normal> |
| void TryCompleteCurrentArg(llvm::StringRef completion, |
| llvm::StringRef description = "") { |
| // Trying to rewrite the whole line while checking for the current |
| // argument never makes sense. Completion modes are always hardcoded, so |
| // this can be a static_assert. |
| static_assert(M != CompletionMode::RewriteLine, |
| "Shouldn't rewrite line with this function"); |
| if (completion.startswith(GetCursorArgumentPrefix())) |
| AddCompletion(completion, description, M); |
| } |
| |
| /// Adds multiple possible completion strings. |
| /// |
| /// \param completions The list of completions. |
| /// |
| /// \see AddCompletion |
| void AddCompletions(const StringList &completions) { |
| for (const std::string &completion : completions) |
| AddCompletion(completion); |
| } |
| |
| /// Adds multiple possible completion strings alongside their descriptions. |
| /// |
| /// The number of completions and descriptions must be identical. |
| /// |
| /// \param completions The list of completions. |
| /// \param completions The list of descriptions. |
| /// |
| /// \see AddCompletion |
| void AddCompletions(const StringList &completions, |
| const StringList &descriptions) { |
| lldbassert(completions.GetSize() == descriptions.GetSize()); |
| for (std::size_t i = 0; i < completions.GetSize(); ++i) |
| AddCompletion(completions.GetStringAtIndex(i), |
| descriptions.GetStringAtIndex(i)); |
| } |
| |
| llvm::StringRef GetCursorArgumentPrefix() const { |
| return GetParsedLine().GetArgumentAtIndex(GetCursorIndex()); |
| } |
| |
| private: |
| /// The raw command line we are supposed to complete. |
| llvm::StringRef m_command; |
| /// The cursor position in m_command. |
| unsigned m_raw_cursor_pos; |
| /// The command line parsed as arguments. |
| Args m_parsed_line; |
| /// The index of the argument in which the completion cursor is. |
| size_t m_cursor_index; |
| /// The cursor position in the argument indexed by m_cursor_index. |
| size_t m_cursor_char_position; |
| |
| /// The result this request is supposed to fill out. |
| /// We keep this object private to ensure that no backend can in any way |
| /// depend on already calculated completions (which would make debugging and |
| /// testing them much more complicated). |
| CompletionResult &m_result; |
| }; |
| |
| } // namespace lldb_private |
| |
| #endif // LLDB_UTILITY_COMPLETIONREQUEST_H |