Module: Dry::CLI::Usage

Extended by:
WordWrap
Defined in:
lib/dry/cli/banner.rb

Overview

The command list agentilda -h prints.

Upstream renders a description on one line however long it is, so a long desc runs off the terminal and a two-line one drops its second line to column zero. Descriptions are wrapped here instead, hung under the # the way Banner already hangs an option's.

Constant Summary collapse

MIN_DESCRIPTION_WIDTH =

Narrowest description column worth wrapping to. Below this the hanging indent leaves no room for words.

24

Class Method Summary collapse

Methods included from WordWrap

wrap_description

Class Method Details

.by_depth(commands) ⇒ Array<Array(String, Dry::CLI::CommandRegistry::Node)>

A command that owns subcommands is the heading for a whole area of the tool, so it belongs above the flat commands rather than filed alphabetically among them. Alphabetical order is kept inside each group.

children? is the direct question, children.any?. leaf? asks something else — whether the node carries a runnable command — and the two are independent: a command that also takes subcommands is both, and sorting on leaf? would file it with the flat commands.

Parameters:

  • commands (Hash{String => Dry::CLI::CommandRegistry::Node})

Returns:

  • (Array<Array(String, Dry::CLI::CommandRegistry::Node)>)


57
58
59
# File 'lib/dry/cli/banner.rb', line 57

def self.by_depth(commands)
  commands.sort_by { |banner, node| [node.children? ? 0 : 1, banner] }
end

.call(result) ⇒ String

Parameters:

  • result (Dry::CLI::CommandRegistry::LookupResult)

Returns:

  • (String)


34
35
36
37
38
39
40
41
42
43
44
# File 'lib/dry/cli/banner.rb', line 34

def self.call(result)
  max_length, commands = commands_and_arguments(result)
  column = max_length + max_length / 2

  by_depth(commands).filter_map { |banner, node|
    next if node.hidden

    usage = description(node.command, column) if node.leaf?
    "#{justify(banner, max_length, usage)}#{usage}"
  }.unshift("Commands:").join("\n")
end

.description(command, column = 0) ⇒ String?

Parameters:

  • command (Dry::CLI::Command)
  • column (Integer) (defaults to: 0)

    the width the banner is padded to; the # sits one past it, so continuation lines do too

Returns:

  • (String, nil)


65
66
67
68
69
70
71
72
73
74
# File 'lib/dry/cli/banner.rb', line 65

def self.description(command, column = 0)
  return unless CLI.command?(command)
  return if command.description.nil?

  prefix = "#{" " * (column + 1)}# "
  width = [86 - prefix.length, MIN_DESCRIPTION_WIDTH].max
  text = command.description.gsub(/\s+/, " ").strip

  " # #{wrap_description(text, width: width, prefix: prefix)}"
end