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