diff --git a/lib/pry/default_commands/help.rb b/lib/pry/default_commands/help.rb index 9b4310f9..ee9b509e 100644 --- a/lib/pry/default_commands/help.rb +++ b/lib/pry/default_commands/help.rb @@ -13,65 +13,103 @@ class Pry When given a command name as an argument, shows the help for that command. BANNER + # We only want to show commands that have descriptions, so that the + # easter eggs don't show up. + def visible_commands + visible = {} + commands.each do |key, command| + visible[key] = command if command.description && !command.description.empty? + end + visible + end + # Get a hash of available commands grouped by the "group" name. - def grouped_commands - commands.values.group_by(&:group) + def command_groups + visible_commands.values.group_by(&:group) end def process if args.empty? - display_index + display_index(command_groups) else - display_topic(args.first) + display_search(args.first) end end # Display the index view, with headings and short descriptions per command. # # @param Hash[String => Array[Commands]] - def display_index(groups=grouped_commands) + def display_index(groups) help_text = [] groups.keys.sort.each do |key| - - commands = groups[key].select do |command| - command.description && !command.description.empty? - end.sort_by do |command| - command.options[:listing].to_s - end + commands = groups[key].sort_by{ |command| command.options[:listing].to_s } unless commands.empty? - help_text << "\n#{text.bold(key)}" - help_text += commands.map do |command| + help_text << "#{text.bold(key)}\n" + commands.map do |command| " #{command.options[:listing].to_s.ljust(18)} #{command.description}" - end + end.join("\n") end end - stagger_output(help_text.join("\n")) + stagger_output(help_text.join("\n\n")) end # Display help for an individual command or group. # # @param String The string to search for. - def display_topic(search) + def display_search(search) if command = command_set.find_command_for_help(search) - stagger_output command.new.help + display_command(command) else - filtered = grouped_commands.select{ |key, value| normalize(key).start_with?(normalize(search)) } + groups = search_hash(search, command_groups) - if filtered.empty? - raise CommandError, "No help found for '#{args.first}'" - elsif filtered.size == 1 - display_index(filtered.first.first => filtered.first.last) + if groups.size > 0 + display_index(groups) + return + end + + filtered = search_hash(search, visible_commands) + raise CommandError, "No help found for '#{args.first}'" if filtered.empty? + + if filtered.size == 1 + display_command(filtered.values.first) else - names = filtered.map(&:first) - last = names.pop - output.puts "Did you mean: #{names.join(", ")} or #{last}?" + display_index({"'#{search}' commands" => filtered.values}) end end end + # Display help for an individual command. + # + # @param [Pry::Command] + def display_command(command) + stagger_output command.new.help + end + + # Find a subset of a hash that matches the user's search term. + # + # If there's an exact match a Hash of one element will be returned, + # otherwise a sub-Hash with every key that matches the search will + # be returned. + # + # @param [String] the search term + # @param [Hash] the hash to search + def search_hash(search, hash) + matching = {} + + hash.each_pair do |key, value| + next unless key.is_a?(String) + if normalize(key) == normalize(search) + return {key => value} + elsif normalize(key).start_with?(normalize(search)) + matching[key] = value + end + end + + matching + end + # Clean search terms to make it easier to search group names # # @param String