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 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 result.SetStatus(eReturnStatusFailed); 515f56fca4SPavel Labath return false; 525f56fca4SPavel Labath } 535f56fca4SPavel Labath args = std::move(*args_or); 544643c012SEnrico Granata options->VerifyPartialOptions(result); 55b9c1b51eSKate Stone if (!result.Succeeded() && 56b9c1b51eSKate Stone result.GetStatus() != lldb::eReturnStatusStarted) { 574643c012SEnrico Granata result.AppendError("Unable to create requested alias.\n"); 584643c012SEnrico Granata return false; 594643c012SEnrico Granata } 604643c012SEnrico Granata } 614643c012SEnrico Granata 62b9c1b51eSKate Stone if (!options_string.empty()) { 634643c012SEnrico Granata if (cmd_obj_sp->WantsRawCommandString()) 645c28c66fSZachary Turner option_arg_vector->emplace_back("<argument>", -1, options_string); 65b9c1b51eSKate Stone else { 6697d2c401SZachary Turner for (auto &entry : args.entries()) { 670d9a201eSRaphael Isemann if (!entry.ref().empty()) 685bbaf543SMartin Storsjö option_arg_vector->emplace_back(std::string("<argument>"), -1, 695bbaf543SMartin Storsjö std::string(entry.ref())); 7097d2c401SZachary Turner } 714643c012SEnrico Granata } 724643c012SEnrico Granata } 734643c012SEnrico Granata 744643c012SEnrico Granata return success; 754643c012SEnrico Granata } 764643c012SEnrico Granata 773e271af4SEnrico Granata CommandAlias::CommandAlias(CommandInterpreter &interpreter, 783e271af4SEnrico Granata lldb::CommandObjectSP cmd_sp, 79a449698cSZachary Turner llvm::StringRef options_args, llvm::StringRef name, 80a449698cSZachary Turner llvm::StringRef help, llvm::StringRef syntax, 81a449698cSZachary Turner uint32_t flags) 82b9c1b51eSKate Stone : CommandObject(interpreter, name, help, syntax, flags), 83*8cdcd41eSTatyana Krasnukha m_option_string(std::string(options_args)), 84bef55ac8SEnrico Granata m_option_args_sp(new OptionArgVector), 85b9c1b51eSKate Stone m_is_dashdash_alias(eLazyBoolCalculate), m_did_set_help(false), 86b9c1b51eSKate Stone m_did_set_help_long(false) { 87b9c1b51eSKate Stone if (ProcessAliasOptionsArgs(cmd_sp, options_args, m_option_args_sp)) { 883e271af4SEnrico Granata m_underlying_command_sp = cmd_sp; 89bef55ac8SEnrico Granata for (int i = 0; 90bef55ac8SEnrico Granata auto cmd_entry = m_underlying_command_sp->GetArgumentEntryAtIndex(i); 91b9c1b51eSKate Stone i++) { 92bef55ac8SEnrico Granata m_arguments.push_back(*cmd_entry); 93bef55ac8SEnrico Granata } 94a449698cSZachary Turner if (!help.empty()) { 953e271af4SEnrico Granata StreamString sstr; 963e271af4SEnrico Granata StreamString translation_and_help; 973e271af4SEnrico Granata GetAliasExpansion(sstr); 983e271af4SEnrico Granata 990fe35b15SZachary Turner translation_and_help.Printf( 1000fe35b15SZachary Turner "(%s) %s", sstr.GetData(), 1011e8016b2SZachary Turner GetUnderlyingCommand()->GetHelp().str().c_str()); 102c156427dSZachary Turner SetHelp(translation_and_help.GetString()); 1033e271af4SEnrico Granata } 1043e271af4SEnrico Granata } 1054643c012SEnrico Granata } 1064643c012SEnrico Granata 107b9c1b51eSKate Stone bool CommandAlias::WantsRawCommandString() { 1083e271af4SEnrico Granata if (IsValid()) 1093e271af4SEnrico Granata return m_underlying_command_sp->WantsRawCommandString(); 1103e271af4SEnrico Granata return false; 1113e271af4SEnrico Granata } 1123e271af4SEnrico Granata 113b9c1b51eSKate Stone bool CommandAlias::WantsCompletion() { 114bef55ac8SEnrico Granata if (IsValid()) 115bef55ac8SEnrico Granata return m_underlying_command_sp->WantsCompletion(); 116bef55ac8SEnrico Granata return false; 117bef55ac8SEnrico Granata } 118bef55ac8SEnrico Granata 119ae34ed2cSRaphael Isemann void CommandAlias::HandleCompletion(CompletionRequest &request) { 120bef55ac8SEnrico Granata if (IsValid()) 121ae34ed2cSRaphael Isemann m_underlying_command_sp->HandleCompletion(request); 122bef55ac8SEnrico Granata } 123bef55ac8SEnrico Granata 124ae34ed2cSRaphael Isemann void CommandAlias::HandleArgumentCompletion( 1252443bbd4SRaphael Isemann CompletionRequest &request, OptionElementVector &opt_element_vector) { 126bef55ac8SEnrico Granata if (IsValid()) 127ae34ed2cSRaphael Isemann m_underlying_command_sp->HandleArgumentCompletion(request, 128ae34ed2cSRaphael Isemann opt_element_vector); 129bef55ac8SEnrico Granata } 130bef55ac8SEnrico Granata 131b9c1b51eSKate Stone Options *CommandAlias::GetOptions() { 132bef55ac8SEnrico Granata if (IsValid()) 133bef55ac8SEnrico Granata return m_underlying_command_sp->GetOptions(); 134bef55ac8SEnrico Granata return nullptr; 135bef55ac8SEnrico Granata } 136bef55ac8SEnrico Granata 137b9c1b51eSKate Stone bool CommandAlias::Execute(const char *args_string, 138b9c1b51eSKate Stone CommandReturnObject &result) { 1393e271af4SEnrico Granata llvm_unreachable("CommandAlias::Execute is not to be called"); 1404643c012SEnrico Granata } 1414643c012SEnrico Granata 142a483f579SZachary Turner void CommandAlias::GetAliasExpansion(StreamString &help_string) const { 143a449698cSZachary Turner llvm::StringRef command_name = m_underlying_command_sp->GetCommandName(); 144a449698cSZachary Turner help_string.Printf("'%*s", (int)command_name.size(), command_name.data()); 1454643c012SEnrico Granata 1465c28c66fSZachary Turner if (!m_option_args_sp) { 1475c28c66fSZachary Turner help_string.Printf("'"); 1485c28c66fSZachary Turner return; 1495c28c66fSZachary Turner } 1505c28c66fSZachary Turner 1514643c012SEnrico Granata OptionArgVector *options = m_option_args_sp.get(); 1525c28c66fSZachary Turner std::string opt; 1535c28c66fSZachary Turner std::string value; 1545c28c66fSZachary Turner 1555c28c66fSZachary Turner for (const auto &opt_entry : *options) { 1565c28c66fSZachary Turner std::tie(opt, std::ignore, value) = opt_entry; 1575c28c66fSZachary Turner if (opt == "<argument>") { 1584643c012SEnrico Granata help_string.Printf(" %s", value.c_str()); 159b9c1b51eSKate Stone } else { 1604643c012SEnrico Granata help_string.Printf(" %s", opt.c_str()); 1618d20cfdfSJonas Devlieghere if ((value != "<no-argument>") && (value != "<need-argument")) { 1624643c012SEnrico Granata help_string.Printf(" %s", value.c_str()); 1634643c012SEnrico Granata } 1644643c012SEnrico Granata } 1654643c012SEnrico Granata } 1664643c012SEnrico Granata 1674643c012SEnrico Granata help_string.Printf("'"); 1684643c012SEnrico Granata } 169bef55ac8SEnrico Granata 170b9c1b51eSKate Stone bool CommandAlias::IsDashDashCommand() { 1715c28c66fSZachary Turner if (m_is_dashdash_alias != eLazyBoolCalculate) 1725c28c66fSZachary Turner return (m_is_dashdash_alias == eLazyBoolYes); 173bef55ac8SEnrico Granata m_is_dashdash_alias = eLazyBoolNo; 1745c28c66fSZachary Turner if (!IsValid()) 1755c28c66fSZachary Turner return false; 1765c28c66fSZachary Turner 1775c28c66fSZachary Turner std::string opt; 1785c28c66fSZachary Turner std::string value; 1795c28c66fSZachary Turner 1805c28c66fSZachary Turner for (const auto &opt_entry : *GetOptionArguments()) { 1815c28c66fSZachary Turner std::tie(opt, std::ignore, value) = opt_entry; 1825c28c66fSZachary Turner if (opt == "<argument>" && !value.empty() && 1835c28c66fSZachary Turner llvm::StringRef(value).endswith("--")) { 184bef55ac8SEnrico Granata m_is_dashdash_alias = eLazyBoolYes; 185bef55ac8SEnrico Granata break; 186bef55ac8SEnrico Granata } 187bef55ac8SEnrico Granata } 1885c28c66fSZachary Turner 18905097246SAdrian Prantl // if this is a nested alias, it may be adding arguments on top of an already 19005097246SAdrian Prantl // dash-dash alias 1913c110dd6SEnrico Granata if ((m_is_dashdash_alias == eLazyBoolNo) && IsNestedAlias()) 192b9c1b51eSKate Stone m_is_dashdash_alias = 193b9c1b51eSKate Stone (GetUnderlyingCommand()->IsDashDashCommand() ? eLazyBoolYes 194b9c1b51eSKate Stone : eLazyBoolNo); 195bef55ac8SEnrico Granata return (m_is_dashdash_alias == eLazyBoolYes); 196bef55ac8SEnrico Granata } 197bef55ac8SEnrico Granata 198b9c1b51eSKate Stone bool CommandAlias::IsNestedAlias() { 1993c110dd6SEnrico Granata if (GetUnderlyingCommand()) 2003c110dd6SEnrico Granata return GetUnderlyingCommand()->IsAlias(); 2013c110dd6SEnrico Granata return false; 2023c110dd6SEnrico Granata } 2033c110dd6SEnrico Granata 204b9c1b51eSKate Stone std::pair<lldb::CommandObjectSP, OptionArgVectorSP> CommandAlias::Desugar() { 205660764a0SEnrico Granata auto underlying = GetUnderlyingCommand(); 206660764a0SEnrico Granata if (!underlying) 207660764a0SEnrico Granata return {nullptr, nullptr}; 208660764a0SEnrico Granata 209b9c1b51eSKate Stone if (underlying->IsAlias()) { 210660764a0SEnrico Granata auto desugared = ((CommandAlias *)underlying.get())->Desugar(); 211660764a0SEnrico Granata auto options = GetOptionArguments(); 212b9c1b51eSKate Stone options->insert(options->begin(), desugared.second->begin(), 213b9c1b51eSKate Stone desugared.second->end()); 214660764a0SEnrico Granata return {desugared.first, options}; 215660764a0SEnrico Granata } 216660764a0SEnrico Granata 217660764a0SEnrico Granata return {underlying, GetOptionArguments()}; 218660764a0SEnrico Granata } 219660764a0SEnrico Granata 220b9c1b51eSKate Stone // allow CommandAlias objects to provide their own help, but fallback to the 22105097246SAdrian Prantl // info for the underlying command if no customization has been provided 222442f6530SZachary Turner void CommandAlias::SetHelp(llvm::StringRef str) { 223bfb75e9bSEnrico Granata this->CommandObject::SetHelp(str); 224bfb75e9bSEnrico Granata m_did_set_help = true; 225bfb75e9bSEnrico Granata } 226bfb75e9bSEnrico Granata 227442f6530SZachary Turner void CommandAlias::SetHelpLong(llvm::StringRef str) { 228bfb75e9bSEnrico Granata this->CommandObject::SetHelpLong(str); 229bfb75e9bSEnrico Granata m_did_set_help_long = true; 230bfb75e9bSEnrico Granata } 231bfb75e9bSEnrico Granata 232442f6530SZachary Turner llvm::StringRef CommandAlias::GetHelp() { 233bfb75e9bSEnrico Granata if (!m_cmd_help_short.empty() || m_did_set_help) 234442f6530SZachary Turner return m_cmd_help_short; 235bef55ac8SEnrico Granata if (IsValid()) 236bef55ac8SEnrico Granata return m_underlying_command_sp->GetHelp(); 237442f6530SZachary Turner return llvm::StringRef(); 238bef55ac8SEnrico Granata } 239bef55ac8SEnrico Granata 240442f6530SZachary Turner llvm::StringRef CommandAlias::GetHelpLong() { 241bfb75e9bSEnrico Granata if (!m_cmd_help_long.empty() || m_did_set_help_long) 242442f6530SZachary Turner return m_cmd_help_long; 243bef55ac8SEnrico Granata if (IsValid()) 244bef55ac8SEnrico Granata return m_underlying_command_sp->GetHelpLong(); 245442f6530SZachary Turner return llvm::StringRef(); 246bef55ac8SEnrico Granata } 247