1 //===-- CommandObjectHelp.cpp -----------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "CommandObjectHelp.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Interpreter/CommandObjectMultiword.h"
17 #include "lldb/Interpreter/CommandInterpreter.h"
18 #include "lldb/Interpreter/Options.h"
19 #include "lldb/Interpreter/CommandReturnObject.h"
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 
24 //-------------------------------------------------------------------------
25 // CommandObjectHelp
26 //-------------------------------------------------------------------------
27 
28 CommandObjectHelp::CommandObjectHelp (CommandInterpreter &interpreter) :
29     CommandObject (interpreter,
30                    "help",
31                    "Show a list of all debugger commands, or give details about specific commands.",
32                    "help [<cmd-name>]")
33 {
34     CommandArgumentEntry arg;
35     CommandArgumentData command_arg;
36 
37     // Define the first (and only) variant of this arg.
38     command_arg.arg_type = eArgTypeCommandName;
39     command_arg.arg_repetition = eArgRepeatStar;
40 
41     // There is only one variant this argument could be; put it into the argument entry.
42     arg.push_back (command_arg);
43 
44     // Push the data for the first argument into the m_arguments vector.
45     m_arguments.push_back (arg);
46 }
47 
48 CommandObjectHelp::~CommandObjectHelp()
49 {
50 }
51 
52 
53 bool
54 CommandObjectHelp::Execute (Args& command, CommandReturnObject &result)
55 {
56     CommandObject::CommandMap::iterator pos;
57     CommandObject *cmd_obj;
58     const int argc = command.GetArgumentCount ();
59 
60     // 'help' doesn't take any options or arguments, other than command names.  If argc is 0, we show the user
61     // all commands and aliases.  Otherwise every argument must be the name of a command or a sub-command.
62     if (argc == 0)
63     {
64         result.SetStatus (eReturnStatusSuccessFinishNoResult);
65         m_interpreter.GetHelp (result);  // General help, for ALL commands.
66     }
67     else
68     {
69         // Get command object for the first command argument. Only search built-in command dictionary.
70         StringList matches;
71         cmd_obj = m_interpreter.GetCommandObject (command.GetArgumentAtIndex (0), &matches);
72         bool is_alias_command = m_interpreter.AliasExists (command.GetArgumentAtIndex (0));
73         std::string alias_name = command.GetArgumentAtIndex(0);
74 
75         if (cmd_obj != NULL)
76         {
77             bool all_okay = true;
78             CommandObject *sub_cmd_obj = cmd_obj;
79             // Loop down through sub_command dictionaries until we find the command object that corresponds
80             // to the help command entered.
81             for (int i = 1; i < argc && all_okay; ++i)
82             {
83                 std::string sub_command = command.GetArgumentAtIndex(i);
84                 if (! sub_cmd_obj->IsMultiwordObject ())
85                 {
86                     all_okay = false;
87                 }
88                 else
89                 {
90                     pos = ((CommandObjectMultiword *) sub_cmd_obj)->m_subcommand_dict.find (sub_command);
91                     if (pos != ((CommandObjectMultiword *) sub_cmd_obj)->m_subcommand_dict.end())
92                         sub_cmd_obj = pos->second.get();
93                     else
94                         all_okay = false;
95                 }
96             }
97 
98             if (!all_okay || (sub_cmd_obj == NULL))
99             {
100                 std::string cmd_string;
101                 command.GetCommandString (cmd_string);
102                 result.AppendErrorWithFormat
103                 ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n",
104                  cmd_string.c_str());
105                 result.SetStatus (eReturnStatusFailed);
106             }
107             else
108             {
109                 Stream &output_strm = result.GetOutputStream();
110                 if (sub_cmd_obj->GetOptions() != NULL)
111                 {
112                     if (sub_cmd_obj->WantsRawCommandString())
113                     {
114                         std::string help_text (sub_cmd_obj->GetHelp());
115                         help_text.append ("  This command takes 'raw' input (no need to quote stuff).");
116                         m_interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1);
117                     }
118                     else
119                         m_interpreter.OutputFormattedHelpText (output_strm, "", "", sub_cmd_obj->GetHelp(), 1);
120                     output_strm.Printf ("\nSyntax: %s\n", sub_cmd_obj->GetSyntax());
121                     sub_cmd_obj->GetOptions()->GenerateOptionUsage (m_interpreter, output_strm, sub_cmd_obj);
122                     const char *long_help = sub_cmd_obj->GetHelpLong();
123                     if ((long_help != NULL)
124                         && (strlen (long_help) > 0))
125                         output_strm.Printf ("\n%s", long_help);
126                     // Mark this help command with a success status.
127                     result.SetStatus (eReturnStatusSuccessFinishNoResult);
128                 }
129                 else if (sub_cmd_obj->IsMultiwordObject())
130                 {
131                     if (sub_cmd_obj->WantsRawCommandString())
132                     {
133                         std::string help_text (sub_cmd_obj->GetHelp());
134                         help_text.append ("  This command takes 'raw' input (no need to quote stuff).");
135                         m_interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1);
136                     }
137                     else
138                         m_interpreter.OutputFormattedHelpText (output_strm, "", "", sub_cmd_obj->GetHelp(), 1);
139                     ((CommandObjectMultiword *) sub_cmd_obj)->GenerateHelpText (result);
140                 }
141                 else
142                 {
143                     const char *long_help = sub_cmd_obj->GetHelpLong();
144                     if ((long_help != NULL)
145                         && (strlen (long_help) > 0))
146                         output_strm.Printf ("\n%s", long_help);
147                     else if (sub_cmd_obj->WantsRawCommandString())
148                     {
149                         std::string help_text (sub_cmd_obj->GetHelp());
150                         help_text.append ("  This command takes 'raw' input (no need to quote stuff).");
151                         m_interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1);
152                     }
153                     else
154                         m_interpreter.OutputFormattedHelpText (output_strm, "", "", sub_cmd_obj->GetHelp(), 1);
155                     output_strm.Printf ("\nSyntax: %s\n", sub_cmd_obj->GetSyntax());
156                     // Mark this help command with a success status.
157                     result.SetStatus (eReturnStatusSuccessFinishNoResult);
158                 }
159             }
160 
161             if (is_alias_command)
162             {
163                 StreamString sstr;
164                 m_interpreter.GetAliasHelp (alias_name.c_str(), cmd_obj->GetCommandName(), sstr);
165                 result.GetOutputStream().Printf ("\n'%s' is an abbreviation for %s\n", alias_name.c_str(), sstr.GetData());
166             }
167         }
168         else if (matches.GetSize() > 0)
169         {
170             Stream &output_strm = result.GetOutputStream();
171             output_strm.Printf("Help requested with ambiguous command name, possible completions:\n");
172             const uint32_t match_count = matches.GetSize();
173             for (uint32_t i = 0; i < match_count; i++)
174             {
175                 output_strm.Printf("\t%s\n", matches.GetStringAtIndex(i));
176             }
177         }
178         else
179         {
180             // Maybe the user is asking for help about a command argument rather than a command.
181             const CommandArgumentType arg_type = CommandObject::LookupArgumentName (command.GetArgumentAtIndex (0));
182             if (arg_type != eArgTypeLastArg)
183             {
184                 Stream &output_strm = result.GetOutputStream ();
185                 CommandObject::GetArgumentHelp (output_strm, arg_type, m_interpreter);
186                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
187             }
188             else
189             {
190                 result.AppendErrorWithFormat
191                     ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n",
192                      command.GetArgumentAtIndex(0));
193                 result.SetStatus (eReturnStatusFailed);
194             }
195         }
196     }
197 
198     return result.Succeeded();
199 }
200 
201 int
202 CommandObjectHelp::HandleCompletion
203 (
204     Args &input,
205     int &cursor_index,
206     int &cursor_char_position,
207     int match_start_point,
208     int max_return_elements,
209     bool &word_complete,
210     StringList &matches
211 )
212 {
213     // Return the completions of the commands in the help system:
214     if (cursor_index == 0)
215     {
216         return m_interpreter.HandleCompletionMatches (input,
217                                                     cursor_index,
218                                                     cursor_char_position,
219                                                     match_start_point,
220                                                     max_return_elements,
221                                                     word_complete,
222                                                     matches);
223     }
224     else
225     {
226         CommandObject *cmd_obj = m_interpreter.GetCommandObject (input.GetArgumentAtIndex(0));
227         input.Shift();
228         cursor_index--;
229         return cmd_obj->HandleCompletion (input,
230                                           cursor_index,
231                                           cursor_char_position,
232                                           match_start_point,
233                                           max_return_elements,
234                                           word_complete,
235                                           matches);
236     }
237 }
238