xref: /openbsd-src/gnu/llvm/lldb/source/Commands/CommandCompletions.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- CommandCompletions.cpp --------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "llvm/ADT/SmallString.h"
10061da546Spatrick #include "llvm/ADT/StringSet.h"
11061da546Spatrick 
12be691f3bSpatrick #include "lldb/Breakpoint/Watchpoint.h"
13061da546Spatrick #include "lldb/Core/FileSpecList.h"
14061da546Spatrick #include "lldb/Core/Module.h"
15061da546Spatrick #include "lldb/Core/PluginManager.h"
16be691f3bSpatrick #include "lldb/DataFormatters/DataVisualization.h"
17061da546Spatrick #include "lldb/Host/FileSystem.h"
18061da546Spatrick #include "lldb/Interpreter/CommandCompletions.h"
19061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
20*f6aab3d8Srobert #include "lldb/Interpreter/CommandObject.h"
21*f6aab3d8Srobert #include "lldb/Interpreter/CommandObjectMultiword.h"
22061da546Spatrick #include "lldb/Interpreter/OptionValueProperties.h"
23061da546Spatrick #include "lldb/Symbol/CompileUnit.h"
24061da546Spatrick #include "lldb/Symbol/Variable.h"
25be691f3bSpatrick #include "lldb/Target/Language.h"
26be691f3bSpatrick #include "lldb/Target/Process.h"
27dda28197Spatrick #include "lldb/Target/RegisterContext.h"
28be691f3bSpatrick #include "lldb/Target/Thread.h"
29061da546Spatrick #include "lldb/Utility/FileSpec.h"
30061da546Spatrick #include "lldb/Utility/StreamString.h"
31061da546Spatrick #include "lldb/Utility/TildeExpressionResolver.h"
32061da546Spatrick 
33061da546Spatrick #include "llvm/Support/FileSystem.h"
34061da546Spatrick #include "llvm/Support/Path.h"
35061da546Spatrick 
36061da546Spatrick using namespace lldb_private;
37061da546Spatrick 
38dda28197Spatrick // This is the command completion callback that is used to complete the
39dda28197Spatrick // argument of the option it is bound to (in the OptionDefinition table
40dda28197Spatrick // below).
41dda28197Spatrick typedef void (*CompletionCallback)(CommandInterpreter &interpreter,
42dda28197Spatrick                                    CompletionRequest &request,
43dda28197Spatrick                                    // A search filter to limit the search...
44dda28197Spatrick                                    lldb_private::SearchFilter *searcher);
45dda28197Spatrick 
46dda28197Spatrick struct CommonCompletionElement {
47dda28197Spatrick   uint32_t type;
48dda28197Spatrick   CompletionCallback callback;
49dda28197Spatrick };
50dda28197Spatrick 
InvokeCommonCompletionCallbacks(CommandInterpreter & interpreter,uint32_t completion_mask,CompletionRequest & request,SearchFilter * searcher)51dda28197Spatrick bool CommandCompletions::InvokeCommonCompletionCallbacks(
52dda28197Spatrick     CommandInterpreter &interpreter, uint32_t completion_mask,
53dda28197Spatrick     CompletionRequest &request, SearchFilter *searcher) {
54dda28197Spatrick   bool handled = false;
55dda28197Spatrick 
56dda28197Spatrick   const CommonCompletionElement common_completions[] = {
57061da546Spatrick       {eSourceFileCompletion, CommandCompletions::SourceFiles},
58061da546Spatrick       {eDiskFileCompletion, CommandCompletions::DiskFiles},
59061da546Spatrick       {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
60061da546Spatrick       {eSymbolCompletion, CommandCompletions::Symbols},
61061da546Spatrick       {eModuleCompletion, CommandCompletions::Modules},
62be691f3bSpatrick       {eModuleUUIDCompletion, CommandCompletions::ModuleUUIDs},
63061da546Spatrick       {eSettingsNameCompletion, CommandCompletions::SettingsNames},
64061da546Spatrick       {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames},
65061da546Spatrick       {eArchitectureCompletion, CommandCompletions::ArchitectureNames},
66061da546Spatrick       {eVariablePathCompletion, CommandCompletions::VariablePath},
67dda28197Spatrick       {eRegisterCompletion, CommandCompletions::Registers},
68dda28197Spatrick       {eBreakpointCompletion, CommandCompletions::Breakpoints},
69dda28197Spatrick       {eProcessPluginCompletion, CommandCompletions::ProcessPluginNames},
70be691f3bSpatrick       {eDisassemblyFlavorCompletion, CommandCompletions::DisassemblyFlavors},
71be691f3bSpatrick       {eTypeLanguageCompletion, CommandCompletions::TypeLanguages},
72be691f3bSpatrick       {eFrameIndexCompletion, CommandCompletions::FrameIndexes},
73be691f3bSpatrick       {eStopHookIDCompletion, CommandCompletions::StopHookIDs},
74be691f3bSpatrick       {eThreadIndexCompletion, CommandCompletions::ThreadIndexes},
75be691f3bSpatrick       {eWatchPointIDCompletion, CommandCompletions::WatchPointIDs},
76be691f3bSpatrick       {eBreakpointNameCompletion, CommandCompletions::BreakpointNames},
77be691f3bSpatrick       {eProcessIDCompletion, CommandCompletions::ProcessIDs},
78be691f3bSpatrick       {eProcessNameCompletion, CommandCompletions::ProcessNames},
79be691f3bSpatrick       {eRemoteDiskFileCompletion, CommandCompletions::RemoteDiskFiles},
80be691f3bSpatrick       {eRemoteDiskDirectoryCompletion,
81be691f3bSpatrick        CommandCompletions::RemoteDiskDirectories},
82be691f3bSpatrick       {eTypeCategoryNameCompletion, CommandCompletions::TypeCategoryNames},
83061da546Spatrick       {eNoCompletion, nullptr} // This one has to be last in the list.
84061da546Spatrick   };
85061da546Spatrick 
86061da546Spatrick   for (int i = 0;; i++) {
87dda28197Spatrick     if (common_completions[i].type == eNoCompletion)
88061da546Spatrick       break;
89dda28197Spatrick     else if ((common_completions[i].type & completion_mask) ==
90dda28197Spatrick                  common_completions[i].type &&
91dda28197Spatrick              common_completions[i].callback != nullptr) {
92061da546Spatrick       handled = true;
93dda28197Spatrick       common_completions[i].callback(interpreter, request, searcher);
94061da546Spatrick     }
95061da546Spatrick   }
96061da546Spatrick   return handled;
97061da546Spatrick }
98061da546Spatrick 
99dda28197Spatrick namespace {
100dda28197Spatrick // The Completer class is a convenient base class for building searchers that
101dda28197Spatrick // go along with the SearchFilter passed to the standard Completer functions.
102dda28197Spatrick class Completer : public Searcher {
103dda28197Spatrick public:
Completer(CommandInterpreter & interpreter,CompletionRequest & request)104dda28197Spatrick   Completer(CommandInterpreter &interpreter, CompletionRequest &request)
105dda28197Spatrick       : m_interpreter(interpreter), m_request(request) {}
106dda28197Spatrick 
107dda28197Spatrick   ~Completer() override = default;
108dda28197Spatrick 
109dda28197Spatrick   CallbackReturn SearchCallback(SearchFilter &filter, SymbolContext &context,
110dda28197Spatrick                                 Address *addr) override = 0;
111dda28197Spatrick 
112dda28197Spatrick   lldb::SearchDepth GetDepth() override = 0;
113dda28197Spatrick 
114dda28197Spatrick   virtual void DoCompletion(SearchFilter *filter) = 0;
115dda28197Spatrick 
116dda28197Spatrick protected:
117dda28197Spatrick   CommandInterpreter &m_interpreter;
118dda28197Spatrick   CompletionRequest &m_request;
119dda28197Spatrick 
120dda28197Spatrick private:
121dda28197Spatrick   Completer(const Completer &) = delete;
122dda28197Spatrick   const Completer &operator=(const Completer &) = delete;
123dda28197Spatrick };
124dda28197Spatrick } // namespace
125dda28197Spatrick 
126dda28197Spatrick // SourceFileCompleter implements the source file completer
127dda28197Spatrick namespace {
128dda28197Spatrick class SourceFileCompleter : public Completer {
129dda28197Spatrick public:
SourceFileCompleter(CommandInterpreter & interpreter,CompletionRequest & request)130dda28197Spatrick   SourceFileCompleter(CommandInterpreter &interpreter,
131dda28197Spatrick                       CompletionRequest &request)
132*f6aab3d8Srobert       : Completer(interpreter, request) {
133dda28197Spatrick     FileSpec partial_spec(m_request.GetCursorArgumentPrefix());
134dda28197Spatrick     m_file_name = partial_spec.GetFilename().GetCString();
135dda28197Spatrick     m_dir_name = partial_spec.GetDirectory().GetCString();
136dda28197Spatrick   }
137dda28197Spatrick 
GetDepth()138dda28197Spatrick   lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthCompUnit; }
139dda28197Spatrick 
SearchCallback(SearchFilter & filter,SymbolContext & context,Address * addr)140dda28197Spatrick   Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
141dda28197Spatrick                                           SymbolContext &context,
142dda28197Spatrick                                           Address *addr) override {
143dda28197Spatrick     if (context.comp_unit != nullptr) {
144dda28197Spatrick       const char *cur_file_name =
145dda28197Spatrick           context.comp_unit->GetPrimaryFile().GetFilename().GetCString();
146dda28197Spatrick       const char *cur_dir_name =
147dda28197Spatrick           context.comp_unit->GetPrimaryFile().GetDirectory().GetCString();
148dda28197Spatrick 
149dda28197Spatrick       bool match = false;
150dda28197Spatrick       if (m_file_name && cur_file_name &&
151dda28197Spatrick           strstr(cur_file_name, m_file_name) == cur_file_name)
152dda28197Spatrick         match = true;
153dda28197Spatrick 
154dda28197Spatrick       if (match && m_dir_name && cur_dir_name &&
155dda28197Spatrick           strstr(cur_dir_name, m_dir_name) != cur_dir_name)
156dda28197Spatrick         match = false;
157dda28197Spatrick 
158dda28197Spatrick       if (match) {
159dda28197Spatrick         m_matching_files.AppendIfUnique(context.comp_unit->GetPrimaryFile());
160dda28197Spatrick       }
161dda28197Spatrick     }
162dda28197Spatrick     return Searcher::eCallbackReturnContinue;
163dda28197Spatrick   }
164dda28197Spatrick 
DoCompletion(SearchFilter * filter)165dda28197Spatrick   void DoCompletion(SearchFilter *filter) override {
166dda28197Spatrick     filter->Search(*this);
167dda28197Spatrick     // Now convert the filelist to completions:
168dda28197Spatrick     for (size_t i = 0; i < m_matching_files.GetSize(); i++) {
169dda28197Spatrick       m_request.AddCompletion(
170dda28197Spatrick           m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
171dda28197Spatrick     }
172dda28197Spatrick   }
173dda28197Spatrick 
174dda28197Spatrick private:
175dda28197Spatrick   FileSpecList m_matching_files;
176dda28197Spatrick   const char *m_file_name;
177dda28197Spatrick   const char *m_dir_name;
178dda28197Spatrick 
179dda28197Spatrick   SourceFileCompleter(const SourceFileCompleter &) = delete;
180dda28197Spatrick   const SourceFileCompleter &operator=(const SourceFileCompleter &) = delete;
181dda28197Spatrick };
182dda28197Spatrick } // namespace
183dda28197Spatrick 
regex_chars(const char comp)184dda28197Spatrick static bool regex_chars(const char comp) {
185dda28197Spatrick   return llvm::StringRef("[](){}+.*|^$\\?").contains(comp);
186dda28197Spatrick }
187dda28197Spatrick 
188dda28197Spatrick namespace {
189dda28197Spatrick class SymbolCompleter : public Completer {
190dda28197Spatrick 
191dda28197Spatrick public:
SymbolCompleter(CommandInterpreter & interpreter,CompletionRequest & request)192dda28197Spatrick   SymbolCompleter(CommandInterpreter &interpreter, CompletionRequest &request)
193dda28197Spatrick       : Completer(interpreter, request) {
194dda28197Spatrick     std::string regex_str;
195dda28197Spatrick     if (!m_request.GetCursorArgumentPrefix().empty()) {
196dda28197Spatrick       regex_str.append("^");
197dda28197Spatrick       regex_str.append(std::string(m_request.GetCursorArgumentPrefix()));
198dda28197Spatrick     } else {
199dda28197Spatrick       // Match anything since the completion string is empty
200dda28197Spatrick       regex_str.append(".");
201dda28197Spatrick     }
202dda28197Spatrick     std::string::iterator pos =
203dda28197Spatrick         find_if(regex_str.begin() + 1, regex_str.end(), regex_chars);
204dda28197Spatrick     while (pos < regex_str.end()) {
205dda28197Spatrick       pos = regex_str.insert(pos, '\\');
206dda28197Spatrick       pos = find_if(pos + 2, regex_str.end(), regex_chars);
207dda28197Spatrick     }
208dda28197Spatrick     m_regex = RegularExpression(regex_str);
209dda28197Spatrick   }
210dda28197Spatrick 
GetDepth()211dda28197Spatrick   lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; }
212dda28197Spatrick 
SearchCallback(SearchFilter & filter,SymbolContext & context,Address * addr)213dda28197Spatrick   Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
214dda28197Spatrick                                           SymbolContext &context,
215dda28197Spatrick                                           Address *addr) override {
216dda28197Spatrick     if (context.module_sp) {
217dda28197Spatrick       SymbolContextList sc_list;
218*f6aab3d8Srobert       ModuleFunctionSearchOptions function_options;
219*f6aab3d8Srobert       function_options.include_symbols = true;
220*f6aab3d8Srobert       function_options.include_inlines = true;
221*f6aab3d8Srobert       context.module_sp->FindFunctions(m_regex, function_options, sc_list);
222dda28197Spatrick 
223dda28197Spatrick       SymbolContext sc;
224dda28197Spatrick       // Now add the functions & symbols to the list - only add if unique:
225dda28197Spatrick       for (uint32_t i = 0; i < sc_list.GetSize(); i++) {
226dda28197Spatrick         if (sc_list.GetContextAtIndex(i, sc)) {
227dda28197Spatrick           ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
228dda28197Spatrick           // Ensure that the function name matches the regex. This is more than
229dda28197Spatrick           // a sanity check. It is possible that the demangled function name
230dda28197Spatrick           // does not start with the prefix, for example when it's in an
231dda28197Spatrick           // anonymous namespace.
232dda28197Spatrick           if (!func_name.IsEmpty() && m_regex.Execute(func_name.GetStringRef()))
233dda28197Spatrick             m_match_set.insert(func_name);
234dda28197Spatrick         }
235dda28197Spatrick       }
236dda28197Spatrick     }
237dda28197Spatrick     return Searcher::eCallbackReturnContinue;
238dda28197Spatrick   }
239dda28197Spatrick 
DoCompletion(SearchFilter * filter)240dda28197Spatrick   void DoCompletion(SearchFilter *filter) override {
241dda28197Spatrick     filter->Search(*this);
242dda28197Spatrick     collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
243dda28197Spatrick     for (pos = m_match_set.begin(); pos != end; pos++)
244dda28197Spatrick       m_request.AddCompletion((*pos).GetCString());
245dda28197Spatrick   }
246dda28197Spatrick 
247dda28197Spatrick private:
248dda28197Spatrick   RegularExpression m_regex;
249dda28197Spatrick   typedef std::set<ConstString> collection;
250dda28197Spatrick   collection m_match_set;
251dda28197Spatrick 
252dda28197Spatrick   SymbolCompleter(const SymbolCompleter &) = delete;
253dda28197Spatrick   const SymbolCompleter &operator=(const SymbolCompleter &) = delete;
254dda28197Spatrick };
255dda28197Spatrick } // namespace
256dda28197Spatrick 
257dda28197Spatrick namespace {
258dda28197Spatrick class ModuleCompleter : public Completer {
259dda28197Spatrick public:
ModuleCompleter(CommandInterpreter & interpreter,CompletionRequest & request)260dda28197Spatrick   ModuleCompleter(CommandInterpreter &interpreter, CompletionRequest &request)
261dda28197Spatrick       : Completer(interpreter, request) {
262dda28197Spatrick     FileSpec partial_spec(m_request.GetCursorArgumentPrefix());
263dda28197Spatrick     m_file_name = partial_spec.GetFilename().GetCString();
264dda28197Spatrick     m_dir_name = partial_spec.GetDirectory().GetCString();
265dda28197Spatrick   }
266dda28197Spatrick 
GetDepth()267dda28197Spatrick   lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; }
268dda28197Spatrick 
SearchCallback(SearchFilter & filter,SymbolContext & context,Address * addr)269dda28197Spatrick   Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
270dda28197Spatrick                                           SymbolContext &context,
271dda28197Spatrick                                           Address *addr) override {
272dda28197Spatrick     if (context.module_sp) {
273dda28197Spatrick       const char *cur_file_name =
274dda28197Spatrick           context.module_sp->GetFileSpec().GetFilename().GetCString();
275dda28197Spatrick       const char *cur_dir_name =
276dda28197Spatrick           context.module_sp->GetFileSpec().GetDirectory().GetCString();
277dda28197Spatrick 
278dda28197Spatrick       bool match = false;
279dda28197Spatrick       if (m_file_name && cur_file_name &&
280dda28197Spatrick           strstr(cur_file_name, m_file_name) == cur_file_name)
281dda28197Spatrick         match = true;
282dda28197Spatrick 
283dda28197Spatrick       if (match && m_dir_name && cur_dir_name &&
284dda28197Spatrick           strstr(cur_dir_name, m_dir_name) != cur_dir_name)
285dda28197Spatrick         match = false;
286dda28197Spatrick 
287dda28197Spatrick       if (match) {
288dda28197Spatrick         m_request.AddCompletion(cur_file_name);
289dda28197Spatrick       }
290dda28197Spatrick     }
291dda28197Spatrick     return Searcher::eCallbackReturnContinue;
292dda28197Spatrick   }
293dda28197Spatrick 
DoCompletion(SearchFilter * filter)294dda28197Spatrick   void DoCompletion(SearchFilter *filter) override { filter->Search(*this); }
295dda28197Spatrick 
296dda28197Spatrick private:
297dda28197Spatrick   const char *m_file_name;
298dda28197Spatrick   const char *m_dir_name;
299dda28197Spatrick 
300dda28197Spatrick   ModuleCompleter(const ModuleCompleter &) = delete;
301dda28197Spatrick   const ModuleCompleter &operator=(const ModuleCompleter &) = delete;
302dda28197Spatrick };
303dda28197Spatrick } // namespace
304dda28197Spatrick 
SourceFiles(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)305061da546Spatrick void CommandCompletions::SourceFiles(CommandInterpreter &interpreter,
306061da546Spatrick                                      CompletionRequest &request,
307061da546Spatrick                                      SearchFilter *searcher) {
308dda28197Spatrick   SourceFileCompleter completer(interpreter, request);
309061da546Spatrick 
310061da546Spatrick   if (searcher == nullptr) {
311061da546Spatrick     lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
312061da546Spatrick     SearchFilterForUnconstrainedSearches null_searcher(target_sp);
313061da546Spatrick     completer.DoCompletion(&null_searcher);
314061da546Spatrick   } else {
315061da546Spatrick     completer.DoCompletion(searcher);
316061da546Spatrick   }
317061da546Spatrick }
318061da546Spatrick 
DiskFilesOrDirectories(const llvm::Twine & partial_name,bool only_directories,CompletionRequest & request,TildeExpressionResolver & Resolver)319061da546Spatrick static void DiskFilesOrDirectories(const llvm::Twine &partial_name,
320061da546Spatrick                                    bool only_directories,
321061da546Spatrick                                    CompletionRequest &request,
322061da546Spatrick                                    TildeExpressionResolver &Resolver) {
323061da546Spatrick   llvm::SmallString<256> CompletionBuffer;
324061da546Spatrick   llvm::SmallString<256> Storage;
325061da546Spatrick   partial_name.toVector(CompletionBuffer);
326061da546Spatrick 
327061da546Spatrick   if (CompletionBuffer.size() >= PATH_MAX)
328061da546Spatrick     return;
329061da546Spatrick 
330061da546Spatrick   namespace path = llvm::sys::path;
331061da546Spatrick 
332061da546Spatrick   llvm::StringRef SearchDir;
333061da546Spatrick   llvm::StringRef PartialItem;
334061da546Spatrick 
335061da546Spatrick   if (CompletionBuffer.startswith("~")) {
336be691f3bSpatrick     llvm::StringRef Buffer = CompletionBuffer;
337061da546Spatrick     size_t FirstSep =
338061da546Spatrick         Buffer.find_if([](char c) { return path::is_separator(c); });
339061da546Spatrick 
340061da546Spatrick     llvm::StringRef Username = Buffer.take_front(FirstSep);
341061da546Spatrick     llvm::StringRef Remainder;
342061da546Spatrick     if (FirstSep != llvm::StringRef::npos)
343061da546Spatrick       Remainder = Buffer.drop_front(FirstSep + 1);
344061da546Spatrick 
345061da546Spatrick     llvm::SmallString<256> Resolved;
346061da546Spatrick     if (!Resolver.ResolveExact(Username, Resolved)) {
347061da546Spatrick       // We couldn't resolve it as a full username.  If there were no slashes
348061da546Spatrick       // then this might be a partial username.   We try to resolve it as such
349061da546Spatrick       // but after that, we're done regardless of any matches.
350061da546Spatrick       if (FirstSep == llvm::StringRef::npos) {
351061da546Spatrick         llvm::StringSet<> MatchSet;
352061da546Spatrick         Resolver.ResolvePartial(Username, MatchSet);
353061da546Spatrick         for (const auto &S : MatchSet) {
354061da546Spatrick           Resolved = S.getKey();
355061da546Spatrick           path::append(Resolved, path::get_separator());
356061da546Spatrick           request.AddCompletion(Resolved, "", CompletionMode::Partial);
357061da546Spatrick         }
358061da546Spatrick       }
359061da546Spatrick       return;
360061da546Spatrick     }
361061da546Spatrick 
362061da546Spatrick     // If there was no trailing slash, then we're done as soon as we resolve
363061da546Spatrick     // the expression to the correct directory.  Otherwise we need to continue
364061da546Spatrick     // looking for matches within that directory.
365061da546Spatrick     if (FirstSep == llvm::StringRef::npos) {
366061da546Spatrick       // Make sure it ends with a separator.
367061da546Spatrick       path::append(CompletionBuffer, path::get_separator());
368061da546Spatrick       request.AddCompletion(CompletionBuffer, "", CompletionMode::Partial);
369061da546Spatrick       return;
370061da546Spatrick     }
371061da546Spatrick 
372061da546Spatrick     // We want to keep the form the user typed, so we special case this to
373061da546Spatrick     // search in the fully resolved directory, but CompletionBuffer keeps the
374061da546Spatrick     // unmodified form that the user typed.
375061da546Spatrick     Storage = Resolved;
376061da546Spatrick     llvm::StringRef RemainderDir = path::parent_path(Remainder);
377061da546Spatrick     if (!RemainderDir.empty()) {
378061da546Spatrick       // Append the remaining path to the resolved directory.
379061da546Spatrick       Storage.append(path::get_separator());
380061da546Spatrick       Storage.append(RemainderDir);
381061da546Spatrick     }
382061da546Spatrick     SearchDir = Storage;
383061da546Spatrick   } else {
384061da546Spatrick     SearchDir = path::parent_path(CompletionBuffer);
385061da546Spatrick   }
386061da546Spatrick 
387061da546Spatrick   size_t FullPrefixLen = CompletionBuffer.size();
388061da546Spatrick 
389061da546Spatrick   PartialItem = path::filename(CompletionBuffer);
390061da546Spatrick 
391061da546Spatrick   // path::filename() will return "." when the passed path ends with a
392061da546Spatrick   // directory separator. We have to filter those out, but only when the
393061da546Spatrick   // "." doesn't come from the completion request itself.
394061da546Spatrick   if (PartialItem == "." && path::is_separator(CompletionBuffer.back()))
395061da546Spatrick     PartialItem = llvm::StringRef();
396061da546Spatrick 
397061da546Spatrick   if (SearchDir.empty()) {
398061da546Spatrick     llvm::sys::fs::current_path(Storage);
399061da546Spatrick     SearchDir = Storage;
400061da546Spatrick   }
401061da546Spatrick   assert(!PartialItem.contains(path::get_separator()));
402061da546Spatrick 
403061da546Spatrick   // SearchDir now contains the directory to search in, and Prefix contains the
404061da546Spatrick   // text we want to match against items in that directory.
405061da546Spatrick 
406061da546Spatrick   FileSystem &fs = FileSystem::Instance();
407061da546Spatrick   std::error_code EC;
408061da546Spatrick   llvm::vfs::directory_iterator Iter = fs.DirBegin(SearchDir, EC);
409061da546Spatrick   llvm::vfs::directory_iterator End;
410061da546Spatrick   for (; Iter != End && !EC; Iter.increment(EC)) {
411061da546Spatrick     auto &Entry = *Iter;
412061da546Spatrick     llvm::ErrorOr<llvm::vfs::Status> Status = fs.GetStatus(Entry.path());
413061da546Spatrick 
414061da546Spatrick     if (!Status)
415061da546Spatrick       continue;
416061da546Spatrick 
417061da546Spatrick     auto Name = path::filename(Entry.path());
418061da546Spatrick 
419061da546Spatrick     // Omit ".", ".."
420061da546Spatrick     if (Name == "." || Name == ".." || !Name.startswith(PartialItem))
421061da546Spatrick       continue;
422061da546Spatrick 
423061da546Spatrick     bool is_dir = Status->isDirectory();
424061da546Spatrick 
425061da546Spatrick     // If it's a symlink, then we treat it as a directory as long as the target
426061da546Spatrick     // is a directory.
427061da546Spatrick     if (Status->isSymlink()) {
428061da546Spatrick       FileSpec symlink_filespec(Entry.path());
429061da546Spatrick       FileSpec resolved_filespec;
430061da546Spatrick       auto error = fs.ResolveSymbolicLink(symlink_filespec, resolved_filespec);
431061da546Spatrick       if (error.Success())
432061da546Spatrick         is_dir = fs.IsDirectory(symlink_filespec);
433061da546Spatrick     }
434061da546Spatrick 
435061da546Spatrick     if (only_directories && !is_dir)
436061da546Spatrick       continue;
437061da546Spatrick 
438061da546Spatrick     // Shrink it back down so that it just has the original prefix the user
439061da546Spatrick     // typed and remove the part of the name which is common to the located
440061da546Spatrick     // item and what the user typed.
441061da546Spatrick     CompletionBuffer.resize(FullPrefixLen);
442061da546Spatrick     Name = Name.drop_front(PartialItem.size());
443061da546Spatrick     CompletionBuffer.append(Name);
444061da546Spatrick 
445061da546Spatrick     if (is_dir) {
446061da546Spatrick       path::append(CompletionBuffer, path::get_separator());
447061da546Spatrick     }
448061da546Spatrick 
449061da546Spatrick     CompletionMode mode =
450061da546Spatrick         is_dir ? CompletionMode::Partial : CompletionMode::Normal;
451061da546Spatrick     request.AddCompletion(CompletionBuffer, "", mode);
452061da546Spatrick   }
453061da546Spatrick }
454061da546Spatrick 
DiskFilesOrDirectories(const llvm::Twine & partial_name,bool only_directories,StringList & matches,TildeExpressionResolver & Resolver)455061da546Spatrick static void DiskFilesOrDirectories(const llvm::Twine &partial_name,
456061da546Spatrick                                    bool only_directories, StringList &matches,
457061da546Spatrick                                    TildeExpressionResolver &Resolver) {
458061da546Spatrick   CompletionResult result;
459061da546Spatrick   std::string partial_name_str = partial_name.str();
460061da546Spatrick   CompletionRequest request(partial_name_str, partial_name_str.size(), result);
461061da546Spatrick   DiskFilesOrDirectories(partial_name, only_directories, request, Resolver);
462061da546Spatrick   result.GetMatches(matches);
463061da546Spatrick }
464061da546Spatrick 
DiskFilesOrDirectories(CompletionRequest & request,bool only_directories)465061da546Spatrick static void DiskFilesOrDirectories(CompletionRequest &request,
466061da546Spatrick                                    bool only_directories) {
467061da546Spatrick   StandardTildeExpressionResolver resolver;
468061da546Spatrick   DiskFilesOrDirectories(request.GetCursorArgumentPrefix(), only_directories,
469061da546Spatrick                          request, resolver);
470061da546Spatrick }
471061da546Spatrick 
DiskFiles(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)472061da546Spatrick void CommandCompletions::DiskFiles(CommandInterpreter &interpreter,
473061da546Spatrick                                    CompletionRequest &request,
474061da546Spatrick                                    SearchFilter *searcher) {
475061da546Spatrick   DiskFilesOrDirectories(request, /*only_dirs*/ false);
476061da546Spatrick }
477061da546Spatrick 
DiskFiles(const llvm::Twine & partial_file_name,StringList & matches,TildeExpressionResolver & Resolver)478061da546Spatrick void CommandCompletions::DiskFiles(const llvm::Twine &partial_file_name,
479061da546Spatrick                                    StringList &matches,
480061da546Spatrick                                    TildeExpressionResolver &Resolver) {
481061da546Spatrick   DiskFilesOrDirectories(partial_file_name, false, matches, Resolver);
482061da546Spatrick }
483061da546Spatrick 
DiskDirectories(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)484061da546Spatrick void CommandCompletions::DiskDirectories(CommandInterpreter &interpreter,
485061da546Spatrick                                          CompletionRequest &request,
486061da546Spatrick                                          SearchFilter *searcher) {
487061da546Spatrick   DiskFilesOrDirectories(request, /*only_dirs*/ true);
488061da546Spatrick }
489061da546Spatrick 
DiskDirectories(const llvm::Twine & partial_file_name,StringList & matches,TildeExpressionResolver & Resolver)490061da546Spatrick void CommandCompletions::DiskDirectories(const llvm::Twine &partial_file_name,
491061da546Spatrick                                          StringList &matches,
492061da546Spatrick                                          TildeExpressionResolver &Resolver) {
493061da546Spatrick   DiskFilesOrDirectories(partial_file_name, true, matches, Resolver);
494061da546Spatrick }
495061da546Spatrick 
RemoteDiskFiles(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)496be691f3bSpatrick void CommandCompletions::RemoteDiskFiles(CommandInterpreter &interpreter,
497be691f3bSpatrick                                          CompletionRequest &request,
498be691f3bSpatrick                                          SearchFilter *searcher) {
499be691f3bSpatrick   lldb::PlatformSP platform_sp =
500be691f3bSpatrick       interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
501be691f3bSpatrick   if (platform_sp)
502be691f3bSpatrick     platform_sp->AutoCompleteDiskFileOrDirectory(request, false);
503be691f3bSpatrick }
504be691f3bSpatrick 
RemoteDiskDirectories(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)505be691f3bSpatrick void CommandCompletions::RemoteDiskDirectories(CommandInterpreter &interpreter,
506be691f3bSpatrick                                                CompletionRequest &request,
507be691f3bSpatrick                                                SearchFilter *searcher) {
508be691f3bSpatrick   lldb::PlatformSP platform_sp =
509be691f3bSpatrick       interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
510be691f3bSpatrick   if (platform_sp)
511be691f3bSpatrick     platform_sp->AutoCompleteDiskFileOrDirectory(request, true);
512be691f3bSpatrick }
513be691f3bSpatrick 
Modules(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)514061da546Spatrick void CommandCompletions::Modules(CommandInterpreter &interpreter,
515061da546Spatrick                                  CompletionRequest &request,
516061da546Spatrick                                  SearchFilter *searcher) {
517061da546Spatrick   ModuleCompleter completer(interpreter, request);
518061da546Spatrick 
519061da546Spatrick   if (searcher == nullptr) {
520061da546Spatrick     lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
521061da546Spatrick     SearchFilterForUnconstrainedSearches null_searcher(target_sp);
522061da546Spatrick     completer.DoCompletion(&null_searcher);
523061da546Spatrick   } else {
524061da546Spatrick     completer.DoCompletion(searcher);
525061da546Spatrick   }
526061da546Spatrick }
527061da546Spatrick 
ModuleUUIDs(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)528be691f3bSpatrick void CommandCompletions::ModuleUUIDs(CommandInterpreter &interpreter,
529be691f3bSpatrick                                      CompletionRequest &request,
530be691f3bSpatrick                                      SearchFilter *searcher) {
531be691f3bSpatrick   const ExecutionContext &exe_ctx = interpreter.GetExecutionContext();
532be691f3bSpatrick   if (!exe_ctx.HasTargetScope())
533be691f3bSpatrick     return;
534be691f3bSpatrick 
535be691f3bSpatrick   exe_ctx.GetTargetPtr()->GetImages().ForEach(
536be691f3bSpatrick       [&request](const lldb::ModuleSP &module) {
537be691f3bSpatrick         StreamString strm;
538be691f3bSpatrick         module->GetDescription(strm.AsRawOstream(),
539be691f3bSpatrick                                lldb::eDescriptionLevelInitial);
540be691f3bSpatrick         request.TryCompleteCurrentArg(module->GetUUID().GetAsString(),
541be691f3bSpatrick                                       strm.GetString());
542be691f3bSpatrick         return true;
543be691f3bSpatrick       });
544be691f3bSpatrick }
545be691f3bSpatrick 
Symbols(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)546061da546Spatrick void CommandCompletions::Symbols(CommandInterpreter &interpreter,
547061da546Spatrick                                  CompletionRequest &request,
548061da546Spatrick                                  SearchFilter *searcher) {
549061da546Spatrick   SymbolCompleter completer(interpreter, request);
550061da546Spatrick 
551061da546Spatrick   if (searcher == nullptr) {
552061da546Spatrick     lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
553061da546Spatrick     SearchFilterForUnconstrainedSearches null_searcher(target_sp);
554061da546Spatrick     completer.DoCompletion(&null_searcher);
555061da546Spatrick   } else {
556061da546Spatrick     completer.DoCompletion(searcher);
557061da546Spatrick   }
558061da546Spatrick }
559061da546Spatrick 
SettingsNames(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)560061da546Spatrick void CommandCompletions::SettingsNames(CommandInterpreter &interpreter,
561061da546Spatrick                                        CompletionRequest &request,
562061da546Spatrick                                        SearchFilter *searcher) {
563061da546Spatrick   // Cache the full setting name list
564061da546Spatrick   static StringList g_property_names;
565061da546Spatrick   if (g_property_names.GetSize() == 0) {
566061da546Spatrick     // Generate the full setting name list on demand
567061da546Spatrick     lldb::OptionValuePropertiesSP properties_sp(
568061da546Spatrick         interpreter.GetDebugger().GetValueProperties());
569061da546Spatrick     if (properties_sp) {
570061da546Spatrick       StreamString strm;
571061da546Spatrick       properties_sp->DumpValue(nullptr, strm, OptionValue::eDumpOptionName);
572dda28197Spatrick       const std::string &str = std::string(strm.GetString());
573061da546Spatrick       g_property_names.SplitIntoLines(str.c_str(), str.size());
574061da546Spatrick     }
575061da546Spatrick   }
576061da546Spatrick 
577061da546Spatrick   for (const std::string &s : g_property_names)
578061da546Spatrick     request.TryCompleteCurrentArg(s);
579061da546Spatrick }
580061da546Spatrick 
PlatformPluginNames(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)581061da546Spatrick void CommandCompletions::PlatformPluginNames(CommandInterpreter &interpreter,
582061da546Spatrick                                              CompletionRequest &request,
583061da546Spatrick                                              SearchFilter *searcher) {
584061da546Spatrick   PluginManager::AutoCompletePlatformName(request.GetCursorArgumentPrefix(),
585061da546Spatrick                                           request);
586061da546Spatrick }
587061da546Spatrick 
ArchitectureNames(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)588061da546Spatrick void CommandCompletions::ArchitectureNames(CommandInterpreter &interpreter,
589061da546Spatrick                                            CompletionRequest &request,
590061da546Spatrick                                            SearchFilter *searcher) {
591061da546Spatrick   ArchSpec::AutoComplete(request);
592061da546Spatrick }
593061da546Spatrick 
VariablePath(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)594061da546Spatrick void CommandCompletions::VariablePath(CommandInterpreter &interpreter,
595061da546Spatrick                                       CompletionRequest &request,
596061da546Spatrick                                       SearchFilter *searcher) {
597061da546Spatrick   Variable::AutoComplete(interpreter.GetExecutionContext(), request);
598061da546Spatrick }
599061da546Spatrick 
Registers(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)600dda28197Spatrick void CommandCompletions::Registers(CommandInterpreter &interpreter,
601dda28197Spatrick                                    CompletionRequest &request,
602dda28197Spatrick                                    SearchFilter *searcher) {
603*f6aab3d8Srobert   std::string reg_prefix;
604dda28197Spatrick   if (request.GetCursorArgumentPrefix().startswith("$"))
605dda28197Spatrick     reg_prefix = "$";
606061da546Spatrick 
607dda28197Spatrick   RegisterContext *reg_ctx =
608dda28197Spatrick       interpreter.GetExecutionContext().GetRegisterContext();
609dda28197Spatrick   const size_t reg_num = reg_ctx->GetRegisterCount();
610dda28197Spatrick   for (size_t reg_idx = 0; reg_idx < reg_num; ++reg_idx) {
611dda28197Spatrick     const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_idx);
612dda28197Spatrick     request.TryCompleteCurrentArg(reg_prefix + reg_info->name,
613dda28197Spatrick                                   reg_info->alt_name);
614061da546Spatrick   }
615061da546Spatrick }
616061da546Spatrick 
Breakpoints(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)617dda28197Spatrick void CommandCompletions::Breakpoints(CommandInterpreter &interpreter,
618dda28197Spatrick                                      CompletionRequest &request,
619dda28197Spatrick                                      SearchFilter *searcher) {
620dda28197Spatrick   lldb::TargetSP target = interpreter.GetDebugger().GetSelectedTarget();
621dda28197Spatrick   if (!target)
622dda28197Spatrick     return;
623061da546Spatrick 
624dda28197Spatrick   const BreakpointList &breakpoints = target->GetBreakpointList();
625dda28197Spatrick 
626dda28197Spatrick   std::unique_lock<std::recursive_mutex> lock;
627dda28197Spatrick   target->GetBreakpointList().GetListMutex(lock);
628dda28197Spatrick 
629dda28197Spatrick   size_t num_breakpoints = breakpoints.GetSize();
630dda28197Spatrick   if (num_breakpoints == 0)
631dda28197Spatrick     return;
632dda28197Spatrick 
633dda28197Spatrick   for (size_t i = 0; i < num_breakpoints; ++i) {
634dda28197Spatrick     lldb::BreakpointSP bp = breakpoints.GetBreakpointAtIndex(i);
635dda28197Spatrick 
636dda28197Spatrick     StreamString s;
637dda28197Spatrick     bp->GetDescription(&s, lldb::eDescriptionLevelBrief);
638dda28197Spatrick     llvm::StringRef bp_info = s.GetString();
639dda28197Spatrick 
640dda28197Spatrick     const size_t colon_pos = bp_info.find_first_of(':');
641dda28197Spatrick     if (colon_pos != llvm::StringRef::npos)
642dda28197Spatrick       bp_info = bp_info.drop_front(colon_pos + 2);
643dda28197Spatrick 
644dda28197Spatrick     request.TryCompleteCurrentArg(std::to_string(bp->GetID()), bp_info);
645dda28197Spatrick   }
646061da546Spatrick }
647061da546Spatrick 
BreakpointNames(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)648be691f3bSpatrick void CommandCompletions::BreakpointNames(CommandInterpreter &interpreter,
649be691f3bSpatrick                                          CompletionRequest &request,
650be691f3bSpatrick                                          SearchFilter *searcher) {
651be691f3bSpatrick   lldb::TargetSP target = interpreter.GetDebugger().GetSelectedTarget();
652be691f3bSpatrick   if (!target)
653be691f3bSpatrick     return;
654be691f3bSpatrick 
655be691f3bSpatrick   std::vector<std::string> name_list;
656be691f3bSpatrick   target->GetBreakpointNames(name_list);
657be691f3bSpatrick 
658be691f3bSpatrick   for (const std::string &name : name_list)
659be691f3bSpatrick     request.TryCompleteCurrentArg(name);
660be691f3bSpatrick }
661be691f3bSpatrick 
ProcessPluginNames(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)662dda28197Spatrick void CommandCompletions::ProcessPluginNames(CommandInterpreter &interpreter,
663dda28197Spatrick                                             CompletionRequest &request,
664dda28197Spatrick                                             SearchFilter *searcher) {
665dda28197Spatrick   PluginManager::AutoCompleteProcessName(request.GetCursorArgumentPrefix(),
666dda28197Spatrick                                          request);
667061da546Spatrick }
DisassemblyFlavors(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)668be691f3bSpatrick void CommandCompletions::DisassemblyFlavors(CommandInterpreter &interpreter,
669be691f3bSpatrick                                             CompletionRequest &request,
670be691f3bSpatrick                                             SearchFilter *searcher) {
671be691f3bSpatrick   // Currently the only valid options for disassemble -F are default, and for
672be691f3bSpatrick   // Intel architectures, att and intel.
673be691f3bSpatrick   static const char *flavors[] = {"default", "att", "intel"};
674be691f3bSpatrick   for (const char *flavor : flavors) {
675be691f3bSpatrick     request.TryCompleteCurrentArg(flavor);
676be691f3bSpatrick   }
677be691f3bSpatrick }
678be691f3bSpatrick 
ProcessIDs(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)679be691f3bSpatrick void CommandCompletions::ProcessIDs(CommandInterpreter &interpreter,
680be691f3bSpatrick                                     CompletionRequest &request,
681be691f3bSpatrick                                     SearchFilter *searcher) {
682be691f3bSpatrick   lldb::PlatformSP platform_sp(interpreter.GetPlatform(true));
683be691f3bSpatrick   if (!platform_sp)
684be691f3bSpatrick     return;
685be691f3bSpatrick   ProcessInstanceInfoList process_infos;
686be691f3bSpatrick   ProcessInstanceInfoMatch match_info;
687be691f3bSpatrick   platform_sp->FindProcesses(match_info, process_infos);
688be691f3bSpatrick   for (const ProcessInstanceInfo &info : process_infos)
689be691f3bSpatrick     request.TryCompleteCurrentArg(std::to_string(info.GetProcessID()),
690be691f3bSpatrick                                   info.GetNameAsStringRef());
691be691f3bSpatrick }
692be691f3bSpatrick 
ProcessNames(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)693be691f3bSpatrick void CommandCompletions::ProcessNames(CommandInterpreter &interpreter,
694be691f3bSpatrick                                       CompletionRequest &request,
695be691f3bSpatrick                                       SearchFilter *searcher) {
696be691f3bSpatrick   lldb::PlatformSP platform_sp(interpreter.GetPlatform(true));
697be691f3bSpatrick   if (!platform_sp)
698be691f3bSpatrick     return;
699be691f3bSpatrick   ProcessInstanceInfoList process_infos;
700be691f3bSpatrick   ProcessInstanceInfoMatch match_info;
701be691f3bSpatrick   platform_sp->FindProcesses(match_info, process_infos);
702be691f3bSpatrick   for (const ProcessInstanceInfo &info : process_infos)
703be691f3bSpatrick     request.TryCompleteCurrentArg(info.GetNameAsStringRef());
704be691f3bSpatrick }
705be691f3bSpatrick 
TypeLanguages(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)706be691f3bSpatrick void CommandCompletions::TypeLanguages(CommandInterpreter &interpreter,
707be691f3bSpatrick                                        CompletionRequest &request,
708be691f3bSpatrick                                        SearchFilter *searcher) {
709be691f3bSpatrick   for (int bit :
710be691f3bSpatrick        Language::GetLanguagesSupportingTypeSystems().bitvector.set_bits()) {
711be691f3bSpatrick     request.TryCompleteCurrentArg(
712be691f3bSpatrick         Language::GetNameForLanguageType(static_cast<lldb::LanguageType>(bit)));
713be691f3bSpatrick   }
714be691f3bSpatrick }
715be691f3bSpatrick 
FrameIndexes(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)716be691f3bSpatrick void CommandCompletions::FrameIndexes(CommandInterpreter &interpreter,
717be691f3bSpatrick                                       CompletionRequest &request,
718be691f3bSpatrick                                       SearchFilter *searcher) {
719be691f3bSpatrick   const ExecutionContext &exe_ctx = interpreter.GetExecutionContext();
720be691f3bSpatrick   if (!exe_ctx.HasProcessScope())
721be691f3bSpatrick     return;
722be691f3bSpatrick 
723be691f3bSpatrick   lldb::ThreadSP thread_sp = exe_ctx.GetThreadSP();
724be691f3bSpatrick   const uint32_t frame_num = thread_sp->GetStackFrameCount();
725be691f3bSpatrick   for (uint32_t i = 0; i < frame_num; ++i) {
726be691f3bSpatrick     lldb::StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(i);
727be691f3bSpatrick     StreamString strm;
728be691f3bSpatrick     frame_sp->Dump(&strm, false, true);
729be691f3bSpatrick     request.TryCompleteCurrentArg(std::to_string(i), strm.GetString());
730be691f3bSpatrick   }
731be691f3bSpatrick }
732be691f3bSpatrick 
StopHookIDs(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)733be691f3bSpatrick void CommandCompletions::StopHookIDs(CommandInterpreter &interpreter,
734be691f3bSpatrick                                      CompletionRequest &request,
735be691f3bSpatrick                                      SearchFilter *searcher) {
736be691f3bSpatrick   const lldb::TargetSP target_sp =
737be691f3bSpatrick       interpreter.GetExecutionContext().GetTargetSP();
738be691f3bSpatrick   if (!target_sp)
739be691f3bSpatrick     return;
740be691f3bSpatrick 
741be691f3bSpatrick   const size_t num = target_sp->GetNumStopHooks();
742be691f3bSpatrick   for (size_t idx = 0; idx < num; ++idx) {
743be691f3bSpatrick     StreamString strm;
744be691f3bSpatrick     // The value 11 is an offset to make the completion description looks
745be691f3bSpatrick     // neater.
746be691f3bSpatrick     strm.SetIndentLevel(11);
747be691f3bSpatrick     const Target::StopHookSP stophook_sp = target_sp->GetStopHookAtIndex(idx);
748be691f3bSpatrick     stophook_sp->GetDescription(&strm, lldb::eDescriptionLevelInitial);
749be691f3bSpatrick     request.TryCompleteCurrentArg(std::to_string(stophook_sp->GetID()),
750be691f3bSpatrick                                   strm.GetString());
751be691f3bSpatrick   }
752be691f3bSpatrick }
753be691f3bSpatrick 
ThreadIndexes(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)754be691f3bSpatrick void CommandCompletions::ThreadIndexes(CommandInterpreter &interpreter,
755be691f3bSpatrick                                        CompletionRequest &request,
756be691f3bSpatrick                                        SearchFilter *searcher) {
757be691f3bSpatrick   const ExecutionContext &exe_ctx = interpreter.GetExecutionContext();
758be691f3bSpatrick   if (!exe_ctx.HasProcessScope())
759be691f3bSpatrick     return;
760be691f3bSpatrick 
761be691f3bSpatrick   ThreadList &threads = exe_ctx.GetProcessPtr()->GetThreadList();
762be691f3bSpatrick   lldb::ThreadSP thread_sp;
763be691f3bSpatrick   for (uint32_t idx = 0; (thread_sp = threads.GetThreadAtIndex(idx)); ++idx) {
764be691f3bSpatrick     StreamString strm;
765be691f3bSpatrick     thread_sp->GetStatus(strm, 0, 1, 1, true);
766be691f3bSpatrick     request.TryCompleteCurrentArg(std::to_string(thread_sp->GetIndexID()),
767be691f3bSpatrick                                   strm.GetString());
768be691f3bSpatrick   }
769be691f3bSpatrick }
770be691f3bSpatrick 
WatchPointIDs(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)771be691f3bSpatrick void CommandCompletions::WatchPointIDs(CommandInterpreter &interpreter,
772be691f3bSpatrick                                        CompletionRequest &request,
773be691f3bSpatrick                                        SearchFilter *searcher) {
774be691f3bSpatrick   const ExecutionContext &exe_ctx = interpreter.GetExecutionContext();
775be691f3bSpatrick   if (!exe_ctx.HasTargetScope())
776be691f3bSpatrick     return;
777be691f3bSpatrick 
778be691f3bSpatrick   const WatchpointList &wp_list = exe_ctx.GetTargetPtr()->GetWatchpointList();
779be691f3bSpatrick   for (lldb::WatchpointSP wp_sp : wp_list.Watchpoints()) {
780be691f3bSpatrick     StreamString strm;
781be691f3bSpatrick     wp_sp->Dump(&strm);
782be691f3bSpatrick     request.TryCompleteCurrentArg(std::to_string(wp_sp->GetID()),
783be691f3bSpatrick                                   strm.GetString());
784be691f3bSpatrick   }
785be691f3bSpatrick }
786be691f3bSpatrick 
TypeCategoryNames(CommandInterpreter & interpreter,CompletionRequest & request,SearchFilter * searcher)787be691f3bSpatrick void CommandCompletions::TypeCategoryNames(CommandInterpreter &interpreter,
788be691f3bSpatrick                                            CompletionRequest &request,
789be691f3bSpatrick                                            SearchFilter *searcher) {
790be691f3bSpatrick   DataVisualization::Categories::ForEach(
791be691f3bSpatrick       [&request](const lldb::TypeCategoryImplSP &category_sp) {
792be691f3bSpatrick         request.TryCompleteCurrentArg(category_sp->GetName(),
793be691f3bSpatrick                                       category_sp->GetDescription());
794be691f3bSpatrick         return true;
795be691f3bSpatrick       });
796be691f3bSpatrick }
797*f6aab3d8Srobert 
CompleteModifiableCmdPathArgs(CommandInterpreter & interpreter,CompletionRequest & request,OptionElementVector & opt_element_vector)798*f6aab3d8Srobert void CommandCompletions::CompleteModifiableCmdPathArgs(
799*f6aab3d8Srobert     CommandInterpreter &interpreter, CompletionRequest &request,
800*f6aab3d8Srobert     OptionElementVector &opt_element_vector) {
801*f6aab3d8Srobert   // The only arguments constitute a command path, however, there might be
802*f6aab3d8Srobert   // options interspersed among the arguments, and we need to skip those.  Do that
803*f6aab3d8Srobert   // by copying the args vector, and just dropping all the option bits:
804*f6aab3d8Srobert   Args args = request.GetParsedLine();
805*f6aab3d8Srobert   std::vector<size_t> to_delete;
806*f6aab3d8Srobert   for (auto &elem : opt_element_vector) {
807*f6aab3d8Srobert     to_delete.push_back(elem.opt_pos);
808*f6aab3d8Srobert     if (elem.opt_arg_pos != 0)
809*f6aab3d8Srobert       to_delete.push_back(elem.opt_arg_pos);
810*f6aab3d8Srobert   }
811*f6aab3d8Srobert   sort(to_delete.begin(), to_delete.end(), std::greater<size_t>());
812*f6aab3d8Srobert   for (size_t idx : to_delete)
813*f6aab3d8Srobert     args.DeleteArgumentAtIndex(idx);
814*f6aab3d8Srobert 
815*f6aab3d8Srobert   // At this point, we should only have args, so now lookup the command up to
816*f6aab3d8Srobert   // the cursor element.
817*f6aab3d8Srobert 
818*f6aab3d8Srobert   // There's nothing here but options.  It doesn't seem very useful here to
819*f6aab3d8Srobert   // dump all the commands, so just return.
820*f6aab3d8Srobert   size_t num_args = args.GetArgumentCount();
821*f6aab3d8Srobert   if (num_args == 0)
822*f6aab3d8Srobert     return;
823*f6aab3d8Srobert 
824*f6aab3d8Srobert   // There's just one argument, so we should complete its name:
825*f6aab3d8Srobert   StringList matches;
826*f6aab3d8Srobert   if (num_args == 1) {
827*f6aab3d8Srobert     interpreter.GetUserCommandObject(args.GetArgumentAtIndex(0), &matches,
828*f6aab3d8Srobert                                      nullptr);
829*f6aab3d8Srobert     request.AddCompletions(matches);
830*f6aab3d8Srobert     return;
831*f6aab3d8Srobert   }
832*f6aab3d8Srobert 
833*f6aab3d8Srobert   // There was more than one path element, lets find the containing command:
834*f6aab3d8Srobert   Status error;
835*f6aab3d8Srobert   CommandObjectMultiword *mwc =
836*f6aab3d8Srobert       interpreter.VerifyUserMultiwordCmdPath(args, true, error);
837*f6aab3d8Srobert 
838*f6aab3d8Srobert   // Something was wrong somewhere along the path, but I don't think there's
839*f6aab3d8Srobert   // a good way to go back and fill in the missing elements:
840*f6aab3d8Srobert   if (error.Fail())
841*f6aab3d8Srobert     return;
842*f6aab3d8Srobert 
843*f6aab3d8Srobert   // This should never happen.  We already handled the case of one argument
844*f6aab3d8Srobert   // above, and we can only get Success & nullptr back if there's a one-word
845*f6aab3d8Srobert   // leaf.
846*f6aab3d8Srobert   assert(mwc != nullptr);
847*f6aab3d8Srobert 
848*f6aab3d8Srobert   mwc->GetSubcommandObject(args.GetArgumentAtIndex(num_args - 1), &matches);
849*f6aab3d8Srobert   if (matches.GetSize() == 0)
850*f6aab3d8Srobert     return;
851*f6aab3d8Srobert 
852*f6aab3d8Srobert   request.AddCompletions(matches);
853*f6aab3d8Srobert }
854