2013-08-23 13:46:38 -04:00
//===-- CommandObjectHelp.cpp -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
2016-07-23 16:50:09 -04:00
# include "CommandObjectHelp.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Interpreter/CommandInterpreter.h"
2017-01-02 14:26:05 -05:00
# include "lldb/Interpreter/CommandObjectMultiword.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Interpreter/CommandReturnObject.h"
2017-01-02 14:26:05 -05:00
# include "lldb/Interpreter/Options.h"
2013-08-23 13:46:38 -04:00
using namespace lldb ;
using namespace lldb_private ;
//-------------------------------------------------------------------------
// CommandObjectHelp
//-------------------------------------------------------------------------
2017-01-02 14:26:05 -05:00
void CommandObjectHelp : : GenerateAdditionalHelpAvenuesMessage (
Stream * s , llvm : : StringRef command , llvm : : StringRef prefix , llvm : : StringRef subcommand ,
bool include_apropos , bool include_type_lookup ) {
if ( ! s | | command . empty ( ) )
return ;
std : : string command_str = command . str ( ) ;
std : : string prefix_str = prefix . str ( ) ;
std : : string subcommand_str = subcommand . str ( ) ;
const std : : string & lookup_str = ! subcommand_str . empty ( ) ? subcommand_str : command_str ;
s - > Printf ( " '%s' is not a known command. \n " , command_str . c_str ( ) ) ;
s - > Printf ( " Try '%shelp' to see a current list of commands. \n " ,
prefix . str ( ) . c_str ( ) ) ;
if ( include_apropos ) {
s - > Printf ( " Try '%sapropos %s' for a list of related commands. \n " ,
prefix_str . c_str ( ) , lookup_str . c_str ( ) ) ;
}
if ( include_type_lookup ) {
s - > Printf ( " Try '%stype lookup %s' for information on types, methods, "
" functions, modules, etc. " ,
prefix_str . c_str ( ) , lookup_str . c_str ( ) ) ;
}
2016-07-23 16:50:09 -04:00
}
CommandObjectHelp : : CommandObjectHelp ( CommandInterpreter & interpreter )
2017-01-02 14:26:05 -05:00
: CommandObjectParsed ( interpreter , " help " , " Show a list of all debugger "
" commands, or give details "
" about a specific command. " ,
2016-07-23 16:50:09 -04:00
" help [<cmd-name>] " ) ,
2017-01-02 14:26:05 -05:00
m_options ( ) {
CommandArgumentEntry arg ;
CommandArgumentData command_arg ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
// Define the first (and only) variant of this arg.
command_arg . arg_type = eArgTypeCommandName ;
command_arg . arg_repetition = eArgRepeatStar ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
// There is only one variant this argument could be; put it into the argument
// entry.
arg . push_back ( command_arg ) ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
2013-08-23 13:46:38 -04:00
}
2016-07-23 16:50:09 -04:00
CommandObjectHelp : : ~ CommandObjectHelp ( ) = default ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
static OptionDefinition g_help_options [ ] = {
// clang-format off
{ LLDB_OPT_SET_ALL , false , " hide-aliases " , ' a ' , OptionParser : : eNoArgument , nullptr , nullptr , 0 , eArgTypeNone , " Hide aliases in the command list. " } ,
{ LLDB_OPT_SET_ALL , false , " hide-user-commands " , ' u ' , OptionParser : : eNoArgument , nullptr , nullptr , 0 , eArgTypeNone , " Hide user-defined commands from the list. " } ,
{ LLDB_OPT_SET_ALL , false , " show-hidden-commands " , ' h ' , OptionParser : : eNoArgument , nullptr , nullptr , 0 , eArgTypeNone , " Include commands prefixed with an underscore. " } ,
// clang-format on
2013-08-23 13:46:38 -04:00
} ;
2017-01-02 14:26:05 -05:00
llvm : : ArrayRef < OptionDefinition >
CommandObjectHelp : : CommandOptions : : GetDefinitions ( ) {
return llvm : : makeArrayRef ( g_help_options ) ;
}
bool CommandObjectHelp : : DoExecute ( Args & command , CommandReturnObject & result ) {
CommandObject : : CommandMap : : iterator pos ;
CommandObject * cmd_obj ;
const size_t argc = command . GetArgumentCount ( ) ;
2013-08-23 13:46:38 -04:00
2018-07-28 07:09:23 -04:00
// 'help' doesn't take any arguments, other than command names. If argc is
// 0, we show the user all commands (aliases and user commands if asked for).
// Otherwise every argument must be the name of a command or a sub-command.
2017-01-02 14:26:05 -05:00
if ( argc = = 0 ) {
uint32_t cmd_types = CommandInterpreter : : eCommandTypesBuiltin ;
if ( m_options . m_show_aliases )
cmd_types | = CommandInterpreter : : eCommandTypesAliases ;
if ( m_options . m_show_user_defined )
cmd_types | = CommandInterpreter : : eCommandTypesUserDef ;
if ( m_options . m_show_hidden )
cmd_types | = CommandInterpreter : : eCommandTypesHidden ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
m_interpreter . GetHelp ( result , cmd_types ) ; // General help
} else {
// Get command object for the first command argument. Only search built-in
// command dictionary.
StringList matches ;
auto command_name = command [ 0 ] . ref ;
cmd_obj = m_interpreter . GetCommandObject ( command_name , & matches ) ;
if ( cmd_obj ! = nullptr ) {
StringList matches ;
bool all_okay = true ;
CommandObject * sub_cmd_obj = cmd_obj ;
// Loop down through sub_command dictionaries until we find the command
// object that corresponds to the help command entered.
std : : string sub_command ;
for ( auto & entry : command . entries ( ) . drop_front ( ) ) {
sub_command = entry . ref ;
matches . Clear ( ) ;
if ( sub_cmd_obj - > IsAlias ( ) )
sub_cmd_obj =
( ( CommandAlias * ) sub_cmd_obj ) - > GetUnderlyingCommand ( ) . get ( ) ;
if ( ! sub_cmd_obj - > IsMultiwordObject ( ) ) {
all_okay = false ;
break ;
} else {
CommandObject * found_cmd ;
found_cmd =
sub_cmd_obj - > GetSubcommandObject ( sub_command . c_str ( ) , & matches ) ;
if ( found_cmd = = nullptr | | matches . GetSize ( ) > 1 ) {
all_okay = false ;
break ;
} else
sub_cmd_obj = found_cmd ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
}
if ( ! all_okay | | ( sub_cmd_obj = = nullptr ) ) {
std : : string cmd_string ;
command . GetCommandString ( cmd_string ) ;
if ( matches . GetSize ( ) > = 2 ) {
StreamString s ;
s . Printf ( " ambiguous command %s " , cmd_string . c_str ( ) ) ;
size_t num_matches = matches . GetSize ( ) ;
for ( size_t match_idx = 0 ; match_idx < num_matches ; match_idx + + ) {
s . Printf ( " \n \t %s " , matches . GetStringAtIndex ( match_idx ) ) ;
}
s . Printf ( " \n " ) ;
result . AppendError ( s . GetString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
} else if ( ! sub_cmd_obj ) {
StreamString error_msg_stream ;
GenerateAdditionalHelpAvenuesMessage (
& error_msg_stream , cmd_string . c_str ( ) ,
m_interpreter . GetCommandPrefix ( ) , sub_command . c_str ( ) ) ;
result . AppendError ( error_msg_stream . GetString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
} else {
GenerateAdditionalHelpAvenuesMessage (
& result . GetOutputStream ( ) , cmd_string . c_str ( ) ,
m_interpreter . GetCommandPrefix ( ) , sub_command . c_str ( ) ) ;
result . GetOutputStream ( ) . Printf (
" \n The closest match is '%s'. Help on it follows. \n \n " ,
sub_cmd_obj - > GetCommandName ( ) . str ( ) . c_str ( ) ) ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
}
sub_cmd_obj - > GenerateHelpText ( result ) ;
if ( m_interpreter . AliasExists ( command_name ) ) {
StreamString sstr ;
m_interpreter . GetAlias ( command_name ) - > GetAliasExpansion ( sstr ) ;
result . GetOutputStream ( ) . Printf ( " \n '%s' is an abbreviation for %s \n " ,
command [ 0 ] . c_str ( ) , sstr . GetData ( ) ) ;
}
} else if ( matches . GetSize ( ) > 0 ) {
Stream & output_strm = result . GetOutputStream ( ) ;
output_strm . Printf ( " Help requested with ambiguous command name, possible "
" completions: \n " ) ;
const size_t match_count = matches . GetSize ( ) ;
for ( size_t i = 0 ; i < match_count ; i + + ) {
output_strm . Printf ( " \t %s \n " , matches . GetStringAtIndex ( i ) ) ;
}
} else {
// Maybe the user is asking for help about a command argument rather than
// a command.
const CommandArgumentType arg_type =
CommandObject : : LookupArgumentName ( command_name ) ;
if ( arg_type ! = eArgTypeLastArg ) {
Stream & output_strm = result . GetOutputStream ( ) ;
CommandObject : : GetArgumentHelp ( output_strm , arg_type , m_interpreter ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
} else {
StreamString error_msg_stream ;
GenerateAdditionalHelpAvenuesMessage ( & error_msg_stream , command_name ,
m_interpreter . GetCommandPrefix ( ) ,
" " ) ;
result . AppendError ( error_msg_stream . GetString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
}
return result . Succeeded ( ) ;
2013-08-23 13:46:38 -04:00
}
2018-07-28 07:09:23 -04:00
int CommandObjectHelp : : HandleCompletion ( CompletionRequest & request ) {
2017-01-02 14:26:05 -05:00
// Return the completions of the commands in the help system:
2018-07-28 07:09:23 -04:00
if ( request . GetCursorIndex ( ) = = 0 ) {
return m_interpreter . HandleCompletionMatches ( request ) ;
2017-01-02 14:26:05 -05:00
} else {
2018-07-28 07:09:23 -04:00
CommandObject * cmd_obj =
m_interpreter . GetCommandObject ( request . GetParsedLine ( ) [ 0 ] . ref ) ;
2017-01-02 14:26:05 -05:00
// The command that they are getting help on might be ambiguous, in which
2018-07-28 07:09:23 -04:00
// case we should complete that, otherwise complete with the command the
// user is getting help on...
2017-01-02 14:26:05 -05:00
if ( cmd_obj ) {
2018-07-28 07:09:23 -04:00
request . GetParsedLine ( ) . Shift ( ) ;
request . SetCursorIndex ( request . GetCursorIndex ( ) - 1 ) ;
return cmd_obj - > HandleCompletion ( request ) ;
2017-01-02 14:26:05 -05:00
} else {
2018-07-28 07:09:23 -04:00
return m_interpreter . HandleCompletionMatches ( request ) ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
}
2013-08-23 13:46:38 -04:00
}