bashly 1.4.0 → 2.0.0.rc2
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.
- checksums.yaml +4 -4
- data/lib/bashly/commands/completions.rb +3 -41
- data/lib/bashly/completions/README.md +3 -7
- data/lib/bashly/completions/bashly-completions.bash +2 -2
- data/lib/bashly/completions/completely.yaml +0 -4
- data/lib/bashly/concerns/settings_completions.rb +37 -0
- data/lib/bashly/config_validator.rb +18 -3
- data/lib/bashly/docs/arg.yml +12 -6
- data/lib/bashly/docs/command.yml +0 -12
- data/lib/bashly/docs/flag.yml +8 -4
- data/lib/bashly/libraries/libraries.yml +0 -15
- data/lib/bashly/libraries/settings/settings.yml +12 -6
- data/lib/bashly/script/argument.rb +17 -0
- data/lib/bashly/script/command.rb +1 -2
- data/lib/bashly/script/flag.rb +12 -1
- data/lib/bashly/script/introspection/commands.rb +5 -0
- data/lib/bashly/script/wrapper.rb +1 -1
- data/lib/bashly/settings.rb +7 -8
- data/lib/bashly/version.rb +1 -1
- data/lib/bashly/views/argument/completion.gtx +31 -0
- data/lib/bashly/views/argument/completion_filter.gtx +1 -0
- data/lib/bashly/views/command/completion_argument_candidates.gtx +12 -0
- data/lib/bashly/views/command/completion_argument_filter.gtx +25 -0
- data/lib/bashly/views/command/completion_command_candidates.gtx +3 -0
- data/lib/bashly/views/command/completion_flag_candidates.gtx +21 -0
- data/lib/bashly/views/command/completion_function.gtx +24 -0
- data/lib/bashly/views/command/completion_script.gtx +21 -0
- data/lib/bashly/views/command/completion_script_bash.gtx +63 -0
- data/lib/bashly/views/command/completion_script_zsh.gtx +52 -0
- data/lib/bashly/views/command/completion_word_filter.gtx +44 -0
- data/lib/bashly/views/command/completions.gtx +81 -0
- data/lib/bashly/views/command/inspect_args.gtx +3 -3
- data/lib/bashly/views/command/master_script.gtx +7 -4
- data/lib/bashly/views/command/start.gtx +12 -3
- data/lib/bashly/views/flag/completion.gtx +1 -0
- data/lib/bashly/views/flag/completion_filter.gtx +7 -0
- data/lib/bashly/views/flag/completion_filter_arg.gtx +10 -0
- data/lib/bashly/views/flag/completion_filter_block.gtx +8 -0
- data/lib/bashly/views/flag/completion_filter_no_arg.gtx +2 -0
- data/lib/bashly/views/flag/completion_value_candidates.gtx +31 -0
- data/lib/bashly/watch.rb +22 -50
- data/lib/bashly.rb +2 -5
- metadata +39 -39
- data/lib/bashly/completion_builder.rb +0 -231
- data/lib/bashly/concerns/completions.rb +0 -48
- data/lib/bashly/libraries/completions/completions_function.rb +0 -37
- data/lib/bashly/libraries/completions/completions_script.rb +0 -28
- data/lib/bashly/libraries/completions/completions_yaml.rb +0 -26
- /data/lib/bashly/views/wrapper/{bash3_bouncer.gtx → bash_version_bouncer.gtx} +0 -0
|
@@ -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
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
require 'completely'
|
|
2
|
-
require 'bashly/completion_builder'
|
|
3
|
-
|
|
4
|
-
module Bashly
|
|
5
|
-
# This is a `Command` and `Flag` concern responsible for providing bash
|
|
6
|
-
# completion data
|
|
7
|
-
module Completions
|
|
8
|
-
module Flag
|
|
9
|
-
def completion_data(command_full_name)
|
|
10
|
-
comps = allowed || completions
|
|
11
|
-
return {} unless comps
|
|
12
|
-
|
|
13
|
-
aliases.to_h do |name|
|
|
14
|
-
prefix = command_full_name
|
|
15
|
-
prefix = "#{prefix}*" unless prefix.end_with? '*'
|
|
16
|
-
["#{prefix}#{name}", comps]
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def completion_option_entry(token_name = nil)
|
|
21
|
-
result = [aliases.join('|')]
|
|
22
|
-
result << "<#{token_name}>" if token_name
|
|
23
|
-
result << '(repeatable)' if repeatable
|
|
24
|
-
result.join ' '
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
module Command
|
|
29
|
-
def completion_data(with_version: true)
|
|
30
|
-
CompletionBuilder.new(self, with_version: with_version).call
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def completion_script
|
|
34
|
-
completion_generator.script
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def completion_function(name = nil)
|
|
38
|
-
completion_generator.wrapper_function name
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
def completion_generator
|
|
44
|
-
Completely::Completions.new completion_data
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
module Bashly
|
|
2
|
-
module Libraries
|
|
3
|
-
class CompletionsFunction < Base
|
|
4
|
-
def files
|
|
5
|
-
[
|
|
6
|
-
{
|
|
7
|
-
path: "#{Settings.full_lib_dir}/#{function_name}.#{Settings.partials_extension}",
|
|
8
|
-
content: completions_function_code(function_name),
|
|
9
|
-
},
|
|
10
|
-
]
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def post_install_message
|
|
14
|
-
<<~MESSAGE
|
|
15
|
-
In order to enable completions in your script, create a command or a flag (for example: g`#{command.name} completions` or g`#{command.name} --completions`) that calls the g`#{function_name}` function.
|
|
16
|
-
|
|
17
|
-
Your users can then run something like this to enable completions:
|
|
18
|
-
|
|
19
|
-
m`$ eval "$(#{command.name} completions)"`
|
|
20
|
-
MESSAGE
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
private
|
|
24
|
-
|
|
25
|
-
def function_name
|
|
26
|
-
@function_name ||= args[0] || 'send_completions'
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def completions_function_code(function_name)
|
|
30
|
-
[
|
|
31
|
-
"## [@bashly-upgrade completions #{function_name}]",
|
|
32
|
-
command.completion_function(function_name),
|
|
33
|
-
].join "\n"
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
module Bashly
|
|
2
|
-
module Libraries
|
|
3
|
-
class CompletionsScript < Base
|
|
4
|
-
def files
|
|
5
|
-
[
|
|
6
|
-
{
|
|
7
|
-
path: target_path,
|
|
8
|
-
content: command.completion_script,
|
|
9
|
-
},
|
|
10
|
-
]
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def post_install_message
|
|
14
|
-
<<~MESSAGE
|
|
15
|
-
In order to enable completions, run:
|
|
16
|
-
|
|
17
|
-
m`$ source #{target_path}`
|
|
18
|
-
MESSAGE
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
def target_path
|
|
24
|
-
@target_path ||= args[0] || "#{Settings.target_dir}/completions.bash"
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
module Bashly
|
|
2
|
-
module Libraries
|
|
3
|
-
class CompletionsYAML < Base
|
|
4
|
-
def files
|
|
5
|
-
[
|
|
6
|
-
{
|
|
7
|
-
path: target_path,
|
|
8
|
-
content: command.completion_data.to_yaml,
|
|
9
|
-
},
|
|
10
|
-
]
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def post_install_message
|
|
14
|
-
<<~MESSAGE
|
|
15
|
-
This file can be converted to a completions script using the g`completely` gem.
|
|
16
|
-
MESSAGE
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
def target_path
|
|
22
|
-
@target_path ||= args[0] || "#{Settings.target_dir}/completions.yml"
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
File without changes
|