Module: SimpleCov::CLI::Completions

Extended by:
CommandHelpers, Completions
Included in:
Completions
Defined in:
lib/simplecov/cli/completions.rb,
lib/simplecov/cli/completions/scripts.rb

Overview

simplecov completions <shell>: completion scripts for fish, bash, and zsh, generated from the usage document rather than a hand-kept table, so a new command or switch shows up in completions the moment it is documented.

Defined Under Namespace

Modules: Scripts

Constant Summary collapse

SHELLS =
%w[fish bash zsh].freeze
OPTION_ROW =

" -q, --quiet Suppress...": optional short, long, optional argument placeholder, then the description after the column gap. A single space never separates the switch from its description, so one non-space token before a two-space run can only be an argument.

/\A\s*(?:(-\w), )?(--[\w-]+)(?: (\S+))?\s{2,}(\S.*)\z/
COMMAND_ROW =
/\A(\S+)(?: \S+)*?\s{2,}(\S.*)\z/

Constants included from CommandHelpers

SimpleCov::CLI::CommandHelpers::STATS_ROW_FORMAT

Instance Method Summary collapse

Methods included from CommandHelpers

build_parser, command_name, common_options, error, error_nil, on_help, one?, parse_common, quiet_option, recorded_contexts, stats_row

Instance Method Details

#commandsObject



46
47
48
49
50
51
# File 'lib/simplecov/cli/completions.rb', line 46

def commands
  Usage.text(CLI).split("\n\n").fetch(1).lines.filter_map do |row|
    match = row.strip.match(COMMAND_ROW)
    match && [(_ = match[1]), (_ = match[2])]
  end
end

#options_by_commandObject



53
54
55
56
57
58
# File 'lib/simplecov/cli/completions.rb', line 53

def options_by_command
  commands.filter_map do |name, _desc|
    list = options_for(name)
    [name, list] unless list.empty?
  end.to_h
end

#options_for(command) ⇒ Object

run takes no options of its own, since everything after it belongs to the command being run, so it must not even offer --help.



62
63
64
65
66
67
68
# File 'lib/simplecov/cli/completions.rb', line 62

def options_for(command)
  return [] if command.eql?("run")

  sections = Usage.text(CLI).split("\n\n").select { |section| Usage.section_for?(section, command) }
  options = sections.flat_map { |section| section_options(section) }
  options << {short: "-h", long: "--help", arg: nil, desc: "Show this command's usage"}
end

#run(args, stdout:, stderr:) ⇒ Object



27
28
29
30
31
32
33
34
35
36
# File 'lib/simplecov/cli/completions.rb', line 27

def run(args, stdout:, stderr:)
  shell, = build_parser.parse(args)
  return error(stderr, "missing shell (expected fish, bash, or zsh)") unless shell
  unless SHELLS.include?(shell)
    return error(stderr, "unknown shell #{shell.inspect} (expected fish, bash, or zsh)")
  end

  stdout.puts(script_for(shell))
  0
end

#script_for(shell) ⇒ Object



38
39
40
41
42
43
44
# File 'lib/simplecov/cli/completions.rb', line 38

def script_for(shell)
  case shell
  when "fish" then Scripts.fish(commands, options_by_command)
  when "bash" then Scripts.bash(commands, options_by_command)
  else Scripts.zsh(commands, options_by_command)
  end
end

#section_options(section) ⇒ Object

Rows that don't parse as options are continuations of the previous row's description, wrapped for the terminal.



72
73
74
75
76
77
78
79
80
# File 'lib/simplecov/cli/completions.rb', line 72

def section_options(section)
  section.lines.each_with_object([]) do |line, options|
    if (match = line.chomp.match(OPTION_ROW))
      options << {short: match[1], long: match[2], arg: match[3], desc: (_ = match[4])}
    elsif (previous = options.last)
      previous[:desc] = "#{previous.fetch(:desc)} #{line.strip}"
    end
  end
end