1 //===-- CommandAlias.cpp --------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Interpreter/CommandAlias.h"
11 #include "llvm/ADT/STLExtras.h"
12 #include "llvm/Support/ErrorHandling.h"
14 #include "lldb/Interpreter/CommandInterpreter.h"
15 #include "lldb/Interpreter/CommandObject.h"
16 #include "lldb/Interpreter/CommandReturnObject.h"
17 #include "lldb/Interpreter/Options.h"
18 #include "lldb/Utility/StreamString.h"
21 using namespace lldb_private
;
23 static bool ProcessAliasOptionsArgs(lldb::CommandObjectSP
&cmd_obj_sp
,
24 llvm::StringRef options_args
,
25 OptionArgVectorSP
&option_arg_vector_sp
) {
27 OptionArgVector
*option_arg_vector
= option_arg_vector_sp
.get();
29 if (options_args
.size() < 1)
32 Args
args(options_args
);
33 std::string
options_string(options_args
);
34 // TODO: Find a way to propagate errors in this CommandReturnObject up the
36 CommandReturnObject
result(false);
37 // Check to see if the command being aliased can take any command options.
38 Options
*options
= cmd_obj_sp
->GetOptions();
40 // See if any options were specified as part of the alias; if so, handle
41 // them appropriately.
42 ExecutionContext exe_ctx
=
43 cmd_obj_sp
->GetCommandInterpreter().GetExecutionContext();
44 options
->NotifyOptionParsingStarting(&exe_ctx
);
46 llvm::Expected
<Args
> args_or
=
47 options
->ParseAlias(args
, option_arg_vector
, options_string
);
49 result
.AppendError(toString(args_or
.takeError()));
50 result
.AppendError("Unable to create requested alias.\n");
53 args
= std::move(*args_or
);
54 options
->VerifyPartialOptions(result
);
55 if (!result
.Succeeded() &&
56 result
.GetStatus() != lldb::eReturnStatusStarted
) {
57 result
.AppendError("Unable to create requested alias.\n");
62 if (!options_string
.empty()) {
63 if (cmd_obj_sp
->WantsRawCommandString())
64 option_arg_vector
->emplace_back(CommandInterpreter::g_argument
,
67 for (auto &entry
: args
.entries()) {
68 if (!entry
.ref().empty())
69 option_arg_vector
->emplace_back(std::string(CommandInterpreter::g_argument
), -1,
70 std::string(entry
.ref()));
78 CommandAlias::CommandAlias(CommandInterpreter
&interpreter
,
79 lldb::CommandObjectSP cmd_sp
,
80 llvm::StringRef options_args
, llvm::StringRef name
,
81 llvm::StringRef help
, llvm::StringRef syntax
,
83 : CommandObject(interpreter
, name
, help
, syntax
, flags
),
84 m_option_string(std::string(options_args
)),
85 m_option_args_sp(new OptionArgVector
),
86 m_is_dashdash_alias(eLazyBoolCalculate
), m_did_set_help(false),
87 m_did_set_help_long(false) {
88 if (ProcessAliasOptionsArgs(cmd_sp
, options_args
, m_option_args_sp
)) {
89 m_underlying_command_sp
= cmd_sp
;
91 auto cmd_entry
= m_underlying_command_sp
->GetArgumentEntryAtIndex(i
);
93 m_arguments
.push_back(*cmd_entry
);
97 StreamString translation_and_help
;
98 GetAliasExpansion(sstr
);
100 translation_and_help
.Printf(
101 "(%s) %s", sstr
.GetData(),
102 GetUnderlyingCommand()->GetHelp().str().c_str());
103 SetHelp(translation_and_help
.GetString());
108 bool CommandAlias::WantsRawCommandString() {
110 return m_underlying_command_sp
->WantsRawCommandString();
114 bool CommandAlias::WantsCompletion() {
116 return m_underlying_command_sp
->WantsCompletion();
120 void CommandAlias::HandleCompletion(CompletionRequest
&request
) {
122 m_underlying_command_sp
->HandleCompletion(request
);
125 void CommandAlias::HandleArgumentCompletion(
126 CompletionRequest
&request
, OptionElementVector
&opt_element_vector
) {
128 m_underlying_command_sp
->HandleArgumentCompletion(request
,
132 Options
*CommandAlias::GetOptions() {
134 return m_underlying_command_sp
->GetOptions();
138 void CommandAlias::Execute(const char *args_string
,
139 CommandReturnObject
&result
) {
140 llvm_unreachable("CommandAlias::Execute is not to be called");
143 void CommandAlias::GetAliasExpansion(StreamString
&help_string
) const {
144 llvm::StringRef command_name
= m_underlying_command_sp
->GetCommandName();
145 help_string
.Printf("'%*s", (int)command_name
.size(), command_name
.data());
147 if (!m_option_args_sp
) {
148 help_string
.Printf("'");
152 OptionArgVector
*options
= m_option_args_sp
.get();
156 for (const auto &opt_entry
: *options
) {
157 std::tie(opt
, std::ignore
, value
) = opt_entry
;
158 if (opt
== CommandInterpreter::g_argument
) {
159 help_string
.Printf(" %s", value
.c_str());
161 help_string
.Printf(" %s", opt
.c_str());
162 if ((value
!= CommandInterpreter::g_no_argument
)
163 && (value
!= CommandInterpreter::g_need_argument
)) {
164 help_string
.Printf(" %s", value
.c_str());
169 help_string
.Printf("'");
172 bool CommandAlias::IsDashDashCommand() {
173 if (m_is_dashdash_alias
!= eLazyBoolCalculate
)
174 return (m_is_dashdash_alias
== eLazyBoolYes
);
175 m_is_dashdash_alias
= eLazyBoolNo
;
182 for (const auto &opt_entry
: *GetOptionArguments()) {
183 std::tie(opt
, std::ignore
, value
) = opt_entry
;
184 if (opt
== CommandInterpreter::g_argument
&& !value
.empty() &&
185 llvm::StringRef(value
).ends_with("--")) {
186 m_is_dashdash_alias
= eLazyBoolYes
;
191 // if this is a nested alias, it may be adding arguments on top of an already
193 if ((m_is_dashdash_alias
== eLazyBoolNo
) && IsNestedAlias())
194 m_is_dashdash_alias
=
195 (GetUnderlyingCommand()->IsDashDashCommand() ? eLazyBoolYes
197 return (m_is_dashdash_alias
== eLazyBoolYes
);
200 bool CommandAlias::IsNestedAlias() {
201 if (GetUnderlyingCommand())
202 return GetUnderlyingCommand()->IsAlias();
206 std::pair
<lldb::CommandObjectSP
, OptionArgVectorSP
> CommandAlias::Desugar() {
207 auto underlying
= GetUnderlyingCommand();
209 return {nullptr, nullptr};
211 if (underlying
->IsAlias()) {
212 // FIXME: This doesn't work if the original alias fills a slot in the
213 // underlying alias, since this just appends the two lists.
214 auto desugared
= ((CommandAlias
*)underlying
.get())->Desugar();
215 OptionArgVectorSP options
= std::make_shared
<OptionArgVector
>();
216 llvm::append_range(*options
, *desugared
.second
);
217 llvm::append_range(*options
, *GetOptionArguments());
218 return {desugared
.first
, options
};
221 return {underlying
, GetOptionArguments()};
224 // allow CommandAlias objects to provide their own help, but fallback to the
225 // info for the underlying command if no customization has been provided
226 void CommandAlias::SetHelp(llvm::StringRef str
) {
227 this->CommandObject::SetHelp(str
);
228 m_did_set_help
= true;
231 void CommandAlias::SetHelpLong(llvm::StringRef str
) {
232 this->CommandObject::SetHelpLong(str
);
233 m_did_set_help_long
= true;
236 llvm::StringRef
CommandAlias::GetHelp() {
237 if (!m_cmd_help_short
.empty() || m_did_set_help
)
238 return m_cmd_help_short
;
240 return m_underlying_command_sp
->GetHelp();
241 return llvm::StringRef();
244 llvm::StringRef
CommandAlias::GetHelpLong() {
245 if (!m_cmd_help_long
.empty() || m_did_set_help_long
)
246 return m_cmd_help_long
;
248 return m_underlying_command_sp
->GetHelpLong();
249 return llvm::StringRef();