Skip to content

Commit deb6e27

Browse files
authored
Merge pull request #714 from bashly-framework/fix/completions-for-default-command
Fix completions for a default command
2 parents 24d428d + 27c9f46 commit deb6e27

5 files changed

Lines changed: 103 additions & 5 deletions

File tree

lib/bashly/completion_builder.rb

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def add_command(command, inherited_global_groups:)
2727
pattern_groups = inherited_global_groups.dup
2828
pattern_groups << local_group if local_group
2929

30-
@patterns << pattern_for(command, pattern_groups)
30+
@patterns << pattern_for(command, pattern_groups) unless visible_default_command(command)
3131

3232
child_global_groups = inherited_global_groups.dup
3333
if command.global_flags?
@@ -36,6 +36,7 @@ def add_command(command, inherited_global_groups:)
3636
end
3737

3838
command.visible_commands.each do |child|
39+
add_default_command_pattern command, child, pattern_groups
3940
add_command child, inherited_global_groups: child_global_groups
4041
end
4142
end
@@ -47,6 +48,38 @@ def pattern_for(command, option_groups)
4748
parts.join ' '
4849
end
4950

51+
def add_default_command_pattern(parent, command, parent_option_groups)
52+
return unless command.default
53+
54+
default_group = add_default_options parent, command, parent_option_groups
55+
option_groups = default_group ? [default_group] : []
56+
57+
@patterns << pattern_for_default_command(parent, command, option_groups)
58+
end
59+
60+
def add_default_options(parent, command, parent_option_groups)
61+
local_group = add_local_options command
62+
group_names = parent_option_groups.dup
63+
group_names << local_group if local_group
64+
65+
entries = group_names.flat_map { |name| @options[name] || [] }.uniq
66+
return if entries.empty?
67+
68+
name = token_name "#{group_name(parent)}_#{group_name(command)}_default"
69+
@options[name] = entries
70+
name
71+
end
72+
73+
def pattern_for_default_command(parent, command, option_groups)
74+
parts = [command_path(parent)]
75+
parts.concat(option_groups.map { |group| "[#{group} options]" })
76+
parts.concat positional_tokens(
77+
command,
78+
first_source_extra: static_source(parent.visible_command_aliases)
79+
)
80+
parts.join ' '
81+
end
82+
5083
def command_path(command)
5184
command_chain(command).map.with_index do |item, index|
5285
index.zero? ? item.name : item.aliases.join('|')
@@ -102,14 +135,20 @@ def flag_token_name(flag, command)
102135
register_token flag.arg || flag.name, command, flag_source(flag)
103136
end
104137

105-
def positional_tokens(command)
106-
command.args.map do |arg|
107-
token_name = register_token arg.name, command, arg_source(arg, command)
138+
def positional_tokens(command, first_source_extra: nil)
139+
command.args.map.with_index do |arg, index|
140+
source = arg_source arg, command
141+
source = merge_sources(first_source_extra, source) if index.zero? && first_source_extra
142+
token_name = register_token arg.name, command, source
108143
suffix = arg.repeatable ? '...' : nil
109144
"<#{token_name}>#{suffix}"
110145
end
111146
end
112147

148+
def merge_sources(*sources)
149+
sources.compact.flatten.uniq
150+
end
151+
113152
def flag_source(flag)
114153
return static_source(flag.allowed) if flag.allowed
115154
return completion_source(flag.completions) if flag.completions
@@ -178,6 +217,10 @@ def group_name(command)
178217
token_name command.root_command? ? 'root' : command.action_name
179218
end
180219

220+
def visible_default_command(command)
221+
command.visible_commands.find(&:default)
222+
end
223+
181224
def token_name(value)
182225
value.to_s
183226
.gsub(/[^a-zA-Z0-9]+/, '_')

lib/bashly/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module Bashly
2-
VERSION = '1.3.8'
2+
VERSION = '1.4.0.rc1'
33
end
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
patterns:
3+
- cli [root_get_default options] <package>
4+
- cli get [get options] <get_package>
5+
options:
6+
root:
7+
- "--help|-h"
8+
- "--version|-v"
9+
get:
10+
- "--help|-h"
11+
- "--source <source>"
12+
root_get_default:
13+
- "--help|-h"
14+
- "--version|-v"
15+
- "--source <source>"
16+
tokens:
17+
source:
18+
- local
19+
- remote
20+
package:
21+
- get
22+
- hello
23+
- world
24+
get_package:
25+
- hello
26+
- world

spec/bashly/completion_builder_spec.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,19 @@
1616
end
1717
end
1818
end
19+
20+
context 'with a default command' do
21+
let(:command) { Script::Command.new fixtures[:default_command]['command'] }
22+
let(:data) { described_class.new(command).call }
23+
24+
it 'adds default command argument completions to the parent command route' do
25+
expect(data['patterns']).to include(
26+
'cli [root_get_default options] <package>',
27+
'cli get [get options] <get_package>'
28+
)
29+
30+
expect(data['tokens']['package']).to eq %w[get hello world]
31+
expect(data['tokens']['get_package']).to eq %w[hello world]
32+
end
33+
end
1934
end

spec/fixtures/completion_builder.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@
4444
arg: env
4545
allowed: [prod, dev]
4646

47+
:default_command:
48+
command:
49+
name: cli
50+
commands:
51+
- name: get
52+
default: true
53+
args:
54+
- name: package
55+
completions: [hello, world]
56+
flags:
57+
- long: --source
58+
arg: source
59+
completions: [local, remote]
60+
4761
:token_collisions:
4862
command:
4963
name: cli

0 commit comments

Comments
 (0)