Class: Autoproj::ShellCompletion

Inherits:
Object
  • Object
show all
Defined in:
lib/autoproj/shell_completion.rb

Overview

Generates shell completion for code for a given Thor subclass

Direct Known Subclasses

BashCompletion, ZshCompletion

Constant Summary collapse

TEMPLATES_DIR =
File.join(File.dirname(__FILE__), "templates")

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name = "autoproj", cli: Autoproj::CLI::Main, command: nil) ⇒ ShellCompletion

Returns a new instance of ShellCompletion.



16
17
18
19
20
21
22
23
24
25
# File 'lib/autoproj/shell_completion.rb', line 16

def initialize(name = "autoproj", cli: Autoproj::CLI::Main, command: nil)
    @cli = cli
    @name = name

    
    return unless command

    @cli_metadata = subcommand_by_name(*command)
    @cli_metadata[:name] = "__#{name}"
end

Instance Attribute Details

#cliObject (readonly)

The CLI



8
9
10
# File 'lib/autoproj/shell_completion.rb', line 8

def cli
  @cli
end

#cli_metadataObject (readonly)

A hash describing the CLI



12
13
14
# File 'lib/autoproj/shell_completion.rb', line 12

def 
  @cli_metadata
end

#nameObject (readonly)

The command name



10
11
12
# File 'lib/autoproj/shell_completion.rb', line 10

def name
  @name
end

Instance Method Details

#generateObject



59
60
61
62
63
# File 'lib/autoproj/shell_completion.rb', line 59

def generate
    template_file = File.join(TEMPLATES_DIR, self.class::MAIN_FUNCTION_TEMPLATE)
    erb = File.read(template_file)
    ::ERB.new(erb, nil, "-").result(binding)
end

#generate_command_metadata(cli, name, command, aliases) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/autoproj/shell_completion.rb', line 128

def (cli, name, command, aliases)
    subcommands = if (subcommand_class = cli.subcommand_classes[name])
                      (subcommand_class)
                  else
                      []
                  end

    info = { name: hyphenate(name),
             aliases: aliases.map { |a| hyphenate(a) },
             usage: command.usage,
             description: command.description,
             options: (cli.class_options) +
                      (command.options),
             subcommands: subcommands }

    if subcommands.empty?
        setup_package_completion(info)
    else
        info[:options] = []
        disable_completion(info)
    end
    info
end

#generate_metadataObject



27
28
29
30
31
32
33
34
35
# File 'lib/autoproj/shell_completion.rb', line 27

def 
    @cli_metadata = { name: "__#{name}",
                      description: nil,
                      options: [],
                      subcommands: (cli) }

    setup_completion_functions
    populate_help_subcommands
end

#hyphenate(s) ⇒ Object



163
164
165
# File 'lib/autoproj/shell_completion.rb', line 163

def hyphenate(s)
    s.to_s.tr("_", "-")
end

#options_metadata(options) ⇒ Object



152
153
154
155
156
157
158
159
160
161
# File 'lib/autoproj/shell_completion.rb', line 152

def (options)
    options.reject { |_, option| option.hide }.map do |_, option|
        names = ["--#{hyphenate(option.name)}"]
        names += ["--no-#{hyphenate(option.name)}"] if option.boolean?
        names += option.aliases.map { |a| "-#{hyphenate(a)}" }

        { names: names,
          description: option.description }
    end
end

#populate_help_subcommands(command_metadata = cli_metadata) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/autoproj/shell_completion.rb', line 76

def populate_help_subcommands( = )
    help_subcommand = subcommand_by_name("help",
                                         metadata: )

    if help_subcommand
        help_subcommand[:options] = []
        disable_completion(help_subcommand)
    end

    [:subcommands].each do |subcommand|
        next if subcommand[:name] == "help"

        populate_help_subcommands(subcommand)
        next unless help_subcommand

        help_subcommand[:subcommands] << { name: subcommand[:name],
                                           aliases: [],
                                           description: subcommand[:description],
                                           options: [],
                                           subcommands: [] }
    end
end

#render_subcommand_function(subcommand, options = {}) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/autoproj/shell_completion.rb', line 99

def render_subcommand_function(subcommand, options = {})
    prefix = options[:prefix] || []
    source = []

    prefix = (prefix + [subcommand[:name]])
    function_name = prefix.join("_")
    depth = prefix.size + 1

    template_file = File.join(TEMPLATES_DIR, self.class::SUBCOMMAND_FUNCTION_TEMPLATE)
    erb = ::ERB.new(File.read(template_file), nil, "-")

    source << erb.result(binding)
    subcommand[:subcommands].each do |subcommand|
        source << render_subcommand_function(subcommand, prefix: prefix)
    end
    "#{source.join("\n").strip}\n"
end

#setup_completion_functionsObject



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/autoproj/shell_completion.rb', line 37

def setup_completion_functions
    %w[which exec].each do |command|
        setup_executable_completion(subcommand_by_name(command))
    end

    %w[cache manifest].each do |command|
        setup_file_completion(subcommand_by_name(command))
    end

    # TODO: investigate how to handle 'plugin' subcommands completion,
    # leaving disabled for now
    # TODO: reset subcommand needs a custom completer,
    # leaving disabled for now
    # TODO: log subcommand needs a custom completer,
    # leaving disabled for now
    ["bootstrap", "envsh", "reconfigure", "reset", "log", "query",
     "switch-config", %w[global register], %w[global status],
     %w[plugin install], %w[plugin remove], %w[plugin list]].each do |command|
        disable_completion(subcommand_by_name(*command))
    end
end

#subcommand_by_name(*name, metadata: cli_metadata) ⇒ Object



65
66
67
68
69
70
71
72
73
74
# File 'lib/autoproj/shell_completion.rb', line 65

def subcommand_by_name(*name, metadata: )
    subcommand = 

    name.each do |subcommand_name|
        subcommand = subcommand[:subcommands].find do |s|
            s[:name] == subcommand_name
        end
    end
    subcommand
end

#subcommand_metadata(cli) ⇒ Object



117
118
119
120
121
122
123
124
125
126
# File 'lib/autoproj/shell_completion.rb', line 117

def (cli)
    result = []
    cli.all_commands.reject { |_, t| t.hidden? }.each do |(name, command)|
        aliases = cli.map.select do |_, original_name|
            name == original_name
        end.map(&:first)
        result << (cli, name, command, aliases)
    end
    result
end