1 //===-- CommandAlias.cpp -----------------------------------------*- C++-*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Interpreter/CommandAlias.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 CommandReturnObject result;
35 // Check to see if the command being aliased can take any command options.
36 Options *options = cmd_obj_sp->GetOptions();
38 // See if any options were specified as part of the alias; if so, handle
39 // them appropriately.
40 ExecutionContext exe_ctx =
41 cmd_obj_sp->GetCommandInterpreter().GetExecutionContext();
42 options->NotifyOptionParsingStarting(&exe_ctx);
43 args.Unshift(llvm::StringRef("dummy_arg"));
44 options_string = args.ParseAliasOptions(*options, result, option_arg_vector,
47 if (result.Succeeded())
48 options->VerifyPartialOptions(result);
49 if (!result.Succeeded() &&
50 result.GetStatus() != lldb::eReturnStatusStarted) {
51 result.AppendError("Unable to create requested alias.\n");
56 if (!options_string.empty()) {
57 if (cmd_obj_sp->WantsRawCommandString())
58 option_arg_vector->emplace_back("<argument>", -1, options_string);
60 for (auto &entry : args.entries()) {
61 if (!entry.ref.empty())
62 option_arg_vector->emplace_back("<argument>", -1, entry.ref);
70 CommandAlias::CommandAlias(CommandInterpreter &interpreter,
71 lldb::CommandObjectSP cmd_sp,
72 llvm::StringRef options_args, llvm::StringRef name,
73 llvm::StringRef help, llvm::StringRef syntax,
75 : CommandObject(interpreter, name, help, syntax, flags),
76 m_underlying_command_sp(), m_option_string(options_args),
77 m_option_args_sp(new OptionArgVector),
78 m_is_dashdash_alias(eLazyBoolCalculate), m_did_set_help(false),
79 m_did_set_help_long(false) {
80 if (ProcessAliasOptionsArgs(cmd_sp, options_args, m_option_args_sp)) {
81 m_underlying_command_sp = cmd_sp;
83 auto cmd_entry = m_underlying_command_sp->GetArgumentEntryAtIndex(i);
85 m_arguments.push_back(*cmd_entry);
89 StreamString translation_and_help;
90 GetAliasExpansion(sstr);
92 translation_and_help.Printf(
93 "(%s) %s", sstr.GetData(),
94 GetUnderlyingCommand()->GetHelp().str().c_str());
95 SetHelp(translation_and_help.GetString());
100 bool CommandAlias::WantsRawCommandString() {
102 return m_underlying_command_sp->WantsRawCommandString();
106 bool CommandAlias::WantsCompletion() {
108 return m_underlying_command_sp->WantsCompletion();
112 int CommandAlias::HandleCompletion(Args &input, int &cursor_index,
113 int &cursor_char_position,
114 int match_start_point,
115 int max_return_elements, bool &word_complete,
116 StringList &matches) {
118 return m_underlying_command_sp->HandleCompletion(
119 input, cursor_index, cursor_char_position, match_start_point,
120 max_return_elements, word_complete, matches);
124 int CommandAlias::HandleArgumentCompletion(
125 Args &input, int &cursor_index, int &cursor_char_position,
126 OptionElementVector &opt_element_vector, int match_start_point,
127 int max_return_elements, bool &word_complete, StringList &matches) {
129 return m_underlying_command_sp->HandleArgumentCompletion(
130 input, cursor_index, cursor_char_position, opt_element_vector,
131 match_start_point, max_return_elements, word_complete, matches);
135 Options *CommandAlias::GetOptions() {
137 return m_underlying_command_sp->GetOptions();
141 bool CommandAlias::Execute(const char *args_string,
142 CommandReturnObject &result) {
143 llvm_unreachable("CommandAlias::Execute is not to be called");
146 void CommandAlias::GetAliasExpansion(StreamString &help_string) const {
147 llvm::StringRef command_name = m_underlying_command_sp->GetCommandName();
148 help_string.Printf("'%*s", (int)command_name.size(), command_name.data());
150 if (!m_option_args_sp) {
151 help_string.Printf("'");
155 OptionArgVector *options = m_option_args_sp.get();
159 for (const auto &opt_entry : *options) {
160 std::tie(opt, std::ignore, value) = opt_entry;
161 if (opt == "<argument>") {
162 help_string.Printf(" %s", value.c_str());
164 help_string.Printf(" %s", opt.c_str());
165 if ((value.compare("<no-argument>") != 0) &&
166 (value.compare("<need-argument") != 0)) {
167 help_string.Printf(" %s", value.c_str());
172 help_string.Printf("'");
175 bool CommandAlias::IsDashDashCommand() {
176 if (m_is_dashdash_alias != eLazyBoolCalculate)
177 return (m_is_dashdash_alias == eLazyBoolYes);
178 m_is_dashdash_alias = eLazyBoolNo;
185 for (const auto &opt_entry : *GetOptionArguments()) {
186 std::tie(opt, std::ignore, value) = opt_entry;
187 if (opt == "<argument>" && !value.empty() &&
188 llvm::StringRef(value).endswith("--")) {
189 m_is_dashdash_alias = eLazyBoolYes;
194 // if this is a nested alias, it may be adding arguments on top of an
195 // already dash-dash alias
196 if ((m_is_dashdash_alias == eLazyBoolNo) && IsNestedAlias())
197 m_is_dashdash_alias =
198 (GetUnderlyingCommand()->IsDashDashCommand() ? eLazyBoolYes
200 return (m_is_dashdash_alias == eLazyBoolYes);
203 bool CommandAlias::IsNestedAlias() {
204 if (GetUnderlyingCommand())
205 return GetUnderlyingCommand()->IsAlias();
209 std::pair<lldb::CommandObjectSP, OptionArgVectorSP> CommandAlias::Desugar() {
210 auto underlying = GetUnderlyingCommand();
212 return {nullptr, nullptr};
214 if (underlying->IsAlias()) {
215 auto desugared = ((CommandAlias *)underlying.get())->Desugar();
216 auto options = GetOptionArguments();
217 options->insert(options->begin(), desugared.second->begin(),
218 desugared.second->end());
219 return {desugared.first, options};
222 return {underlying, GetOptionArguments()};
225 // allow CommandAlias objects to provide their own help, but fallback to the
227 // for the underlying command if no customization has been provided
228 void CommandAlias::SetHelp(llvm::StringRef str) {
229 this->CommandObject::SetHelp(str);
230 m_did_set_help = true;
233 void CommandAlias::SetHelpLong(llvm::StringRef str) {
234 this->CommandObject::SetHelpLong(str);
235 m_did_set_help_long = true;
238 llvm::StringRef CommandAlias::GetHelp() {
239 if (!m_cmd_help_short.empty() || m_did_set_help)
240 return m_cmd_help_short;
242 return m_underlying_command_sp->GetHelp();
243 return llvm::StringRef();
246 llvm::StringRef CommandAlias::GetHelpLong() {
247 if (!m_cmd_help_long.empty() || m_did_set_help_long)
248 return m_cmd_help_long;
250 return m_underlying_command_sp->GetHelpLong();
251 return llvm::StringRef();