bashly 1.4.0 → 2.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bashly/commands/completions.rb +3 -41
  3. data/lib/bashly/completions/README.md +3 -7
  4. data/lib/bashly/completions/bashly-completions.bash +2 -2
  5. data/lib/bashly/completions/completely.yaml +0 -4
  6. data/lib/bashly/config_validator.rb +16 -3
  7. data/lib/bashly/docs/arg.yml +12 -6
  8. data/lib/bashly/docs/command.yml +0 -12
  9. data/lib/bashly/docs/flag.yml +8 -4
  10. data/lib/bashly/libraries/libraries.yml +0 -15
  11. data/lib/bashly/libraries/settings/settings.yml +9 -1
  12. data/lib/bashly/script/argument.rb +12 -0
  13. data/lib/bashly/script/command.rb +1 -2
  14. data/lib/bashly/script/flag.rb +12 -1
  15. data/lib/bashly/script/introspection/commands.rb +5 -0
  16. data/lib/bashly/script/wrapper.rb +1 -1
  17. data/lib/bashly/settings.rb +28 -3
  18. data/lib/bashly/version.rb +1 -1
  19. data/lib/bashly/views/argument/completion.gtx +31 -0
  20. data/lib/bashly/views/argument/completion_filter.gtx +1 -0
  21. data/lib/bashly/views/command/completion_argument_candidates.gtx +11 -0
  22. data/lib/bashly/views/command/completion_argument_filter.gtx +25 -0
  23. data/lib/bashly/views/command/completion_command_candidates.gtx +3 -0
  24. data/lib/bashly/views/command/completion_flag_candidates.gtx +21 -0
  25. data/lib/bashly/views/command/completion_function.gtx +24 -0
  26. data/lib/bashly/views/command/completion_script.gtx +21 -0
  27. data/lib/bashly/views/command/completion_script_bash.gtx +63 -0
  28. data/lib/bashly/views/command/completion_script_zsh.gtx +52 -0
  29. data/lib/bashly/views/command/completion_word_filter.gtx +44 -0
  30. data/lib/bashly/views/command/completions.gtx +81 -0
  31. data/lib/bashly/views/command/inspect_args.gtx +3 -3
  32. data/lib/bashly/views/command/master_script.gtx +1 -0
  33. data/lib/bashly/views/command/start.gtx +9 -0
  34. data/lib/bashly/views/flag/completion.gtx +1 -0
  35. data/lib/bashly/views/flag/completion_filter.gtx +7 -0
  36. data/lib/bashly/views/flag/completion_filter_arg.gtx +10 -0
  37. data/lib/bashly/views/flag/completion_filter_block.gtx +8 -0
  38. data/lib/bashly/views/flag/completion_filter_no_arg.gtx +2 -0
  39. data/lib/bashly/views/flag/completion_value_candidates.gtx +31 -0
  40. data/lib/bashly.rb +2 -5
  41. metadata +22 -23
  42. data/lib/bashly/completion_builder.rb +0 -231
  43. data/lib/bashly/concerns/completions.rb +0 -48
  44. data/lib/bashly/libraries/completions/completions_function.rb +0 -37
  45. data/lib/bashly/libraries/completions/completions_script.rb +0 -28
  46. data/lib/bashly/libraries/completions/completions_yaml.rb +0 -26
  47. /data/lib/bashly/views/wrapper/{bash3_bouncer.gtx → bash_version_bouncer.gtx} +0 -0
