Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 47 additions & 4 deletions lib/bashly/completion_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def add_command(command, inherited_global_groups:)
pattern_groups = inherited_global_groups.dup
pattern_groups << local_group if local_group

@patterns << pattern_for(command, pattern_groups)
@patterns << pattern_for(command, pattern_groups) unless visible_default_command(command)

child_global_groups = inherited_global_groups.dup
if command.global_flags?
Expand All @@ -36,6 +36,7 @@ def add_command(command, inherited_global_groups:)
end

command.visible_commands.each do |child|
add_default_command_pattern command, child, pattern_groups
add_command child, inherited_global_groups: child_global_groups
end
end
Expand All @@ -47,6 +48,38 @@ def pattern_for(command, option_groups)
parts.join ' '
end

def add_default_command_pattern(parent, command, parent_option_groups)
return unless command.default

default_group = add_default_options parent, command, parent_option_groups
option_groups = default_group ? [default_group] : []

@patterns << pattern_for_default_command(parent, command, option_groups)
end

def add_default_options(parent, command, parent_option_groups)
local_group = add_local_options command
group_names = parent_option_groups.dup
group_names << local_group if local_group

entries = group_names.flat_map { |name| @options[name] || [] }.uniq
return if entries.empty?

name = token_name "#{group_name(parent)}_#{group_name(command)}_default"
@options[name] = entries
name
end

def pattern_for_default_command(parent, command, option_groups)
parts = [command_path(parent)]
parts.concat(option_groups.map { |group| "[#{group} options]" })
parts.concat positional_tokens(
command,
first_source_extra: static_source(parent.visible_command_aliases)
)
parts.join ' '
end

def command_path(command)
command_chain(command).map.with_index do |item, index|
index.zero? ? item.name : item.aliases.join('|')
Expand Down Expand Up @@ -102,14 +135,20 @@ def flag_token_name(flag, command)
register_token flag.arg || flag.name, command, flag_source(flag)
end

def positional_tokens(command)
command.args.map do |arg|
token_name = register_token arg.name, command, arg_source(arg, command)
def positional_tokens(command, first_source_extra: nil)
command.args.map.with_index do |arg, index|
source = arg_source arg, command
source = merge_sources(first_source_extra, source) if index.zero? && first_source_extra
token_name = register_token arg.name, command, source
suffix = arg.repeatable ? '...' : nil
"<#{token_name}>#{suffix}"
end
end

def merge_sources(*sources)
sources.compact.flatten.uniq
end

def flag_source(flag)
return static_source(flag.allowed) if flag.allowed
return completion_source(flag.completions) if flag.completions
Expand Down Expand Up @@ -178,6 +217,10 @@ def group_name(command)
token_name command.root_command? ? 'root' : command.action_name
end

def visible_default_command(command)
command.visible_commands.find(&:default)
end

def token_name(value)
value.to_s
.gsub(/[^a-zA-Z0-9]+/, '_')
Expand Down
2 changes: 1 addition & 1 deletion lib/bashly/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Bashly
VERSION = '1.3.8'
VERSION = '1.4.0.rc1'
end
26 changes: 26 additions & 0 deletions spec/approvals/completion_builder/default_command
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
patterns:
- cli [root_get_default options] <package>
- cli get [get options] <get_package>
options:
root:
- "--help|-h"
- "--version|-v"
get:
- "--help|-h"
- "--source <source>"
root_get_default:
- "--help|-h"
- "--version|-v"
- "--source <source>"
tokens:
source:
- local
- remote
package:
- get
- hello
- world
get_package:
- hello
- world
15 changes: 15 additions & 0 deletions spec/bashly/completion_builder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,19 @@
end
end
end

context 'with a default command' do
let(:command) { Script::Command.new fixtures[:default_command]['command'] }
let(:data) { described_class.new(command).call }

it 'adds default command argument completions to the parent command route' do
expect(data['patterns']).to include(
'cli [root_get_default options] <package>',
'cli get [get options] <get_package>'
)

expect(data['tokens']['package']).to eq %w[get hello world]
expect(data['tokens']['get_package']).to eq %w[hello world]
end
end
end
14 changes: 14 additions & 0 deletions spec/fixtures/completion_builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@
arg: env
allowed: [prod, dev]

:default_command:
command:
name: cli
commands:
- name: get
default: true
args:
- name: package
completions: [hello, world]
flags:
- long: --source
arg: source
completions: [local, remote]

:token_collisions:
command:
name: cli
Expand Down