diff --git a/lib/mothership/help.rb b/lib/mothership/help.rb index 7d76305..a2b1283 100644 --- a/lib/mothership/help.rb +++ b/lib/mothership/help.rb @@ -1,4 +1,5 @@ require "mothership/base" +require "mothership/help/commands" module Mothership::Help @@groups = [] @@ -9,69 +10,6 @@ def has_groups? !@@groups.empty? end - def print_help_groups(global = nil, all = false) - @@groups.each do |commands| - print_help_group(commands, all) - end - - command_options(global) - end - - def unique_commands(commands) - uniq_commands = [] - cmd_index = {} - - commands.each do |cmd| - if idx = cmd_index[cmd.name] - uniq_commands[idx] = cmd - else - cmd_index[cmd.name] = uniq_commands.size - uniq_commands << cmd - end - end - - uniq_commands - end - - def print_help_group(group, all = false, indent = 0) - return if nothing_printable?(group, all) - - members = group[:members] - - unless all - members = members.reject do |_, opts| - opts[:hidden] - end - end - - commands = members.collect(&:first) - - i = " " * indent - - print i - puts group[:description] - - commands = unique_commands(commands) - - width = 0 - commands.each do |cmd| - len = cmd.usage.size - if len > width - width = len - end - end - - commands.each do |cmd| - puts "#{i} #{cmd.usage.ljust(width)}\t#{cmd.description}" - end - - puts "" unless commands.empty? - - group[:children].each do |group| - print_help_group(group, all, indent + 1) - end - end - # define help groups def groups(*tree) tree.each do |*args| @@ -79,120 +17,33 @@ def groups(*tree) end end - def add_to_group(command, names, options) - where = @@tree - top = true - names.each do |n| - where = where[:children] unless top - break unless where - - where = where[n] - break unless where - - top = false - end - - unless where - raise "unknown help group: #{names.join("/")}" - end - - where[:members] << [command, options] - end - - def basic_help(commands, global) - puts "Commands:" - - width = 0 - commands.each do |_, c| - len = c.usage.size - width = len if len > width - end - - commands.each do |_, c| - puts " #{c.usage.ljust(width)}\t#{c.description}" - end - - unless global.flags.empty? - puts "" - command_options(global) + def group(*names) + if where = find_group(names, @@tree) + where[:members].collect(&:first) + else + [] end end - def command_help(cmd) - puts cmd.description - puts "" - command_usage(cmd) - end - - def command_usage(cmd, io = $stdout) - io.puts "Usage: #{cmd.usage}" - - unless cmd.flags.empty? - io.puts "" - command_options(cmd, io) - end + def add_to_group(command, names, options) + where = find_group(names, @@tree) + raise "unknown help group: #{names.join("/")}" unless where + + where[:members] << [command, options] end - def command_options(cmd, io = $stdout) - io.puts "Options:" - - rev_flags = Hash.new { |h, k| h[k] = [] } - - cmd.flags.each do |f, n| - rev_flags[n] << f - end - - usages = [] - - max_width = 0 - rev_flags.collect do |name, fs| - info = cmd.inputs[name] - next if info[:hidden] - - flag = name.to_s.gsub("_", "-") - - # move full form to the front - fs.unshift fs.delete("--#{flag}") - - if short = fs.find { |x| x =~ /^-.$/ } - fs.delete short - end - - if info[:type] == :boolean && info[:default] - fs[0] = "--[no-]#{flag}" - end - - if info.key?(:default) && info.key?(:interact) - fs.unshift "--ask-#{flag}" - end - - usage = "#{short ? short + "," : " "} #{fs.join ", "}" - - unless info[:type] == :boolean - usage << " #{(info[:value] || name).to_s.upcase}" - end - - max_width = usage.size if usage.size > max_width - - usages << [usage, info[:description]] - end + private - usages.sort! { |a, b| a.first <=> b.first } + def find_group(names, where) + names.each_with_index do |n, index| + where = where[:children] unless index == 0 + break unless where - usages.each do |u, d| - if d - io.puts " #{u.ljust(max_width)} #{d}" - else - io.puts " #{u}" - end + where = where[n] + break unless where end - end - - private - def nothing_printable?(group, all = false) - group[:members].reject { |_, opts| !all && opts[:hidden] }.empty? && - group[:children].all? { |g| nothing_printable?(g) } + where end def add_group(groups, tree, name, desc, *subs) @@ -211,51 +62,3 @@ def add_group(groups, tree, name, desc, *subs) end end end - -class Mothership - class << self - # add command to help group - def group(*names) - options = - if names.last.is_a? Hash - names.pop - else - {} - end - - Mothership::Help.add_to_group(@command, names, options) - end - end - - def default_action - invoke :help - end - - def unknown_command(name) - $stderr.print "Unknown command '#{name.to_s.gsub("_", "-")}'. " - $stderr.puts "See 'help' for available commands." - exit_status 1 - end - - desc "Help!" - input :command, :argument => :optional - input :all, :type => :boolean - def help - if name = input[:command] - if cmd = @@commands[name.gsub("-", "_").to_sym] - Mothership::Help.command_help(cmd) - else - unknown_command(name) - end - elsif Help.has_groups? - unless input[:all] - puts "Showing basic command set. Pass --all to list all commands." - puts "" - end - - Mothership::Help.print_help_groups(@@global, input[:all]) - else - Mothership::Help.basic_help(@@commands, @@global) - end - end -end diff --git a/lib/mothership/help/commands.rb b/lib/mothership/help/commands.rb new file mode 100644 index 0000000..10854a3 --- /dev/null +++ b/lib/mothership/help/commands.rb @@ -0,0 +1,55 @@ +require "mothership/help/printer" + +class Mothership + class << self + # add command to help group + def group(*names) + options = + if names.last.is_a? Hash + names.pop + else + {} + end + + Mothership::Help.add_to_group(@command, names, options) + end + end + + def default_action + invoke :help + end + + def unknown_command(name) + $stderr.print "Unknown command '#{name.to_s.gsub("_", "-")}'. " + $stderr.puts "See 'help' for available commands." + exit_status 1 + end + + desc "Help!" + input :command, :argument => :optional + input :all, :type => :boolean + def help + if name = input[:command] + if cmd = @@commands[name.gsub("-", "_").to_sym] + Mothership::Help.command_help(cmd) + else + unknown_command(name) + end + elsif Help.has_groups? + unless input[:all] + puts "Showing basic command set. Pass --all to list all commands." + puts "" + end + + Mothership::Help.print_help_groups(@@global, input[:all]) + else + Mothership::Help.basic_help(@@commands, @@global) + end + end +end + +class Mothership::Command + def group + p Mothership::Help.tree[:apps][:children][:manage] + end +end diff --git a/lib/mothership/help/printer.rb b/lib/mothership/help/printer.rb new file mode 100644 index 0000000..e5fcdb1 --- /dev/null +++ b/lib/mothership/help/printer.rb @@ -0,0 +1,162 @@ +module Mothership::Help + class << self + def print_help_groups(global = nil, all = false) + @@groups.each do |commands| + print_help_group(commands, all) + end + + command_options(global) + end + + def print_help_group(group, all = false, indent = 0) + return if nothing_printable?(group, all) + + members = group[:members] + + unless all + members = members.reject do |_, opts| + opts[:hidden] + end + end + + commands = members.collect(&:first) + + i = " " * indent + + print i + puts group[:description] + + commands = unique_commands(commands) + + width = 0 + commands.each do |cmd| + len = cmd.usage.size + if len > width + width = len + end + end + + commands.each do |cmd| + puts "#{i} #{cmd.usage.ljust(width)}\t#{cmd.description}" + end + + puts "" unless commands.empty? + + group[:children].each do |group| + print_help_group(group, all, indent + 1) + end + end + + def basic_help(commands, global) + puts "Commands:" + + width = 0 + commands.each do |_, c| + len = c.usage.size + width = len if len > width + end + + commands.each do |_, c| + puts " #{c.usage.ljust(width)}\t#{c.description}" + end + + unless global.flags.empty? + puts "" + command_options(global) + end + end + + def command_help(cmd) + puts cmd.description + puts "" + command_usage(cmd) + end + + def command_usage(cmd, io = $stdout) + io.puts "Usage: #{cmd.usage}" + + unless cmd.flags.empty? + io.puts "" + command_options(cmd, io) + end + end + + def command_options(cmd, io = $stdout) + io.puts "Options:" + + rev_flags = Hash.new { |h, k| h[k] = [] } + + cmd.flags.each do |f, n| + rev_flags[n] << f + end + + usages = [] + + max_width = 0 + rev_flags.collect do |name, fs| + info = cmd.inputs[name] + next if info[:hidden] + + flag = name.to_s.gsub("_", "-") + + # move full form to the front + fs.unshift fs.delete("--#{flag}") + + if short = fs.find { |x| x =~ /^-.$/ } + fs.delete short + end + + if info[:type] == :boolean && info[:default] + fs[0] = "--[no-]#{flag}" + end + + if info.key?(:default) && info.key?(:interact) + fs.unshift "--ask-#{flag}" + end + + usage = "#{short ? short + "," : " "} #{fs.join ", "}" + + unless info[:type] == :boolean + usage << " #{(info[:value] || name).to_s.upcase}" + end + + max_width = usage.size if usage.size > max_width + + usages << [usage, info[:description]] + end + + usages.sort! { |a, b| a.first <=> b.first } + + usages.each do |u, d| + if d + io.puts " #{u.ljust(max_width)} #{d}" + else + io.puts " #{u}" + end + end + end + + private + + def nothing_printable?(group, all = false) + group[:members].reject { |_, opts| !all && opts[:hidden] }.empty? && + group[:children].all? { |g| nothing_printable?(g) } + end + + def unique_commands(commands) + uniq_commands = [] + cmd_index = {} + + commands.each do |cmd| + if idx = cmd_index[cmd.name] + uniq_commands[idx] = cmd + else + cmd_index[cmd.name] = uniq_commands.size + uniq_commands << cmd + end + end + + uniq_commands + end + end +end