180814287SRaphael Isemann //===-- CommandAlias.cpp --------------------------------------------------===//
2937631cfSEnrico Granata //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6937631cfSEnrico Granata //
7937631cfSEnrico Granata //===----------------------------------------------------------------------===//
8937631cfSEnrico Granata
9937631cfSEnrico Granata #include "lldb/Interpreter/CommandAlias.h"
10937631cfSEnrico Granata
113e271af4SEnrico Granata #include "llvm/Support/ErrorHandling.h"
123e271af4SEnrico Granata
13e1cfbc79STodd Fiala #include "lldb/Interpreter/CommandInterpreter.h"
144643c012SEnrico Granata #include "lldb/Interpreter/CommandObject.h"
154643c012SEnrico Granata #include "lldb/Interpreter/CommandReturnObject.h"
164643c012SEnrico Granata #include "lldb/Interpreter/Options.h"
17bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
184643c012SEnrico Granata
194643c012SEnrico Granata using namespace lldb;
204643c012SEnrico Granata using namespace lldb_private;
214643c012SEnrico Granata
ProcessAliasOptionsArgs(lldb::CommandObjectSP & cmd_obj_sp,llvm::StringRef options_args,OptionArgVectorSP & option_arg_vector_sp)22b9c1b51eSKate Stone static bool ProcessAliasOptionsArgs(lldb::CommandObjectSP &cmd_obj_sp,
23a449698cSZachary Turner llvm::StringRef options_args,
24b9c1b51eSKate Stone OptionArgVectorSP &option_arg_vector_sp) {
254643c012SEnrico Granata bool success = true;
264643c012SEnrico Granata OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
274643c012SEnrico Granata
28a449698cSZachary Turner if (options_args.size() < 1)
294643c012SEnrico Granata return true;
304643c012SEnrico Granata
314643c012SEnrico Granata Args args(options_args);
32a449698cSZachary Turner std::string options_string(options_args);
331abaeeceSPavel Labath // TODO: Find a way to propagate errors in this CommandReturnObject up the
341abaeeceSPavel Labath // stack.
35de019b88SJonas Devlieghere CommandReturnObject result(false);
364643c012SEnrico Granata // Check to see if the command being aliased can take any command options.
374643c012SEnrico Granata Options *options = cmd_obj_sp->GetOptions();
38b9c1b51eSKate Stone if (options) {
39b9c1b51eSKate Stone // See if any options were specified as part of the alias; if so, handle
40b9c1b51eSKate Stone // them appropriately.
41e1cfbc79STodd Fiala ExecutionContext exe_ctx =
42e1cfbc79STodd Fiala cmd_obj_sp->GetCommandInterpreter().GetExecutionContext();
43e1cfbc79STodd Fiala options->NotifyOptionParsingStarting(&exe_ctx);
445f56fca4SPavel Labath
455f56fca4SPavel Labath llvm::Expected<Args> args_or =
465f56fca4SPavel Labath options->ParseAlias(args, option_arg_vector, options_string);
475f56fca4SPavel Labath if (!args_or) {
485f56fca4SPavel Labath result.AppendError(toString(args_or.takeError()));
495f56fca4SPavel Labath result.AppendError("Unable to create requested alias.\n");
505f56fca4SPavel Labath return false;
515f56fca4SPavel Labath }
525f56fca4SPavel Labath args = std::move(*args_or);
534643c012SEnrico Granata options->VerifyPartialOptions(result);
54b9c1b51eSKate Stone if (!result.Succeeded() &&
55b9c1b51eSKate Stone result.GetStatus() != lldb::eReturnStatusStarted) {
564643c012SEnrico Granata result.AppendError("Unable to create requested alias.\n");
574643c012SEnrico Granata return false;
584643c012SEnrico Granata }
594643c012SEnrico Granata }
604643c012SEnrico Granata
61b9c1b51eSKate Stone if (!options_string.empty()) {
624643c012SEnrico Granata if (cmd_obj_sp->WantsRawCommandString())
635c28c66fSZachary Turner option_arg_vector->emplace_back("<argument>", -1, options_string);
64b9c1b51eSKate Stone else {
6597d2c401SZachary Turner for (auto &entry : args.entries()) {
660d9a201eSRaphael Isemann if (!entry.ref().empty())
675bbaf543SMartin Storsjö option_arg_vector->emplace_back(std::string("<argument>"), -1,
685bbaf543SMartin Storsjö std::string(entry.ref()));
6997d2c401SZachary Turner }
704643c012SEnrico Granata }
714643c012SEnrico Granata }
724643c012SEnrico Granata
734643c012SEnrico Granata return success;
744643c012SEnrico Granata }
754643c012SEnrico Granata
CommandAlias(CommandInterpreter & interpreter,lldb::CommandObjectSP cmd_sp,llvm::StringRef options_args,llvm::StringRef name,llvm::StringRef help,llvm::StringRef syntax,uint32_t flags)763e271af4SEnrico Granata CommandAlias::CommandAlias(CommandInterpreter &interpreter,
773e271af4SEnrico Granata lldb::CommandObjectSP cmd_sp,
78a449698cSZachary Turner llvm::StringRef options_args, llvm::StringRef name,
79a449698cSZachary Turner llvm::StringRef help, llvm::StringRef syntax,
80a449698cSZachary Turner uint32_t flags)
81b9c1b51eSKate Stone : CommandObject(interpreter, name, help, syntax, flags),
82*8cdcd41eSTatyana Krasnukha m_option_string(std::string(options_args)),
83bef55ac8SEnrico Granata m_option_args_sp(new OptionArgVector),
84b9c1b51eSKate Stone m_is_dashdash_alias(eLazyBoolCalculate), m_did_set_help(false),
85b9c1b51eSKate Stone m_did_set_help_long(false) {
86b9c1b51eSKate Stone if (ProcessAliasOptionsArgs(cmd_sp, options_args, m_option_args_sp)) {
873e271af4SEnrico Granata m_underlying_command_sp = cmd_sp;
88bef55ac8SEnrico Granata for (int i = 0;
89bef55ac8SEnrico Granata auto cmd_entry = m_underlying_command_sp->GetArgumentEntryAtIndex(i);
90b9c1b51eSKate Stone i++) {
91bef55ac8SEnrico Granata m_arguments.push_back(*cmd_entry);
92bef55ac8SEnrico Granata }
93a449698cSZachary Turner if (!help.empty()) {
943e271af4SEnrico Granata StreamString sstr;
953e271af4SEnrico Granata StreamString translation_and_help;
963e271af4SEnrico Granata GetAliasExpansion(sstr);
973e271af4SEnrico Granata
980fe35b15SZachary Turner translation_and_help.Printf(
990fe35b15SZachary Turner "(%s) %s", sstr.GetData(),
1001e8016b2SZachary Turner GetUnderlyingCommand()->GetHelp().str().c_str());
101c156427dSZachary Turner SetHelp(translation_and_help.GetString());
1023e271af4SEnrico Granata }
1033e271af4SEnrico Granata }
1044643c012SEnrico Granata }
1054643c012SEnrico Granata
WantsRawCommandString()106b9c1b51eSKate Stone bool CommandAlias::WantsRawCommandString() {
1073e271af4SEnrico Granata if (IsValid())
1083e271af4SEnrico Granata return m_underlying_command_sp->WantsRawCommandString();
1093e271af4SEnrico Granata return false;
1103e271af4SEnrico Granata }
1113e271af4SEnrico Granata
WantsCompletion()112b9c1b51eSKate Stone bool CommandAlias::WantsCompletion() {
113bef55ac8SEnrico Granata if (IsValid())
114bef55ac8SEnrico Granata return m_underlying_command_sp->WantsCompletion();
115bef55ac8SEnrico Granata return false;
116bef55ac8SEnrico Granata }
117bef55ac8SEnrico Granata
HandleCompletion(CompletionRequest & request)118ae34ed2cSRaphael Isemann void CommandAlias::HandleCompletion(CompletionRequest &request) {
119bef55ac8SEnrico Granata if (IsValid())
120ae34ed2cSRaphael Isemann m_underlying_command_sp->HandleCompletion(request);
121bef55ac8SEnrico Granata }
122bef55ac8SEnrico Granata
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)123ae34ed2cSRaphael Isemann void CommandAlias::HandleArgumentCompletion(
1242443bbd4SRaphael Isemann CompletionRequest &request, OptionElementVector &opt_element_vector) {
125bef55ac8SEnrico Granata if (IsValid())
126ae34ed2cSRaphael Isemann m_underlying_command_sp->HandleArgumentCompletion(request,
127ae34ed2cSRaphael Isemann opt_element_vector);
128bef55ac8SEnrico Granata }
129bef55ac8SEnrico Granata
GetOptions()130b9c1b51eSKate Stone Options *CommandAlias::GetOptions() {
131bef55ac8SEnrico Granata if (IsValid())
132bef55ac8SEnrico Granata return m_underlying_command_sp->GetOptions();
133bef55ac8SEnrico Granata return nullptr;
134bef55ac8SEnrico Granata }
135bef55ac8SEnrico Granata
Execute(const char * args_string,CommandReturnObject & result)136b9c1b51eSKate Stone bool CommandAlias::Execute(const char *args_string,
137b9c1b51eSKate Stone CommandReturnObject &result) {
1383e271af4SEnrico Granata llvm_unreachable("CommandAlias::Execute is not to be called");
1394643c012SEnrico Granata }
1404643c012SEnrico Granata
GetAliasExpansion(StreamString & help_string) const141a483f579SZachary Turner void CommandAlias::GetAliasExpansion(StreamString &help_string) const {
142a449698cSZachary Turner llvm::StringRef command_name = m_underlying_command_sp->GetCommandName();
143a449698cSZachary Turner help_string.Printf("'%*s", (int)command_name.size(), command_name.data());
1444643c012SEnrico Granata
1455c28c66fSZachary Turner if (!m_option_args_sp) {
1465c28c66fSZachary Turner help_string.Printf("'");
1475c28c66fSZachary Turner return;
1485c28c66fSZachary Turner }
1495c28c66fSZachary Turner
1504643c012SEnrico Granata OptionArgVector *options = m_option_args_sp.get();
1515c28c66fSZachary Turner std::string opt;
1525c28c66fSZachary Turner std::string value;
1535c28c66fSZachary Turner
1545c28c66fSZachary Turner for (const auto &opt_entry : *options) {
1555c28c66fSZachary Turner std::tie(opt, std::ignore, value) = opt_entry;
1565c28c66fSZachary Turner if (opt == "<argument>") {
1574643c012SEnrico Granata help_string.Printf(" %s", value.c_str());
158b9c1b51eSKate Stone } else {
1594643c012SEnrico Granata help_string.Printf(" %s", opt.c_str());
1608d20cfdfSJonas Devlieghere if ((value != "<no-argument>") && (value != "<need-argument")) {
1614643c012SEnrico Granata help_string.Printf(" %s", value.c_str());
1624643c012SEnrico Granata }
1634643c012SEnrico Granata }
1644643c012SEnrico Granata }
1654643c012SEnrico Granata
1664643c012SEnrico Granata help_string.Printf("'");
1674643c012SEnrico Granata }
168bef55ac8SEnrico Granata
IsDashDashCommand()169b9c1b51eSKate Stone bool CommandAlias::IsDashDashCommand() {
1705c28c66fSZachary Turner if (m_is_dashdash_alias != eLazyBoolCalculate)
1715c28c66fSZachary Turner return (m_is_dashdash_alias == eLazyBoolYes);
172bef55ac8SEnrico Granata m_is_dashdash_alias = eLazyBoolNo;
1735c28c66fSZachary Turner if (!IsValid())
1745c28c66fSZachary Turner return false;
1755c28c66fSZachary Turner
1765c28c66fSZachary Turner std::string opt;
1775c28c66fSZachary Turner std::string value;
1785c28c66fSZachary Turner
1795c28c66fSZachary Turner for (const auto &opt_entry : *GetOptionArguments()) {
1805c28c66fSZachary Turner std::tie(opt, std::ignore, value) = opt_entry;
1815c28c66fSZachary Turner if (opt == "<argument>" && !value.empty() &&
1825c28c66fSZachary Turner llvm::StringRef(value).endswith("--")) {
183bef55ac8SEnrico Granata m_is_dashdash_alias = eLazyBoolYes;
184bef55ac8SEnrico Granata break;
185bef55ac8SEnrico Granata }
186bef55ac8SEnrico Granata }
1875c28c66fSZachary Turner
18805097246SAdrian Prantl // if this is a nested alias, it may be adding arguments on top of an already
18905097246SAdrian Prantl // dash-dash alias
1903c110dd6SEnrico Granata if ((m_is_dashdash_alias == eLazyBoolNo) && IsNestedAlias())
191b9c1b51eSKate Stone m_is_dashdash_alias =
192b9c1b51eSKate Stone (GetUnderlyingCommand()->IsDashDashCommand() ? eLazyBoolYes
193b9c1b51eSKate Stone : eLazyBoolNo);
194bef55ac8SEnrico Granata return (m_is_dashdash_alias == eLazyBoolYes);
195bef55ac8SEnrico Granata }
196bef55ac8SEnrico Granata
IsNestedAlias()197b9c1b51eSKate Stone bool CommandAlias::IsNestedAlias() {
1983c110dd6SEnrico Granata if (GetUnderlyingCommand())
1993c110dd6SEnrico Granata return GetUnderlyingCommand()->IsAlias();
2003c110dd6SEnrico Granata return false;
2013c110dd6SEnrico Granata }
2023c110dd6SEnrico Granata
Desugar()203b9c1b51eSKate Stone std::pair<lldb::CommandObjectSP, OptionArgVectorSP> CommandAlias::Desugar() {
204660764a0SEnrico Granata auto underlying = GetUnderlyingCommand();
205660764a0SEnrico Granata if (!underlying)
206660764a0SEnrico Granata return {nullptr, nullptr};
207660764a0SEnrico Granata
208b9c1b51eSKate Stone if (underlying->IsAlias()) {
209660764a0SEnrico Granata auto desugared = ((CommandAlias *)underlying.get())->Desugar();
210660764a0SEnrico Granata auto options = GetOptionArguments();
211b9c1b51eSKate Stone options->insert(options->begin(), desugared.second->begin(),
212b9c1b51eSKate Stone desugared.second->end());
213660764a0SEnrico Granata return {desugared.first, options};
214660764a0SEnrico Granata }
215660764a0SEnrico Granata
216660764a0SEnrico Granata return {underlying, GetOptionArguments()};
217660764a0SEnrico Granata }
218660764a0SEnrico Granata
219b9c1b51eSKate Stone // allow CommandAlias objects to provide their own help, but fallback to the
22005097246SAdrian Prantl // info for the underlying command if no customization has been provided
SetHelp(llvm::StringRef str)221442f6530SZachary Turner void CommandAlias::SetHelp(llvm::StringRef str) {
222bfb75e9bSEnrico Granata this->CommandObject::SetHelp(str);
223bfb75e9bSEnrico Granata m_did_set_help = true;
224bfb75e9bSEnrico Granata }
225bfb75e9bSEnrico Granata
SetHelpLong(llvm::StringRef str)226442f6530SZachary Turner void CommandAlias::SetHelpLong(llvm::StringRef str) {
227bfb75e9bSEnrico Granata this->CommandObject::SetHelpLong(str);
228bfb75e9bSEnrico Granata m_did_set_help_long = true;
229bfb75e9bSEnrico Granata }
230bfb75e9bSEnrico Granata
GetHelp()231442f6530SZachary Turner llvm::StringRef CommandAlias::GetHelp() {
232bfb75e9bSEnrico Granata if (!m_cmd_help_short.empty() || m_did_set_help)
233442f6530SZachary Turner return m_cmd_help_short;
234bef55ac8SEnrico Granata if (IsValid())
235bef55ac8SEnrico Granata return m_underlying_command_sp->GetHelp();
236442f6530SZachary Turner return llvm::StringRef();
237bef55ac8SEnrico Granata }
238bef55ac8SEnrico Granata
GetHelpLong()239442f6530SZachary Turner llvm::StringRef CommandAlias::GetHelpLong() {
240bfb75e9bSEnrico Granata if (!m_cmd_help_long.empty() || m_did_set_help_long)
241442f6530SZachary Turner return m_cmd_help_long;
242bef55ac8SEnrico Granata if (IsValid())
243bef55ac8SEnrico Granata return m_underlying_command_sp->GetHelpLong();
244442f6530SZachary Turner return llvm::StringRef();
245bef55ac8SEnrico Granata }
246