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