@@ -0,0 +1,52 @@
1
+ = view_marker
2
+
3
+ > send_completions_zsh() {
4
+ > echo $'#compdef {{ name }}'
5
+ > echo $''
6
+ > echo $'_{{ name.to_underscore }}_completions() {'
7
+ > echo $' local completion_command="${words[1]}"'
8
+ > echo $' local completion_current="${words[CURRENT]:-}"'
9
+ > echo $' local completion_output'
10
+ > echo $' local completion_directive'
11
+ > echo $' local -a completion_words=()'
12
+ > echo $' local -a completion_response=()'
13
+ > echo $' local -a completion_options=()'
14
+ > echo $' local -a completion_add_args=()'
15
+ > echo $''
16
+ > echo $' if (( CURRENT > 2 )); then'
17
+ > echo $' completion_words=("${words[2,$((CURRENT - 1))]}")'
18
+ > echo $' fi'
19
+ > echo $''
20
+ > echo $' completion_output="$("$completion_command" __complete "${completion_words[@]}" "$completion_current")"'
21
+ > echo $' completion_response=("${(@f)completion_output}")'
22
+ > echo $''
23
+ > echo $' completion_directive="${completion_response[-1]:-}"'
24
+ > echo $' if [[ $completion_directive == :options=* ]]; then'
25
+ > echo $' completion_response[-1]=()'
26
+ > echo $' completion_options=("${(@s:,:)${completion_directive#:options=}}")'
27
+ > echo $' fi'
28
+ > echo $''
29
+ > echo $' local completion_option'
30
+ > echo $' local completion_files=false'
31
+ > echo $' local completion_directories=false'
32
+ > echo $' for completion_option in "${completion_options[@]}"; do'
33
+ > echo $' case "$completion_option" in'
34
+ > echo $' files) completion_files=true ;;'
35
+ > echo $' directories) completion_directories=true ;;'
36
+ > echo $' no-space) completion_add_args=(-S "") ;;'
37
+ > echo $' esac'
38
+ > echo $' done'
39
+ > echo $''
40
+ > echo $' if (( ${#completion_response[@]} > 0 )); then'
41
+ > echo $' compadd "${completion_add_args[@]}" -- "${completion_response[@]}"'
42
+ > echo $' fi'
43
+ > echo $''
44
+ > echo $' if [[ $completion_files == true ]]; then'
45
+ > echo $' _files "${completion_add_args[@]}"'
46
+ > echo $' elif [[ $completion_directories == true ]]; then'
47
+ > echo $' _files -/ "${completion_add_args[@]}"'
48
+ > echo $' fi'
49
+ > echo $'}'
50
+ > echo $''
51
+ > echo $'compdef _{{ name.to_underscore }}_completions {{ name }}'
52
+ > }
@@ -0,0 +1,44 @@
1
+ > while [[ $# -gt 0 ]]; do
2
+ > case "$1" in
3
+ public_commands.each do |command|
4
+ > {{ command.aliases.join ' | ' }})
5
+ > shift
6
+ > {{ command.function_name }}_completion "$completion_current" "$@"
7
+ > return
8
+ > ;;
9
+ end
10
+ if fixed_flags?
11
+ if short_flag_exist? '-h'
12
+ > --help)
13
+ else
14
+ > --help | -h)
15
+ end
16
+ > completion_blocked_flags["--help"]=1
17
+ > shift
18
+ > ;;
19
+ if root_command?
20
+ if short_flag_exist? '-v'
21
+ > --version)
22
+ else
23
+ > --version | -v)
24
+ end
25
+ > completion_blocked_flags["--version"]=1
26
+ > shift
27
+ > ;;
28
+ end
29
+ end
30
+ public_flags.each do |flag|
31
+ = flag.render(:completion_filter).indent 4
32
+ end
33
+ > *)
34
+ if args.any?
35
+ = render(:completion_argument_filter).indent 6
36
+ elsif default_command
37
+ > {{ default_command.function_name }}_completion "$completion_current" "$@"
38
+ > return
39
+ else
40
+ > return
41
+ end
42
+ > ;;
43
+ > esac
44
+ > done
@@ -0,0 +1,81 @@
1
+ = view_marker
2
+
3
+ > completion_run() {
4
+ > local -a completion_words=("$@")
5
+ > local -A completion_blocked_flags=()
6
+ > local -A completion_emitted=()
7
+ > local -a completion_options=()
8
+ > local -A completion_options_seen=()
9
+ > local completion_count=${#completion_words[@]}
10
+ > local completion_current=""
11
+ >
12
+ > if [[ $completion_count -gt 0 ]]; then
13
+ > completion_current="${completion_words[$((completion_count - 1))]}"
14
+ > unset 'completion_words[completion_count - 1]'
15
+ > fi
16
+ >
17
+ > {{ function_name }}_completion "$completion_current" "${completion_words[@]}"
18
+ >
19
+ > local completion_options_string=""
20
+ > if [[ ${#completion_options[@]} -gt 0 ]]; then
21
+ > completion_options_string="$(
22
+ > IFS=,
23
+ > printf '%s' "${completion_options[*]}"
24
+ > )"
25
+ > fi
26
+ > printf ':options=%s\n' "$completion_options_string"
27
+ > }
28
+ >
29
+ > completion_candidates() {
30
+ > local completion_current="$1"
31
+ > shift
32
+ >
33
+ > local completion_candidate
34
+ > for completion_candidate in "$@"; do
35
+ > if [[ $completion_candidate == "$completion_current"* ]] &&
36
+ > [[ -z "${completion_emitted[$completion_candidate]:-}" ]]; then
37
+ > printf '%s\n' "$completion_candidate"
38
+ > completion_emitted["$completion_candidate"]=1
39
+ > fi
40
+ > done
41
+ > }
42
+ >
43
+ > completion_flag_candidates() {
44
+ > local completion_flag="$1"
45
+ > local completion_current="$2"
46
+ > shift 2
47
+ >
48
+ > if [[ -z "${completion_blocked_flags[$completion_flag]:-}" ]]; then
49
+ > completion_candidates "$completion_current" "$@"
50
+ > fi
51
+ > }
52
+ >
53
+ > completion_add_options() {
54
+ > local completion_option
55
+ > for completion_option in "$@"; do
56
+ > if [[ -z "${completion_options_seen[$completion_option]:-}" ]]; then
57
+ > completion_options+=("$completion_option")
58
+ > completion_options_seen["$completion_option"]=1
59
+ > fi
60
+ > done
61
+ > }
62
+ >
63
+ > completion_dynamic_candidates() {
64
+ > local completion_current="$1"
65
+ > local completion_output="$2"
66
+ >
67
+ > [[ -n $completion_output ]] || return
68
+ >
69
+ > local completion_candidate
70
+ > while IFS= read -r completion_candidate; do
71
+ > if [[ -n $completion_candidate ]]; then
72
+ > completion_candidates "$completion_current" "$completion_candidate"
73
+ > fi
74
+ > done <<<"$completion_output"
75
+ > }
76
+ >
77
+ = render :completion_script if Settings.completion_shells.any?
78
+ = render :completion_function
79
+ deep_commands.each do |command|
80
+ = command.render :completion_function
81
+ end
@@ -4,7 +4,7 @@
4
4
  > local k
5
5
  >
6
6
  > if ((${#args[@]})); then
7
- > readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort)
7
+ > readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | LC_ALL=C sort)
8
8
  > echo args:
9
9
  > for k in "${sorted_keys[@]}"; do
10
10
  > echo "- \${args[$k]} = ${args[$k]}"
@@ -28,7 +28,7 @@ end
28
28
 
29
29
  if Settings.enabled? :deps_array
30
30
  > if ((${#deps[@]})); then
31
- > readarray -t sorted_keys < <(printf '%s\n' "${!deps[@]}" | sort)
31
+ > readarray -t sorted_keys < <(printf '%s\n' "${!deps[@]}" | LC_ALL=C sort)
32
32
  > echo
33
33
  > echo deps:
34
34
  > for k in "${sorted_keys[@]}"; do
@@ -40,7 +40,7 @@ end
40
40
 
41
41
  if Settings.enabled? :env_var_names_array
42
42
  > if ((${#env_var_names[@]})); then
43
- > readarray -t sorted_names < <(printf '%s\n' "${env_var_names[@]}" | sort)
43
+ > readarray -t sorted_names < <(printf '%s\n' "${env_var_names[@]}" | LC_ALL=C sort)
44
44
  > echo
45
45
  > echo "environment variables:"
46
46
  > for k in "${sorted_names[@]}"; do
@@ -8,6 +8,7 @@
8
8
  = render :user_lib if user_lib.any?
9
9
  = render :command_functions
10
10
  = render :parse_requirements
11
+ = render :completions if Settings.completions?
11
12
  = render :user_hooks
12
13
  = render :initialize
13
14
  = render :run
@@ -1,5 +1,14 @@
1
1
  = view_marker
2
2
 
3
3
  > command_line_args=("$@")
4
+ if Settings.completions?
5
+ > if [[ "${command_line_args[0]:-}" == "__complete" ]]; then
6
+ > completion_run "${command_line_args[@]:1}"
7
+ > else
8
+ > {{ Settings.function_name :initialize }}
9
+ > {{ Settings.function_name :run }} "${command_line_args[@]}"
10
+ > fi
11
+ else
4
12
  > {{ Settings.function_name :initialize }}
5
13
  > {{ Settings.function_name :run }} "${command_line_args[@]}"
14
+ end
@@ -0,0 +1 @@
1
+ > completion_flag_candidates {{ name }} "$completion_current" {{ aliases.join ' ' }}
@@ -0,0 +1,7 @@
1
+ > {{ aliases.join ' | ' }})
2
+ if arg
3
+ = render(:completion_filter_arg).indent 2
4
+ else
5
+ = render(:completion_filter_no_arg).indent 2
6
+ end
7
+ > ;;
@@ -0,0 +1,10 @@
1
+ > shift
2
+ > if [[ $# -eq 0 ]]; then
3
+ = render(:completion_value_candidates).indent 2
4
+ > return
5
+ > fi
6
+ if unique
7
+ > completion_used_flag_values["{{ name }}:$1"]=1
8
+ end
9
+ > shift
10
+ = render :completion_filter_block
@@ -0,0 +1,8 @@
1
+ unless repeatable
2
+ > completion_blocked_flags["{{ name }}"]=1
3
+ end
4
+ if conflicts
5
+ conflicts.each do |conflict|
6
+ > completion_blocked_flags["{{ conflict }}"]=1
7
+ end
8
+ end
@@ -0,0 +1,2 @@
1
+ = render :completion_filter_block
2
+ > shift
@@ -0,0 +1,31 @@
1
+ if allowed
2
+ > local -a completion_values=(
3
+ allowed.each do |value|
4
+ > "{{ value }}"
5
+ end
6
+ > )
7
+ if unique
8
+ > local completion_value
9
+ > for completion_value in "${completion_values[@]}"; do
10
+ > if [[ -z "${completion_used_flag_values["{{ name }}:$completion_value"]:-}" ]]; then
11
+ > completion_candidates "$completion_current" "$completion_value"
12
+ > fi
13
+ > done
14
+ else
15
+ > completion_candidates "$completion_current" "${completion_values[@]}"
16
+ end
17
+ end
18
+
19
+ if completion_static.any?
20
+ > completion_candidates "$completion_current" {{ completion_static.map { |value| Shellwords.shellescape value }.join ' ' }}
21
+ end
22
+
23
+ completion_dynamic.each do |command|
24
+ > if completion_output="$({ {{ command }}; } 2>/dev/null)"; then
25
+ > completion_dynamic_candidates "$completion_current" "$completion_output"
26
+ > fi
27
+ end
28
+
29
+ if completion_options.any?
30
+ > completion_add_options {{ completion_options.join ' ' }}
31
+ end
data/lib/bashly.rb CHANGED
@@ -6,13 +6,13 @@ module Bashly
6
6
  autoloads 'bashly/refinements', %i[ComposeRefinements]
7
7
 
8
8
  autoloads 'bashly', %i[
9
- CLI CompletionBuilder Config ConfigValidator Library LibrarySource
9
+ CLI Config ConfigValidator Library LibrarySource
10
10
  LibrarySourceConfig MessageStrings RenderContext RenderSource Settings
11
11
  VERSION Watch
12
12
  ]
13
13
 
14
14
  autoloads 'bashly/concerns', %i[
15
- AssetHelper Completions Renderable ValidationHelpers
15
+ AssetHelper Renderable ValidationHelpers
16
16
  ]
17
17
 
18
18
  module Script
@@ -37,9 +37,6 @@ module Bashly
37
37
 
38
38
  module Libraries
39
39
  autoload :Base, 'bashly/libraries/base'
40
- autoload :CompletionsFunction, 'bashly/libraries/completions/completions_function'
41
- autoload :CompletionsScript, 'bashly/libraries/completions/completions_script'
42
- autoload :CompletionsYAML, 'bashly/libraries/completions/completions_yaml'
43
40
  autoload :Help, 'bashly/libraries/help/help'
44
41
  end
45
42
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bashly
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 2.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Ben Shitrit
@@ -23,20 +23,6 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '1.0'
26
- - !ruby/object:Gem::Dependency
27
- name: completely
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
30
- - - "~>"
31
- - !ruby/object:Gem::Version
32
- version: 0.8.0
33
- type: :runtime
34
- prerelease: false
35
- version_requirements: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: 0.8.0
40
26
  - !ruby/object:Gem::Dependency
41
27
  name: gtx
42
28
  requirement: !ruby/object:Gem::Requirement
@@ -142,13 +128,11 @@ files:
142
128
  - lib/bashly/commands/render.rb
143
129
  - lib/bashly/commands/shell.rb
144
130
  - lib/bashly/commands/validate.rb
145
- - lib/bashly/completion_builder.rb
146
131
  - lib/bashly/completions/README.md
147
132
  - lib/bashly/completions/bashly-completions.bash
148
133
  - lib/bashly/completions/completely.yaml
149
134
  - lib/bashly/completions/completely.yaml.gtx
150
135
  - lib/bashly/concerns/asset_helper.rb
151
- - lib/bashly/concerns/completions.rb
152
136
  - lib/bashly/concerns/indentation_helper.rb
153
137
  - lib/bashly/concerns/renderable.rb
154
138
  - lib/bashly/concerns/validation_helpers.rb
@@ -166,9 +150,6 @@ files:
166
150
  - lib/bashly/extensions/yaml.rb
167
151
  - lib/bashly/libraries/base.rb
168
152
  - lib/bashly/libraries/colors/colors.sh
169
- - lib/bashly/libraries/completions/completions_function.rb
170
- - lib/bashly/libraries/completions/completions_script.rb
171
- - lib/bashly/libraries/completions/completions_yaml.rb
172
153
  - lib/bashly/libraries/config/config.sh
173
154
  - lib/bashly/libraries/help/help.rb
174
155
  - lib/bashly/libraries/help/help_command.sh
@@ -231,6 +212,8 @@ files:
231
212
  - lib/bashly/views/README.md
232
213
  - lib/bashly/views/argument/case.gtx
233
214
  - lib/bashly/views/argument/case_repeatable.gtx
215
+ - lib/bashly/views/argument/completion.gtx
216
+ - lib/bashly/views/argument/completion_filter.gtx
234
217
  - lib/bashly/views/argument/usage.gtx
235
218
  - lib/bashly/views/argument/validations.gtx
236
219
  - lib/bashly/views/command/argfile_filter.gtx
@@ -238,6 +221,16 @@ files:
238
221
  - lib/bashly/views/command/command_fallback.gtx
239
222
  - lib/bashly/views/command/command_filter.gtx
240
223
  - lib/bashly/views/command/command_functions.gtx
224
+ - lib/bashly/views/command/completion_argument_candidates.gtx
225
+ - lib/bashly/views/command/completion_argument_filter.gtx
226
+ - lib/bashly/views/command/completion_command_candidates.gtx
227
+ - lib/bashly/views/command/completion_flag_candidates.gtx
228
+ - lib/bashly/views/command/completion_function.gtx
229
+ - lib/bashly/views/command/completion_script.gtx
230
+ - lib/bashly/views/command/completion_script_bash.gtx
231
+ - lib/bashly/views/command/completion_script_zsh.gtx
232
+ - lib/bashly/views/command/completion_word_filter.gtx
233
+ - lib/bashly/views/command/completions.gtx
241
234
  - lib/bashly/views/command/default_assignments.gtx
242
235
  - lib/bashly/views/command/default_script.gtx
243
236
  - lib/bashly/views/command/dependencies_filter.gtx
@@ -291,12 +284,18 @@ files:
291
284
  - lib/bashly/views/flag/case.gtx
292
285
  - lib/bashly/views/flag/case_arg.gtx
293
286
  - lib/bashly/views/flag/case_no_arg.gtx
287
+ - lib/bashly/views/flag/completion.gtx
288
+ - lib/bashly/views/flag/completion_filter.gtx
289
+ - lib/bashly/views/flag/completion_filter_arg.gtx
290
+ - lib/bashly/views/flag/completion_filter_block.gtx
291
+ - lib/bashly/views/flag/completion_filter_no_arg.gtx
292
+ - lib/bashly/views/flag/completion_value_candidates.gtx
294
293
  - lib/bashly/views/flag/conflicts.gtx
295
294
  - lib/bashly/views/flag/needs.gtx
296
295
  - lib/bashly/views/flag/usage.gtx
297
296
  - lib/bashly/views/flag/validations.gtx
298
297
  - lib/bashly/views/variable/definition.gtx
299
- - lib/bashly/views/wrapper/bash3_bouncer.gtx
298
+ - lib/bashly/views/wrapper/bash_version_bouncer.gtx
300
299
  - lib/bashly/views/wrapper/header.gtx
301
300
  - lib/bashly/views/wrapper/wrapper.gtx
302
301
  - lib/bashly/watch.rb
@@ -316,14 +315,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
316
315
  requirements:
317
316
  - - ">="
318
317
  - !ruby/object:Gem::Version
319
- version: '3.2'
318
+ version: '3.3'
320
319
  required_rubygems_version: !ruby/object:Gem::Requirement
321
320
  requirements:
322
321
  - - ">="
323
322
  - !ruby/object:Gem::Version
324
323
  version: '0'
325
324
  requirements: []
326
- rubygems_version: 4.0.15
325
+ rubygems_version: 4.0.17
327
326
  specification_version: 4
328
327
  summary: Bash Command Line Tool Generator
329
328
  test_files: []
@@ -1,231 +0,0 @@
1
- module Bashly
2
- class CompletionBuilder
3
- BUILTIN_PATTERN = /\A<([^>]+)>\z/
4
-
5
- def initialize(command, with_version: true)
6
- @command = command
7
- @with_version = with_version
8
- @patterns = []
9
- @options = {}
10
- @tokens = {}
11
- @token_sources = {}
12
- end
13
-
14
- def call
15
- add_command @command, inherited_global_groups: []
16
-
17
- result = { 'patterns' => @patterns }
18
- result['options'] = @options if @options.any?
19
- result['tokens'] = @tokens if @tokens.any?
20
- result
21
- end
22
-
23
- private
24
-
25
- def add_command(command, inherited_global_groups:)
26
- local_group = add_local_options command
27
- pattern_groups = inherited_global_groups.dup
28
- pattern_groups << local_group if local_group
29
-
30
- @patterns << pattern_for(command, pattern_groups) unless visible_default_command(command)
31
-
32
- child_global_groups = inherited_global_groups.dup
33
- if command.global_flags?
34
- global_group = add_global_options command
35
- child_global_groups << global_group if global_group
36
- end
37
-
38
- command.visible_commands.each do |child|
39
- add_default_command_pattern command, child, pattern_groups
40
- add_command child, inherited_global_groups: child_global_groups
41
- end
42
- end
43
-
44
- def pattern_for(command, option_groups)
45
- parts = [command_path(command)]
46
- parts.concat(option_groups.map { |group| "[#{group} options]" })
47
- parts.concat positional_tokens(command)
48
- parts.join ' '
49
- end
50
-
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
-
83
- def command_path(command)
84
- command_chain(command).map.with_index do |item, index|
85
- index.zero? ? item.name : item.aliases.join('|')
86
- end.join ' '
87
- end
88
-
89
- def command_chain(command)
90
- result = []
91
- current = command
92
- while current
93
- result.unshift current
94
- current = current.parent_command
95
- end
96
- result
97
- end
98
-
99
- def add_local_options(command)
100
- entries = fixed_option_entries(command) + flag_option_entries(command.visible_flags, command)
101
- return if entries.empty?
102
-
103
- name = group_name command
104
- @options[name] = entries
105
- name
106
- end
107
-
108
- def add_global_options(command)
109
- entries = flag_option_entries command.visible_flags, command
110
- return if entries.empty?
111
-
112
- name = "#{group_name(command)}_global"
113
- @options[name] = entries
114
- name
115
- end
116
-
117
- def fixed_option_entries(command)
118
- return [] if !command.root_command? && command.catch_all.catch_help?
119
-
120
- entries = %w[--help|-h]
121
- entries << '--version|-v' if command.root_command? && @with_version
122
- entries
123
- end
124
-
125
- def flag_option_entries(flags, command)
126
- flags.map do |flag|
127
- token_name = flag_token_name flag, command
128
- flag.completion_option_entry token_name
129
- end
130
- end
131
-
132
- def flag_token_name(flag, command)
133
- return unless flag.arg || flag.allowed || flag.completions
134
-
135
- register_token flag.arg || flag.name, command, flag_source(flag)
136
- end
137
-
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
143
- suffix = arg.repeatable ? '...' : nil
144
- "<#{token_name}>#{suffix}"
145
- end
146
- end
147
-
148
- def merge_sources(*sources)
149
- sources.compact.flatten.uniq
150
- end
151
-
152
- def flag_source(flag)
153
- return static_source(flag.allowed) if flag.allowed
154
- return completion_source(flag.completions) if flag.completions
155
-
156
- nil
157
- end
158
-
159
- def arg_source(arg, command)
160
- return static_source(arg.allowed) if arg.allowed
161
- return completion_source(arg.completions) if arg.completions
162
- return completion_source(command.completions) if command.completions
163
-
164
- nil
165
- end
166
-
167
- def static_source(values)
168
- Array(values).compact.map { |value| escape_static_source value }
169
- end
170
-
171
- def completion_source(values)
172
- Array(values).compact.map do |value|
173
- string = value.to_s
174
- builtin = string[BUILTIN_PATTERN, 1]
175
-
176
- if builtin
177
- "+#{builtin}"
178
- else
179
- escape_static_source string
180
- end
181
- end
182
- end
183
-
184
- def escape_static_source(value)
185
- string = value.to_s
186
- string.start_with?('+') ? "+#{string}" : string
187
- end
188
-
189
- def register_token(base_name, command, source)
190
- preferred = token_name base_name
191
- return preferred if register_token_name preferred, source
192
-
193
- scoped = token_name "#{group_name command}_#{base_name}"
194
- return scoped if register_token_name scoped, source
195
-
196
- suffix = 2
197
- loop do
198
- candidate = "#{scoped}_#{suffix}"
199
- return candidate if register_token_name candidate, source
200
-
201
- suffix += 1
202
- end
203
- end
204
-
205
- def register_token_name(name, source)
206
- if @token_sources.has_key? name
207
- return false unless @token_sources[name] == source
208
- else
209
- @token_sources[name] = source
210
- @tokens[name] = source
211
- end
212
-
213
- true
214
- end
215
-
216
- def group_name(command)
217
- token_name command.root_command? ? 'root' : command.action_name
218
- end
219
-
220
- def visible_default_command(command)
221
- command.visible_commands.find(&:default)
222
- end
223
-
224
- def token_name(value)
225
- value.to_s
226
- .gsub(/[^a-zA-Z0-9]+/, '_')
227
- .gsub(/\A_+|_+\z/, '')
228
- .downcase
229
- end
230
- end
231
- end