blob: bdfdbb83219bd8cf1f3cfa18dbb5fc31d106a980 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- CommandCompletions.cpp ----------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Chris Lattner30fdc8d2010-06-08 16:52:24 +000010// C Includes
Jim Ingham558ce122010-06-30 05:02:46 +000011#include <sys/stat.h>
Greg Claytonfd184262011-02-05 02:27:52 +000012#if defined(__APPLE__) || defined(__linux__)
Jim Ingham7cc478b2010-07-02 00:45:55 +000013#include <pwd.h>
Greg Claytonfd184262011-02-05 02:27:52 +000014#endif
Jim Ingham558ce122010-06-30 05:02:46 +000015
Chris Lattner30fdc8d2010-06-08 16:52:24 +000016// C++ Includes
17// Other libraries and framework includes
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +000018#include "llvm/ADT/SmallString.h"
Zachary Turner2cc5a182017-03-13 00:41:01 +000019#include "llvm/ADT/StringSet.h"
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +000020
Chris Lattner30fdc8d2010-06-08 16:52:24 +000021// Project includes
Greg Clayton9b62fd22011-02-01 05:15:22 +000022#include "lldb/Core/FileSpecList.h"
Greg Clayton1f746072012-08-29 21:13:06 +000023#include "lldb/Core/Module.h"
Zachary Turner190fadc2016-03-22 17:58:09 +000024#include "lldb/Core/PluginManager.h"
Zachary Turner190fadc2016-03-22 17:58:09 +000025#include "lldb/Host/FileSystem.h"
Greg Clayton9b62fd22011-02-01 05:15:22 +000026#include "lldb/Interpreter/CommandCompletions.h"
27#include "lldb/Interpreter/CommandInterpreter.h"
Zachary Turner633a29c2015-03-04 01:58:01 +000028#include "lldb/Interpreter/OptionValueProperties.h"
Greg Clayton1f746072012-08-29 21:13:06 +000029#include "lldb/Symbol/CompileUnit.h"
Greg Claytonf21fead2013-05-14 23:43:18 +000030#include "lldb/Symbol/Variable.h"
Greg Clayton9b62fd22011-02-01 05:15:22 +000031#include "lldb/Target/Target.h"
Pavel Labath145d95c2018-04-17 18:53:35 +000032#include "lldb/Utility/Args.h"
Zachary Turner5713a052017-03-22 18:40:07 +000033#include "lldb/Utility/FileSpec.h"
Zachary Turner2f3df612017-04-06 21:28:29 +000034#include "lldb/Utility/StreamString.h"
Zachary Turner2cc5a182017-03-13 00:41:01 +000035#include "lldb/Utility/TildeExpressionResolver.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000036
Zachary Turner190fadc2016-03-22 17:58:09 +000037#include "llvm/ADT/SmallString.h"
Zachary Turner7d86ee52017-03-08 17:56:08 +000038#include "llvm/Support/FileSystem.h"
Zachary Turner2cc5a182017-03-13 00:41:01 +000039#include "llvm/Support/Path.h"
Zachary Turner190fadc2016-03-22 17:58:09 +000040
Chris Lattner30fdc8d2010-06-08 16:52:24 +000041using namespace lldb_private;
42
43CommandCompletions::CommonCompletionElement
Kate Stoneb9c1b512016-09-06 20:57:50 +000044 CommandCompletions::g_common_completions[] = {
45 {eCustomCompletion, nullptr},
46 {eSourceFileCompletion, CommandCompletions::SourceFiles},
47 {eDiskFileCompletion, CommandCompletions::DiskFiles},
48 {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
49 {eSymbolCompletion, CommandCompletions::Symbols},
50 {eModuleCompletion, CommandCompletions::Modules},
51 {eSettingsNameCompletion, CommandCompletions::SettingsNames},
52 {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames},
53 {eArchitectureCompletion, CommandCompletions::ArchitectureNames},
54 {eVariablePathCompletion, CommandCompletions::VariablePath},
55 {eNoCompletion, nullptr} // This one has to be last in the list.
Chris Lattner30fdc8d2010-06-08 16:52:24 +000056};
57
Kate Stoneb9c1b512016-09-06 20:57:50 +000058bool CommandCompletions::InvokeCommonCompletionCallbacks(
59 CommandInterpreter &interpreter, uint32_t completion_mask,
Raphael Isemanna2e76c02018-07-13 18:28:14 +000060 CompletionRequest &request, SearchFilter *searcher) {
Kate Stoneb9c1b512016-09-06 20:57:50 +000061 bool handled = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000062
Kate Stoneb9c1b512016-09-06 20:57:50 +000063 if (completion_mask & eCustomCompletion)
64 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000065
Kate Stoneb9c1b512016-09-06 20:57:50 +000066 for (int i = 0;; i++) {
67 if (g_common_completions[i].type == eNoCompletion)
68 break;
69 else if ((g_common_completions[i].type & completion_mask) ==
70 g_common_completions[i].type &&
71 g_common_completions[i].callback != nullptr) {
72 handled = true;
Raphael Isemanna2e76c02018-07-13 18:28:14 +000073 g_common_completions[i].callback(interpreter, request, searcher);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000074 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000075 }
76 return handled;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000077}
78
Kate Stoneb9c1b512016-09-06 20:57:50 +000079int CommandCompletions::SourceFiles(CommandInterpreter &interpreter,
Raphael Isemanna2e76c02018-07-13 18:28:14 +000080 CompletionRequest &request,
81 SearchFilter *searcher) {
82 request.SetWordComplete(true);
Kate Stoneb9c1b512016-09-06 20:57:50 +000083 // Find some way to switch "include support files..."
Raphael Isemanna2e76c02018-07-13 18:28:14 +000084 SourceFileCompleter completer(interpreter, false, request);
Kate Stoneb9c1b512016-09-06 20:57:50 +000085
86 if (searcher == nullptr) {
87 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
88 SearchFilterForUnconstrainedSearches null_searcher(target_sp);
89 completer.DoCompletion(&null_searcher);
90 } else {
91 completer.DoCompletion(searcher);
92 }
Raphael Isemanna2e76c02018-07-13 18:28:14 +000093 return request.GetMatches().GetSize();
Jim Ingham558ce122010-06-30 05:02:46 +000094}
95
Zachary Turner2cc5a182017-03-13 00:41:01 +000096static int DiskFilesOrDirectories(const llvm::Twine &partial_name,
Raphael Isemanna2e76c02018-07-13 18:28:14 +000097 bool only_directories, StringList &matches,
Zachary Turner2cc5a182017-03-13 00:41:01 +000098 TildeExpressionResolver &Resolver) {
99 matches.Clear();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000100
Zachary Turner2cc5a182017-03-13 00:41:01 +0000101 llvm::SmallString<256> CompletionBuffer;
102 llvm::SmallString<256> Storage;
103 partial_name.toVector(CompletionBuffer);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000104
Zachary Turner2cc5a182017-03-13 00:41:01 +0000105 if (CompletionBuffer.size() >= PATH_MAX)
106 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000107
Zachary Turner2cc5a182017-03-13 00:41:01 +0000108 namespace fs = llvm::sys::fs;
109 namespace path = llvm::sys::path;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000110
Zachary Turner2cc5a182017-03-13 00:41:01 +0000111 llvm::StringRef SearchDir;
112 llvm::StringRef PartialItem;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113
Zachary Turner2cc5a182017-03-13 00:41:01 +0000114 if (CompletionBuffer.startswith("~")) {
115 llvm::StringRef Buffer(CompletionBuffer);
Zachary Turner5c5091f2017-03-16 22:28:04 +0000116 size_t FirstSep =
117 Buffer.find_if([](char c) { return path::is_separator(c); });
Kate Stoneb9c1b512016-09-06 20:57:50 +0000118
Zachary Turner2cc5a182017-03-13 00:41:01 +0000119 llvm::StringRef Username = Buffer.take_front(FirstSep);
120 llvm::StringRef Remainder;
121 if (FirstSep != llvm::StringRef::npos)
122 Remainder = Buffer.drop_front(FirstSep + 1);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000123
Zachary Turner2cc5a182017-03-13 00:41:01 +0000124 llvm::SmallString<PATH_MAX> Resolved;
125 if (!Resolver.ResolveExact(Username, Resolved)) {
126 // We couldn't resolve it as a full username. If there were no slashes
127 // then this might be a partial username. We try to resolve it as such
128 // but after that, we're done regardless of any matches.
129 if (FirstSep == llvm::StringRef::npos) {
130 llvm::StringSet<> MatchSet;
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000131 Resolver.ResolvePartial(Username, MatchSet);
Zachary Turner2cc5a182017-03-13 00:41:01 +0000132 for (const auto &S : MatchSet) {
133 Resolved = S.getKey();
134 path::append(Resolved, path::get_separator());
135 matches.AppendString(Resolved);
136 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000137 }
Zachary Turner0734e6a2017-03-12 20:01:37 +0000138 return matches.GetSize();
Zachary Turner2cc5a182017-03-13 00:41:01 +0000139 }
140
Adrian Prantl05097242018-04-30 16:49:04 +0000141 // If there was no trailing slash, then we're done as soon as we resolve
142 // the expression to the correct directory. Otherwise we need to continue
Zachary Turner2cc5a182017-03-13 00:41:01 +0000143 // looking for matches within that directory.
144 if (FirstSep == llvm::StringRef::npos) {
145 // Make sure it ends with a separator.
146 path::append(CompletionBuffer, path::get_separator());
Zachary Turner2cc5a182017-03-13 00:41:01 +0000147 matches.AppendString(CompletionBuffer);
148 return 1;
149 }
150
151 // We want to keep the form the user typed, so we special case this to
152 // search in the fully resolved directory, but CompletionBuffer keeps the
153 // unmodified form that the user typed.
154 Storage = Resolved;
Pavel Labath88ec2e42018-06-29 10:27:18 +0000155 llvm::StringRef RemainderDir = path::parent_path(Remainder);
Raphael Isemann4621e0b2018-06-18 20:11:38 +0000156 if (!RemainderDir.empty()) {
157 // Append the remaining path to the resolved directory.
158 Storage.append(path::get_separator());
159 Storage.append(RemainderDir);
160 }
Raphael Isemann17843882018-01-22 09:17:16 +0000161 SearchDir = Storage;
Zachary Turner2cc5a182017-03-13 00:41:01 +0000162 } else {
163 SearchDir = path::parent_path(CompletionBuffer);
Zachary Turnerd5bd3a12017-03-12 18:18:50 +0000164 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000165
Zachary Turner2cc5a182017-03-13 00:41:01 +0000166 size_t FullPrefixLen = CompletionBuffer.size();
Zachary Turner0734e6a2017-03-12 20:01:37 +0000167
Zachary Turner2cc5a182017-03-13 00:41:01 +0000168 PartialItem = path::filename(CompletionBuffer);
169 if (PartialItem == ".")
170 PartialItem = llvm::StringRef();
Zachary Turner0734e6a2017-03-12 20:01:37 +0000171
Zachary Turner426d1372017-04-15 02:44:53 +0000172 if (SearchDir.empty()) {
173 llvm::sys::fs::current_path(Storage);
174 SearchDir = Storage;
175 }
Zachary Turner2cc5a182017-03-13 00:41:01 +0000176 assert(!PartialItem.contains(path::get_separator()));
Zachary Turner0734e6a2017-03-12 20:01:37 +0000177
Zachary Turner2cc5a182017-03-13 00:41:01 +0000178 // SearchDir now contains the directory to search in, and Prefix contains the
179 // text we want to match against items in that directory.
180
181 std::error_code EC;
182 fs::directory_iterator Iter(SearchDir, EC, false);
183 fs::directory_iterator End;
184 for (; Iter != End && !EC; Iter.increment(EC)) {
185 auto &Entry = *Iter;
186
187 auto Name = path::filename(Entry.path());
188
189 // Omit ".", ".."
190 if (Name == "." || Name == ".." || !Name.startswith(PartialItem))
191 continue;
192
193 // We have a match.
194
Peter Collingbourne0dfdb442017-10-10 22:19:46 +0000195 llvm::ErrorOr<fs::basic_file_status> st = Entry.status();
196 if (!st)
Zachary Turner2cc5a182017-03-13 00:41:01 +0000197 continue;
198
199 // If it's a symlink, then we treat it as a directory as long as the target
200 // is a directory.
Peter Collingbourne0dfdb442017-10-10 22:19:46 +0000201 bool is_dir = fs::is_directory(*st);
202 if (fs::is_symlink_file(*st)) {
Zachary Turner2cc5a182017-03-13 00:41:01 +0000203 fs::file_status target_st;
204 if (!fs::status(Entry.path(), target_st))
205 is_dir = fs::is_directory(target_st);
206 }
207 if (only_directories && !is_dir)
208 continue;
209
210 // Shrink it back down so that it just has the original prefix the user
211 // typed and remove the part of the name which is common to the located
212 // item and what the user typed.
213 CompletionBuffer.resize(FullPrefixLen);
214 Name = Name.drop_front(PartialItem.size());
215 CompletionBuffer.append(Name);
216
217 if (is_dir) {
Zachary Turner2cc5a182017-03-13 00:41:01 +0000218 path::append(CompletionBuffer, path::get_separator());
219 }
220
221 matches.AppendString(CompletionBuffer);
222 }
Zachary Turner0734e6a2017-03-12 20:01:37 +0000223
Kate Stoneb9c1b512016-09-06 20:57:50 +0000224 return matches.GetSize();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000225}
226
Kate Stoneb9c1b512016-09-06 20:57:50 +0000227int CommandCompletions::DiskFiles(CommandInterpreter &interpreter,
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000228 CompletionRequest &request,
229 SearchFilter *searcher) {
230 request.SetWordComplete(false);
Zachary Turner2cc5a182017-03-13 00:41:01 +0000231 StandardTildeExpressionResolver Resolver;
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000232 return DiskFiles(request.GetCursorArgumentPrefix(), request.GetMatches(),
233 Resolver);
Zachary Turner2cc5a182017-03-13 00:41:01 +0000234}
235
236int CommandCompletions::DiskFiles(const llvm::Twine &partial_file_name,
237 StringList &matches,
238 TildeExpressionResolver &Resolver) {
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000239 return DiskFilesOrDirectories(partial_file_name, false, matches, Resolver);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000240}
241
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000242int CommandCompletions::DiskDirectories(CommandInterpreter &interpreter,
243 CompletionRequest &request,
244 SearchFilter *searcher) {
245 request.SetWordComplete(false);
Zachary Turner2cc5a182017-03-13 00:41:01 +0000246 StandardTildeExpressionResolver Resolver;
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000247 return DiskDirectories(request.GetCursorArgumentPrefix(),
248 request.GetMatches(), Resolver);
Zachary Turner2cc5a182017-03-13 00:41:01 +0000249}
250
251int CommandCompletions::DiskDirectories(const llvm::Twine &partial_file_name,
252 StringList &matches,
253 TildeExpressionResolver &Resolver) {
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000254 return DiskFilesOrDirectories(partial_file_name, true, matches, Resolver);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000255}
256
257int CommandCompletions::Modules(CommandInterpreter &interpreter,
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000258 CompletionRequest &request,
259 SearchFilter *searcher) {
260 request.SetWordComplete(true);
261 ModuleCompleter completer(interpreter, request);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000262
263 if (searcher == nullptr) {
264 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
265 SearchFilterForUnconstrainedSearches null_searcher(target_sp);
266 completer.DoCompletion(&null_searcher);
267 } else {
268 completer.DoCompletion(searcher);
269 }
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000270 return request.GetMatches().GetSize();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000271}
272
273int CommandCompletions::Symbols(CommandInterpreter &interpreter,
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000274 CompletionRequest &request,
275 SearchFilter *searcher) {
276 request.SetWordComplete(true);
277 SymbolCompleter completer(interpreter, request);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000278
279 if (searcher == nullptr) {
280 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
281 SearchFilterForUnconstrainedSearches null_searcher(target_sp);
282 completer.DoCompletion(&null_searcher);
283 } else {
284 completer.DoCompletion(searcher);
285 }
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000286 return request.GetMatches().GetSize();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000287}
288
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000289int CommandCompletions::SettingsNames(CommandInterpreter &interpreter,
290 CompletionRequest &request,
291 SearchFilter *searcher) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000292 // Cache the full setting name list
293 static StringList g_property_names;
294 if (g_property_names.GetSize() == 0) {
295 // Generate the full setting name list on demand
296 lldb::OptionValuePropertiesSP properties_sp(
297 interpreter.GetDebugger().GetValueProperties());
298 if (properties_sp) {
299 StreamString strm;
300 properties_sp->DumpValue(nullptr, strm, OptionValue::eDumpOptionName);
301 const std::string &str = strm.GetString();
302 g_property_names.SplitIntoLines(str.c_str(), str.size());
303 }
304 }
305
306 size_t exact_matches_idx = SIZE_MAX;
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000307 const size_t num_matches =
308 g_property_names.AutoComplete(request.GetCursorArgumentPrefix(),
309 request.GetMatches(), exact_matches_idx);
310 request.SetWordComplete(exact_matches_idx != SIZE_MAX);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000311 return num_matches;
312}
313
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000314int CommandCompletions::PlatformPluginNames(CommandInterpreter &interpreter,
315 CompletionRequest &request,
316 SearchFilter *searcher) {
317 const uint32_t num_matches = PluginManager::AutoCompletePlatformName(
318 request.GetCursorArgumentPrefix(), request.GetMatches());
319 request.SetWordComplete(num_matches == 1);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000320 return num_matches;
321}
322
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000323int CommandCompletions::ArchitectureNames(CommandInterpreter &interpreter,
324 CompletionRequest &request,
325 SearchFilter *searcher) {
326 const uint32_t num_matches = ArchSpec::AutoComplete(request);
327 request.SetWordComplete(num_matches == 1);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000328 return num_matches;
329}
330
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000331int CommandCompletions::VariablePath(CommandInterpreter &interpreter,
332 CompletionRequest &request,
333 SearchFilter *searcher) {
334 return Variable::AutoComplete(interpreter.GetExecutionContext(), request);
Greg Claytonf21fead2013-05-14 23:43:18 +0000335}
336
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000337CommandCompletions::Completer::Completer(CommandInterpreter &interpreter,
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000338 CompletionRequest &request)
339 : m_interpreter(interpreter), m_request(request) {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000340
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000341CommandCompletions::Completer::~Completer() = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000342
343//----------------------------------------------------------------------
344// SourceFileCompleter
345//----------------------------------------------------------------------
346
Kate Stoneb9c1b512016-09-06 20:57:50 +0000347CommandCompletions::SourceFileCompleter::SourceFileCompleter(
348 CommandInterpreter &interpreter, bool include_support_files,
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000349 CompletionRequest &request)
350 : CommandCompletions::Completer(interpreter, request),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000351 m_include_support_files(include_support_files), m_matching_files() {
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000352 FileSpec partial_spec(m_request.GetCursorArgumentPrefix(), false);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000353 m_file_name = partial_spec.GetFilename().GetCString();
354 m_dir_name = partial_spec.GetDirectory().GetCString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000355}
356
Kate Stoneb9c1b512016-09-06 20:57:50 +0000357Searcher::Depth CommandCompletions::SourceFileCompleter::GetDepth() {
358 return eDepthCompUnit;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000359}
360
361Searcher::CallbackReturn
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000362CommandCompletions::SourceFileCompleter::SearchCallback(SearchFilter &filter,
363 SymbolContext &context,
364 Address *addr,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000365 bool complete) {
366 if (context.comp_unit != nullptr) {
367 if (m_include_support_files) {
368 FileSpecList supporting_files = context.comp_unit->GetSupportFiles();
369 for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++) {
370 const FileSpec &sfile_spec =
371 supporting_files.GetFileSpecAtIndex(sfiles);
372 const char *sfile_file_name = sfile_spec.GetFilename().GetCString();
373 const char *sfile_dir_name = sfile_spec.GetFilename().GetCString();
374 bool match = false;
375 if (m_file_name && sfile_file_name &&
376 strstr(sfile_file_name, m_file_name) == sfile_file_name)
377 match = true;
378 if (match && m_dir_name && sfile_dir_name &&
379 strstr(sfile_dir_name, m_dir_name) != sfile_dir_name)
380 match = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000381
Kate Stoneb9c1b512016-09-06 20:57:50 +0000382 if (match) {
383 m_matching_files.AppendIfUnique(sfile_spec);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000384 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000385 }
386 } else {
387 const char *cur_file_name = context.comp_unit->GetFilename().GetCString();
388 const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000389
Kate Stoneb9c1b512016-09-06 20:57:50 +0000390 bool match = false;
391 if (m_file_name && cur_file_name &&
392 strstr(cur_file_name, m_file_name) == cur_file_name)
393 match = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000394
Kate Stoneb9c1b512016-09-06 20:57:50 +0000395 if (match && m_dir_name && cur_dir_name &&
396 strstr(cur_dir_name, m_dir_name) != cur_dir_name)
397 match = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000398
Kate Stoneb9c1b512016-09-06 20:57:50 +0000399 if (match) {
400 m_matching_files.AppendIfUnique(context.comp_unit);
401 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000402 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000403 }
404 return Searcher::eCallbackReturnContinue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000405}
406
407size_t
Kate Stoneb9c1b512016-09-06 20:57:50 +0000408CommandCompletions::SourceFileCompleter::DoCompletion(SearchFilter *filter) {
409 filter->Search(*this);
410 // Now convert the filelist to completions:
411 for (size_t i = 0; i < m_matching_files.GetSize(); i++) {
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000412 m_request.GetMatches().AppendString(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000413 m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
414 }
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000415 return m_request.GetMatches().GetSize();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000416}
417
418//----------------------------------------------------------------------
419// SymbolCompleter
420//----------------------------------------------------------------------
421
Kate Stoneb9c1b512016-09-06 20:57:50 +0000422static bool regex_chars(const char comp) {
423 return (comp == '[' || comp == ']' || comp == '(' || comp == ')' ||
424 comp == '{' || comp == '}' || comp == '+' || comp == '.' ||
425 comp == '*' || comp == '|' || comp == '^' || comp == '$' ||
426 comp == '\\' || comp == '?');
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000427}
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000428
Kate Stoneb9c1b512016-09-06 20:57:50 +0000429CommandCompletions::SymbolCompleter::SymbolCompleter(
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000430 CommandInterpreter &interpreter, CompletionRequest &request)
431 : CommandCompletions::Completer(interpreter, request) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000432 std::string regex_str;
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000433 if (!m_request.GetCursorArgumentPrefix().empty()) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000434 regex_str.append("^");
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000435 regex_str.append(m_request.GetCursorArgumentPrefix());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000436 } else {
437 // Match anything since the completion string is empty
438 regex_str.append(".");
439 }
440 std::string::iterator pos =
441 find_if(regex_str.begin() + 1, regex_str.end(), regex_chars);
442 while (pos < regex_str.end()) {
443 pos = regex_str.insert(pos, '\\');
444 pos = find_if(pos + 2, regex_str.end(), regex_chars);
445 }
Zachary Turner95eae422016-09-21 16:01:28 +0000446 m_regex.Compile(regex_str);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000447}
448
Kate Stoneb9c1b512016-09-06 20:57:50 +0000449Searcher::Depth CommandCompletions::SymbolCompleter::GetDepth() {
450 return eDepthModule;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000451}
452
Kate Stoneb9c1b512016-09-06 20:57:50 +0000453Searcher::CallbackReturn CommandCompletions::SymbolCompleter::SearchCallback(
454 SearchFilter &filter, SymbolContext &context, Address *addr,
455 bool complete) {
456 if (context.module_sp) {
457 SymbolContextList sc_list;
458 const bool include_symbols = true;
459 const bool include_inlines = true;
460 const bool append = true;
461 context.module_sp->FindFunctions(m_regex, include_symbols, include_inlines,
462 append, sc_list);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000463
Kate Stoneb9c1b512016-09-06 20:57:50 +0000464 SymbolContext sc;
465 // Now add the functions & symbols to the list - only add if unique:
466 for (uint32_t i = 0; i < sc_list.GetSize(); i++) {
467 if (sc_list.GetContextAtIndex(i, sc)) {
468 ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
469 if (!func_name.IsEmpty())
470 m_match_set.insert(func_name);
471 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000472 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000473 }
474 return Searcher::eCallbackReturnContinue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000475}
476
Kate Stoneb9c1b512016-09-06 20:57:50 +0000477size_t CommandCompletions::SymbolCompleter::DoCompletion(SearchFilter *filter) {
478 filter->Search(*this);
479 collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
480 for (pos = m_match_set.begin(); pos != end; pos++)
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000481 m_request.GetMatches().AppendString((*pos).GetCString());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000482
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000483 return m_request.GetMatches().GetSize();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000484}
485
486//----------------------------------------------------------------------
487// ModuleCompleter
488//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000489CommandCompletions::ModuleCompleter::ModuleCompleter(
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000490 CommandInterpreter &interpreter, CompletionRequest &request)
491 : CommandCompletions::Completer(interpreter, request) {
492 FileSpec partial_spec(m_request.GetCursorArgumentPrefix(), false);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000493 m_file_name = partial_spec.GetFilename().GetCString();
494 m_dir_name = partial_spec.GetDirectory().GetCString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000495}
496
Kate Stoneb9c1b512016-09-06 20:57:50 +0000497Searcher::Depth CommandCompletions::ModuleCompleter::GetDepth() {
498 return eDepthModule;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000499}
500
Kate Stoneb9c1b512016-09-06 20:57:50 +0000501Searcher::CallbackReturn CommandCompletions::ModuleCompleter::SearchCallback(
502 SearchFilter &filter, SymbolContext &context, Address *addr,
503 bool complete) {
504 if (context.module_sp) {
505 const char *cur_file_name =
506 context.module_sp->GetFileSpec().GetFilename().GetCString();
507 const char *cur_dir_name =
508 context.module_sp->GetFileSpec().GetDirectory().GetCString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000509
Kate Stoneb9c1b512016-09-06 20:57:50 +0000510 bool match = false;
511 if (m_file_name && cur_file_name &&
512 strstr(cur_file_name, m_file_name) == cur_file_name)
513 match = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000514
Kate Stoneb9c1b512016-09-06 20:57:50 +0000515 if (match && m_dir_name && cur_dir_name &&
516 strstr(cur_dir_name, m_dir_name) != cur_dir_name)
517 match = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000518
Kate Stoneb9c1b512016-09-06 20:57:50 +0000519 if (match) {
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000520 m_request.GetMatches().AppendString(cur_file_name);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000521 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000522 }
523 return Searcher::eCallbackReturnContinue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000524}
525
Kate Stoneb9c1b512016-09-06 20:57:50 +0000526size_t CommandCompletions::ModuleCompleter::DoCompletion(SearchFilter *filter) {
527 filter->Search(*this);
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000528 return m_request.GetMatches().GetSize();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000529}