Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Commands/CommandObjectHelp.cpp
39587 views
1
//===-- CommandObjectHelp.cpp ---------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "CommandObjectHelp.h"
10
#include "lldb/Interpreter/CommandInterpreter.h"
11
#include "lldb/Interpreter/CommandOptionArgumentTable.h"
12
#include "lldb/Interpreter/CommandReturnObject.h"
13
14
using namespace lldb;
15
using namespace lldb_private;
16
17
// CommandObjectHelp
18
19
void CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
20
Stream *s, llvm::StringRef command, llvm::StringRef prefix,
21
llvm::StringRef subcommand, bool include_upropos,
22
bool include_type_lookup) {
23
if (!s || command.empty())
24
return;
25
26
std::string command_str = command.str();
27
std::string prefix_str = prefix.str();
28
std::string subcommand_str = subcommand.str();
29
const std::string &lookup_str =
30
!subcommand_str.empty() ? subcommand_str : command_str;
31
s->Printf("'%s' is not a known command.\n", command_str.c_str());
32
s->Printf("Try '%shelp' to see a current list of commands.\n",
33
prefix.str().c_str());
34
if (include_upropos) {
35
s->Printf("Try '%sapropos %s' for a list of related commands.\n",
36
prefix_str.c_str(), lookup_str.c_str());
37
}
38
if (include_type_lookup) {
39
s->Printf("Try '%stype lookup %s' for information on types, methods, "
40
"functions, modules, etc.",
41
prefix_str.c_str(), lookup_str.c_str());
42
}
43
}
44
45
CommandObjectHelp::CommandObjectHelp(CommandInterpreter &interpreter)
46
: CommandObjectParsed(interpreter, "help",
47
"Show a list of all debugger "
48
"commands, or give details "
49
"about a specific command.",
50
"help [<cmd-name>]") {
51
// A list of command names forming a path to the command we want help on.
52
// No names is allowed - in which case we dump the top-level help.
53
AddSimpleArgumentList(eArgTypeCommand, eArgRepeatStar);
54
}
55
56
CommandObjectHelp::~CommandObjectHelp() = default;
57
58
#define LLDB_OPTIONS_help
59
#include "CommandOptions.inc"
60
61
llvm::ArrayRef<OptionDefinition>
62
CommandObjectHelp::CommandOptions::GetDefinitions() {
63
return llvm::ArrayRef(g_help_options);
64
}
65
66
void CommandObjectHelp::DoExecute(Args &command, CommandReturnObject &result) {
67
CommandObject::CommandMap::iterator pos;
68
CommandObject *cmd_obj;
69
const size_t argc = command.GetArgumentCount();
70
71
// 'help' doesn't take any arguments, other than command names. If argc is
72
// 0, we show the user all commands (aliases and user commands if asked for).
73
// Otherwise every argument must be the name of a command or a sub-command.
74
if (argc == 0) {
75
uint32_t cmd_types = CommandInterpreter::eCommandTypesBuiltin;
76
if (m_options.m_show_aliases)
77
cmd_types |= CommandInterpreter::eCommandTypesAliases;
78
if (m_options.m_show_user_defined) {
79
cmd_types |= CommandInterpreter::eCommandTypesUserDef;
80
cmd_types |= CommandInterpreter::eCommandTypesUserMW;
81
}
82
if (m_options.m_show_hidden)
83
cmd_types |= CommandInterpreter::eCommandTypesHidden;
84
85
result.SetStatus(eReturnStatusSuccessFinishNoResult);
86
m_interpreter.GetHelp(result, cmd_types); // General help
87
} else {
88
// Get command object for the first command argument. Only search built-in
89
// command dictionary.
90
StringList matches;
91
auto command_name = command[0].ref();
92
cmd_obj = m_interpreter.GetCommandObject(command_name, &matches);
93
94
if (cmd_obj != nullptr) {
95
StringList matches;
96
bool all_okay = true;
97
CommandObject *sub_cmd_obj = cmd_obj;
98
// Loop down through sub_command dictionaries until we find the command
99
// object that corresponds to the help command entered.
100
std::string sub_command;
101
for (auto &entry : command.entries().drop_front()) {
102
sub_command = std::string(entry.ref());
103
matches.Clear();
104
if (sub_cmd_obj->IsAlias())
105
sub_cmd_obj =
106
((CommandAlias *)sub_cmd_obj)->GetUnderlyingCommand().get();
107
if (!sub_cmd_obj->IsMultiwordObject()) {
108
all_okay = false;
109
break;
110
} else {
111
CommandObject *found_cmd;
112
found_cmd =
113
sub_cmd_obj->GetSubcommandObject(sub_command.c_str(), &matches);
114
if (found_cmd == nullptr || matches.GetSize() > 1) {
115
all_okay = false;
116
break;
117
} else
118
sub_cmd_obj = found_cmd;
119
}
120
}
121
122
if (!all_okay || (sub_cmd_obj == nullptr)) {
123
std::string cmd_string;
124
command.GetCommandString(cmd_string);
125
if (matches.GetSize() >= 2) {
126
StreamString s;
127
s.Printf("ambiguous command %s", cmd_string.c_str());
128
size_t num_matches = matches.GetSize();
129
for (size_t match_idx = 0; match_idx < num_matches; match_idx++) {
130
s.Printf("\n\t%s", matches.GetStringAtIndex(match_idx));
131
}
132
s.Printf("\n");
133
result.AppendError(s.GetString());
134
return;
135
} else if (!sub_cmd_obj) {
136
StreamString error_msg_stream;
137
GenerateAdditionalHelpAvenuesMessage(
138
&error_msg_stream, cmd_string.c_str(),
139
m_interpreter.GetCommandPrefix(), sub_command.c_str());
140
result.AppendError(error_msg_stream.GetString());
141
return;
142
} else {
143
GenerateAdditionalHelpAvenuesMessage(
144
&result.GetOutputStream(), cmd_string.c_str(),
145
m_interpreter.GetCommandPrefix(), sub_command.c_str());
146
result.GetOutputStream().Printf(
147
"\nThe closest match is '%s'. Help on it follows.\n\n",
148
sub_cmd_obj->GetCommandName().str().c_str());
149
}
150
}
151
152
sub_cmd_obj->GenerateHelpText(result);
153
std::string alias_full_name;
154
// Don't use AliasExists here, that only checks exact name matches. If
155
// the user typed a shorter unique alias name, we should still tell them
156
// it was an alias.
157
if (m_interpreter.GetAliasFullName(command_name, alias_full_name)) {
158
StreamString sstr;
159
m_interpreter.GetAlias(alias_full_name)->GetAliasExpansion(sstr);
160
result.GetOutputStream().Printf("\n'%s' is an abbreviation for %s\n",
161
command[0].c_str(), sstr.GetData());
162
}
163
} else if (matches.GetSize() > 0) {
164
Stream &output_strm = result.GetOutputStream();
165
output_strm.Printf("Help requested with ambiguous command name, possible "
166
"completions:\n");
167
const size_t match_count = matches.GetSize();
168
for (size_t i = 0; i < match_count; i++) {
169
output_strm.Printf("\t%s\n", matches.GetStringAtIndex(i));
170
}
171
} else {
172
// Maybe the user is asking for help about a command argument rather than
173
// a command.
174
const CommandArgumentType arg_type =
175
CommandObject::LookupArgumentName(command_name);
176
if (arg_type != eArgTypeLastArg) {
177
Stream &output_strm = result.GetOutputStream();
178
CommandObject::GetArgumentHelp(output_strm, arg_type, m_interpreter);
179
result.SetStatus(eReturnStatusSuccessFinishNoResult);
180
} else {
181
StreamString error_msg_stream;
182
GenerateAdditionalHelpAvenuesMessage(&error_msg_stream, command_name,
183
m_interpreter.GetCommandPrefix(),
184
"");
185
result.AppendError(error_msg_stream.GetString());
186
}
187
}
188
}
189
}
190
191
void CommandObjectHelp::HandleCompletion(CompletionRequest &request) {
192
// Return the completions of the commands in the help system:
193
if (request.GetCursorIndex() == 0) {
194
m_interpreter.HandleCompletionMatches(request);
195
return;
196
}
197
CommandObject *cmd_obj =
198
m_interpreter.GetCommandObject(request.GetParsedLine()[0].ref());
199
200
// The command that they are getting help on might be ambiguous, in which
201
// case we should complete that, otherwise complete with the command the
202
// user is getting help on...
203
204
if (cmd_obj) {
205
request.ShiftArguments();
206
cmd_obj->HandleCompletion(request);
207
return;
208
}
209
m_interpreter.HandleCompletionMatches(request);
210
}
211
212