130fdc8d8SChris Lattner //===-- CommandObjectHelp.cpp -----------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner 
1030fdc8d8SChris Lattner // C Includes
1130fdc8d8SChris Lattner // C++ Includes
1230fdc8d8SChris Lattner // Other libraries and framework includes
1330fdc8d8SChris Lattner // Project includes
1426cac3afSEugene Zelenko #include "CommandObjectHelp.h"
1530fdc8d8SChris Lattner #include "lldb/Interpreter/CommandObjectMultiword.h"
1630fdc8d8SChris Lattner #include "lldb/Interpreter/CommandInterpreter.h"
1740af72e1SJim Ingham #include "lldb/Interpreter/Options.h"
1830fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h"
1930fdc8d8SChris Lattner 
2030fdc8d8SChris Lattner using namespace lldb;
2130fdc8d8SChris Lattner using namespace lldb_private;
2230fdc8d8SChris Lattner 
2330fdc8d8SChris Lattner //-------------------------------------------------------------------------
2430fdc8d8SChris Lattner // CommandObjectHelp
2530fdc8d8SChris Lattner //-------------------------------------------------------------------------
2630fdc8d8SChris Lattner 
2746d4aa21SEnrico Granata void
2846d4aa21SEnrico Granata CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage (Stream *s,
2946d4aa21SEnrico Granata                                                          const char* command,
3046d4aa21SEnrico Granata                                                          const char* prefix,
3146d4aa21SEnrico Granata                                                          const char* subcommand,
3246d4aa21SEnrico Granata                                                          bool include_apropos,
3346d4aa21SEnrico Granata                                                          bool include_type_lookup)
3446d4aa21SEnrico Granata {
3546d4aa21SEnrico Granata     if (s && command && *command)
3646d4aa21SEnrico Granata     {
3746d4aa21SEnrico Granata         s->Printf("'%s' is not a known command.\n", command);
3846d4aa21SEnrico Granata         if (prefix && *prefix)
3946d4aa21SEnrico Granata         {
4046d4aa21SEnrico Granata             s->Printf("Try '%shelp' to see a current list of commands.\n", prefix);
4146d4aa21SEnrico Granata         }
4246d4aa21SEnrico Granata         else
4346d4aa21SEnrico Granata         {
4446d4aa21SEnrico Granata             s->PutCString("Try 'help' to see a current list of commands.\n");
4546d4aa21SEnrico Granata         }
4646d4aa21SEnrico Granata 
4746d4aa21SEnrico Granata         if (include_apropos)
4846d4aa21SEnrico Granata         {
4946d4aa21SEnrico Granata             s->Printf("Try 'apropos %s' for a list of related commands.\n", subcommand ? subcommand : command);
5046d4aa21SEnrico Granata         }
5146d4aa21SEnrico Granata         if (include_type_lookup)
5246d4aa21SEnrico Granata         {
5346d4aa21SEnrico Granata             s->Printf("Try 'type lookup %s' for information on types, methods, functions, modules, etc.", subcommand ? subcommand : command);
5446d4aa21SEnrico Granata         }
5546d4aa21SEnrico Granata     }
5646d4aa21SEnrico Granata }
5746d4aa21SEnrico Granata 
58a7015092SGreg Clayton CommandObjectHelp::CommandObjectHelp (CommandInterpreter &interpreter) :
595a988416SJim Ingham     CommandObjectParsed (interpreter,
60a7015092SGreg Clayton                          "help",
613f4c09c1SCaroline Tice                          "Show a list of all debugger commands, or give details about specific commands.",
6208633eeaSEnrico Granata                          "help [<cmd-name>]"), m_options (interpreter)
6330fdc8d8SChris Lattner {
64405fe67fSCaroline Tice     CommandArgumentEntry arg;
65405fe67fSCaroline Tice     CommandArgumentData command_arg;
66405fe67fSCaroline Tice 
67405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
68405fe67fSCaroline Tice     command_arg.arg_type = eArgTypeCommandName;
69405fe67fSCaroline Tice     command_arg.arg_repetition = eArgRepeatStar;
70405fe67fSCaroline Tice 
71405fe67fSCaroline Tice     // There is only one variant this argument could be; put it into the argument entry.
72405fe67fSCaroline Tice     arg.push_back (command_arg);
73405fe67fSCaroline Tice 
74405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
75405fe67fSCaroline Tice     m_arguments.push_back (arg);
7630fdc8d8SChris Lattner }
7730fdc8d8SChris Lattner 
7826cac3afSEugene Zelenko CommandObjectHelp::~CommandObjectHelp() = default;
7930fdc8d8SChris Lattner 
8008633eeaSEnrico Granata OptionDefinition
8108633eeaSEnrico Granata CommandObjectHelp::CommandOptions::g_option_table[] =
8208633eeaSEnrico Granata {
8326cac3afSEugene Zelenko     { LLDB_OPT_SET_ALL, false, "hide-aliases", 'a', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone,         "Hide aliases in the command list."},
8426cac3afSEugene Zelenko     { LLDB_OPT_SET_ALL, false, "hide-user-commands", 'u', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone,         "Hide user-defined commands from the list."},
8526cac3afSEugene Zelenko     { LLDB_OPT_SET_ALL, false, "show-hidden-commands", 'h', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone,         "Include commands prefixed with an underscore."},
8626cac3afSEugene Zelenko     { 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr }
8708633eeaSEnrico Granata };
8808633eeaSEnrico Granata 
8930fdc8d8SChris Lattner bool
905a988416SJim Ingham CommandObjectHelp::DoExecute (Args& command, CommandReturnObject &result)
9130fdc8d8SChris Lattner {
9230fdc8d8SChris Lattner     CommandObject::CommandMap::iterator pos;
9330fdc8d8SChris Lattner     CommandObject *cmd_obj;
94c7bece56SGreg Clayton     const size_t argc = command.GetArgumentCount ();
9530fdc8d8SChris Lattner 
9608633eeaSEnrico Granata     // 'help' doesn't take any arguments, other than command names.  If argc is 0, we show the user
9708633eeaSEnrico Granata     // all commands (aliases and user commands if asked for).  Otherwise every argument must be the name of a command or a sub-command.
9830fdc8d8SChris Lattner     if (argc == 0)
9930fdc8d8SChris Lattner     {
10008633eeaSEnrico Granata         uint32_t cmd_types = CommandInterpreter::eCommandTypesBuiltin;
10108633eeaSEnrico Granata         if (m_options.m_show_aliases)
10208633eeaSEnrico Granata             cmd_types |= CommandInterpreter::eCommandTypesAliases;
10308633eeaSEnrico Granata         if (m_options.m_show_user_defined)
10408633eeaSEnrico Granata             cmd_types |= CommandInterpreter::eCommandTypesUserDef;
105a487aa4cSKate Stone         if (m_options.m_show_hidden)
106a487aa4cSKate Stone             cmd_types |= CommandInterpreter::eCommandTypesHidden;
10708633eeaSEnrico Granata 
10830fdc8d8SChris Lattner         result.SetStatus (eReturnStatusSuccessFinishNoResult);
10908633eeaSEnrico Granata         m_interpreter.GetHelp (result, cmd_types);  // General help
11030fdc8d8SChris Lattner     }
11130fdc8d8SChris Lattner     else
11230fdc8d8SChris Lattner     {
11330fdc8d8SChris Lattner         // Get command object for the first command argument. Only search built-in command dictionary.
114279a6c26SJim Ingham         StringList matches;
115a7015092SGreg Clayton         cmd_obj = m_interpreter.GetCommandObject (command.GetArgumentAtIndex (0), &matches);
116e7941795SCaroline Tice         bool is_alias_command = m_interpreter.AliasExists (command.GetArgumentAtIndex (0));
117e7941795SCaroline Tice         std::string alias_name = command.GetArgumentAtIndex(0);
11830fdc8d8SChris Lattner 
11926cac3afSEugene Zelenko         if (cmd_obj != nullptr)
12030fdc8d8SChris Lattner         {
121271ad29aSJim Ingham             StringList matches;
12230fdc8d8SChris Lattner             bool all_okay = true;
12330fdc8d8SChris Lattner             CommandObject *sub_cmd_obj = cmd_obj;
12430fdc8d8SChris Lattner             // Loop down through sub_command dictionaries until we find the command object that corresponds
12530fdc8d8SChris Lattner             // to the help command entered.
12646d4aa21SEnrico Granata             std::string sub_command;
127a297a97eSAndy Gibbs             for (size_t i = 1; i < argc && all_okay; ++i)
12830fdc8d8SChris Lattner             {
12946d4aa21SEnrico Granata                 sub_command = command.GetArgumentAtIndex(i);
130271ad29aSJim Ingham                 matches.Clear();
131*bef55ac8SEnrico Granata                 if (sub_cmd_obj->IsAlias())
132*bef55ac8SEnrico Granata                     sub_cmd_obj = ((CommandAlias*)sub_cmd_obj)->GetUnderlyingCommand().get();
13330fdc8d8SChris Lattner                 if (! sub_cmd_obj->IsMultiwordObject ())
13430fdc8d8SChris Lattner                 {
13530fdc8d8SChris Lattner                     all_okay = false;
13630fdc8d8SChris Lattner                 }
13730fdc8d8SChris Lattner                 else
13830fdc8d8SChris Lattner                 {
139271ad29aSJim Ingham                     CommandObject *found_cmd;
140998255bfSGreg Clayton                     found_cmd = sub_cmd_obj->GetSubcommandObject(sub_command.c_str(), &matches);
14126cac3afSEugene Zelenko                     if (found_cmd == nullptr)
14230fdc8d8SChris Lattner                         all_okay = false;
14397253e62SJim Ingham                     else if (matches.GetSize() > 1)
144271ad29aSJim Ingham                         all_okay = false;
145271ad29aSJim Ingham                     else
146271ad29aSJim Ingham                         sub_cmd_obj = found_cmd;
14730fdc8d8SChris Lattner                 }
14830fdc8d8SChris Lattner             }
14930fdc8d8SChris Lattner 
15026cac3afSEugene Zelenko             if (!all_okay || (sub_cmd_obj == nullptr))
15130fdc8d8SChris Lattner             {
15230fdc8d8SChris Lattner                 std::string cmd_string;
15330fdc8d8SChris Lattner                 command.GetCommandString (cmd_string);
1549b62d1d5SEnrico Granata                 if (matches.GetSize() >= 2)
155271ad29aSJim Ingham                 {
156271ad29aSJim Ingham                     StreamString s;
157271ad29aSJim Ingham                     s.Printf ("ambiguous command %s", cmd_string.c_str());
158271ad29aSJim Ingham                     size_t num_matches = matches.GetSize();
159271ad29aSJim Ingham                     for (size_t match_idx = 0; match_idx < num_matches; match_idx++)
160271ad29aSJim Ingham                     {
161271ad29aSJim Ingham                         s.Printf ("\n\t%s", matches.GetStringAtIndex(match_idx));
162271ad29aSJim Ingham                     }
163271ad29aSJim Ingham                     s.Printf ("\n");
164271ad29aSJim Ingham                     result.AppendError(s.GetData());
16530fdc8d8SChris Lattner                     result.SetStatus (eReturnStatusFailed);
1669b62d1d5SEnrico Granata                     return false;
1679b62d1d5SEnrico Granata                 }
1689b62d1d5SEnrico Granata                 else if (!sub_cmd_obj)
1699b62d1d5SEnrico Granata                 {
17046d4aa21SEnrico Granata                     StreamString error_msg_stream;
17146d4aa21SEnrico Granata                     GenerateAdditionalHelpAvenuesMessage(&error_msg_stream,
172a487aa4cSKate Stone                                                          cmd_string.c_str(),
17346d4aa21SEnrico Granata                                                          m_interpreter.GetCommandPrefix(),
17446d4aa21SEnrico Granata                                                          sub_command.c_str());
17546d4aa21SEnrico Granata                     result.AppendErrorWithFormat("%s",error_msg_stream.GetData());
1769b62d1d5SEnrico Granata                     result.SetStatus (eReturnStatusFailed);
1779b62d1d5SEnrico Granata                     return false;
17830fdc8d8SChris Lattner                 }
17930fdc8d8SChris Lattner                 else
18030fdc8d8SChris Lattner                 {
18146d4aa21SEnrico Granata                     GenerateAdditionalHelpAvenuesMessage(&result.GetOutputStream(),
1829b62d1d5SEnrico Granata                                                          cmd_string.c_str(),
183a487aa4cSKate Stone                                                          m_interpreter.GetCommandPrefix(),
18446d4aa21SEnrico Granata                                                          sub_command.c_str());
18546d4aa21SEnrico Granata                     result.GetOutputStream().Printf("\nThe closest match is '%s'. Help on it follows.\n\n", sub_cmd_obj->GetCommandName());
186e139cf23SCaroline Tice                 }
187c007e846SJim Ingham             }
188c007e846SJim Ingham 
189998255bfSGreg Clayton             sub_cmd_obj->GenerateHelpText(result);
190e7941795SCaroline Tice 
191e7941795SCaroline Tice             if (is_alias_command)
192e7941795SCaroline Tice             {
193e7941795SCaroline Tice                 StreamString sstr;
1944643c012SEnrico Granata                 m_interpreter.GetAlias(alias_name.c_str())->GetAliasExpansion(sstr);
195e7941795SCaroline Tice                 result.GetOutputStream().Printf ("\n'%s' is an abbreviation for %s\n", alias_name.c_str(), sstr.GetData());
196e7941795SCaroline Tice             }
19730fdc8d8SChris Lattner         }
198279a6c26SJim Ingham         else if (matches.GetSize() > 0)
199279a6c26SJim Ingham         {
200279a6c26SJim Ingham             Stream &output_strm = result.GetOutputStream();
201279a6c26SJim Ingham             output_strm.Printf("Help requested with ambiguous command name, possible completions:\n");
202c7bece56SGreg Clayton             const size_t match_count = matches.GetSize();
203c7bece56SGreg Clayton             for (size_t i = 0; i < match_count; i++)
204279a6c26SJim Ingham             {
205279a6c26SJim Ingham                 output_strm.Printf("\t%s\n", matches.GetStringAtIndex(i));
206279a6c26SJim Ingham             }
207279a6c26SJim Ingham         }
20830fdc8d8SChris Lattner         else
20930fdc8d8SChris Lattner         {
210e139cf23SCaroline Tice             // Maybe the user is asking for help about a command argument rather than a command.
211e139cf23SCaroline Tice             const CommandArgumentType arg_type = CommandObject::LookupArgumentName (command.GetArgumentAtIndex (0));
212e139cf23SCaroline Tice             if (arg_type != eArgTypeLastArg)
213e139cf23SCaroline Tice             {
214e139cf23SCaroline Tice                 Stream &output_strm = result.GetOutputStream ();
215e139cf23SCaroline Tice                 CommandObject::GetArgumentHelp (output_strm, arg_type, m_interpreter);
216e139cf23SCaroline Tice                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
217e139cf23SCaroline Tice             }
218e139cf23SCaroline Tice             else
219e139cf23SCaroline Tice             {
22046d4aa21SEnrico Granata                 StreamString error_msg_stream;
22146d4aa21SEnrico Granata                 GenerateAdditionalHelpAvenuesMessage(&error_msg_stream, command.GetArgumentAtIndex(0), m_interpreter.GetCommandPrefix());
22246d4aa21SEnrico Granata                 result.AppendErrorWithFormat("%s",error_msg_stream.GetData());
22330fdc8d8SChris Lattner                 result.SetStatus (eReturnStatusFailed);
22430fdc8d8SChris Lattner             }
22530fdc8d8SChris Lattner         }
226e139cf23SCaroline Tice     }
22730fdc8d8SChris Lattner 
22830fdc8d8SChris Lattner     return result.Succeeded();
22930fdc8d8SChris Lattner }
23030fdc8d8SChris Lattner 
23130fdc8d8SChris Lattner int
23226cac3afSEugene Zelenko CommandObjectHelp::HandleCompletion(Args &input,
23330fdc8d8SChris Lattner                                     int &cursor_index,
23430fdc8d8SChris Lattner                                     int &cursor_char_position,
23530fdc8d8SChris Lattner                                     int match_start_point,
23630fdc8d8SChris Lattner                                     int max_return_elements,
237558ce124SJim Ingham                                     bool &word_complete,
23826cac3afSEugene Zelenko                                     StringList &matches)
23930fdc8d8SChris Lattner {
24030fdc8d8SChris Lattner     // Return the completions of the commands in the help system:
24130fdc8d8SChris Lattner     if (cursor_index == 0)
24230fdc8d8SChris Lattner     {
243a7015092SGreg Clayton         return m_interpreter.HandleCompletionMatches (input,
244a7015092SGreg Clayton                                                     cursor_index,
245a7015092SGreg Clayton                                                     cursor_char_position,
246a7015092SGreg Clayton                                                     match_start_point,
247a7015092SGreg Clayton                                                     max_return_elements,
248a7015092SGreg Clayton                                                     word_complete,
249a7015092SGreg Clayton                                                     matches);
25030fdc8d8SChris Lattner     }
25130fdc8d8SChris Lattner     else
25230fdc8d8SChris Lattner     {
253a7015092SGreg Clayton         CommandObject *cmd_obj = m_interpreter.GetCommandObject (input.GetArgumentAtIndex(0));
2541d18ebf6SJim Ingham 
2551d18ebf6SJim Ingham         // The command that they are getting help on might be ambiguous, in which case we should complete that,
2561d18ebf6SJim Ingham         // otherwise complete with the command the user is getting help on...
2571d18ebf6SJim Ingham 
2581d18ebf6SJim Ingham         if (cmd_obj)
2591d18ebf6SJim Ingham         {
26030fdc8d8SChris Lattner             input.Shift();
26130fdc8d8SChris Lattner             cursor_index--;
262a7015092SGreg Clayton             return cmd_obj->HandleCompletion (input,
263a7015092SGreg Clayton                                               cursor_index,
264a7015092SGreg Clayton                                               cursor_char_position,
265a7015092SGreg Clayton                                               match_start_point,
266a7015092SGreg Clayton                                               max_return_elements,
267a7015092SGreg Clayton                                               word_complete,
268a7015092SGreg Clayton                                               matches);
26930fdc8d8SChris Lattner         }
2701d18ebf6SJim Ingham         else
2711d18ebf6SJim Ingham         {
2721d18ebf6SJim Ingham             return m_interpreter.HandleCompletionMatches (input,
2731d18ebf6SJim Ingham                                                         cursor_index,
2741d18ebf6SJim Ingham                                                         cursor_char_position,
2751d18ebf6SJim Ingham                                                         match_start_point,
2761d18ebf6SJim Ingham                                                         max_return_elements,
2771d18ebf6SJim Ingham                                                         word_complete,
2781d18ebf6SJim Ingham                                                         matches);
2791d18ebf6SJim Ingham         }
2801d18ebf6SJim Ingham     }
28130fdc8d8SChris Lattner }
282