davetron5000 / gli

Make awesome command-line applications the easy way
http://davetron5000.github.io/gli
Apache License 2.0
1.26k stars 102 forks source link

Paginate help output? #314

Closed ttscoff closed 1 month ago

ttscoff commented 2 years ago

Some of my subcommand help screens have gotten quite large between long_desc, flags/options and multiple examples. I have a pager built into my little app and I'm wondering if there's a way I could hook the help command to direct output through the pager so it works more the way that git help (or even man) does instead of requiring the user to scroll back up to see the first options.

ttscoff commented 2 years ago

I monkey patched it for now, but if there's a more elegant way, I'd love to hear. If it's not already an option and I missed it, might be nice to have the ability to pipe the help command output as needed.

davetron5000 commented 2 years ago

Hmm, yeah this seems like a good feature, but I'm not sure exactly how to achieve this. Can you share what you did?

The only thing I can think of is to have gli replace itself with gli «args» | $PAGER somehow

ttscoff commented 2 years ago

I just did a very dirty monkey patch over the whole show_help function and changed the puts command to my built-in pagination function.

module GLI
  module Commands
    # Help Command Monkeypatch for paginated output
    class Help < Command
      def show_help(global_options,options,arguments,out,error)
        Doing::Pager.paginate = true

        command_finder = HelpModules::CommandFinder.new(@app,arguments,error)
        if options[:c]
          help_output = HelpModules::HelpCompletionFormat.new(@app,command_finder,arguments).format
          out.puts help_output unless help_output.nil?
        elsif arguments.empty? || options[:c]
          Doing::Pager.page HelpModules::GlobalHelpFormat.new(@app,@sorter,@text_wrapping_class).format
        else
          name = arguments.shift
          command = command_finder.find_command(name)
          unless command.nil?
            Doing::Pager.page HelpModules::CommandHelpFormat.new(
              command,
              @app,
              @sorter,
              @synopsis_formatter_class,
              @text_wrapping_class).format
          end
        end
      end
    end
  end
end

My pagination routine just detects the appropriate pager for the system based on GIT_PAGER, PAGER, and a cascade of potential executables (bat, less, more). If it finds a usable one, it uses IO.pipe to send text to it. Happy to share it, but I'm just bad enough at Ruby to by shy about it :).

What I'd be interested in is just a block like on_error, but on_help do |help_text| that received the formatted help output and let you do what you wanted to with it, defaulting to puts if it returns true. And if help -c was run than the block would be skipped. I'm probably not thinking through the complexities or possibilities, though.

davetron5000 commented 1 month ago

Closing as old - I'd like to keep GLI relative stable so I won't be able to work on this. If someone has a patch with tests, please open a PR