toys-core 0.12.2 → 0.13.0
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/CHANGELOG.md +22 -0
- data/LICENSE.md +1 -1
- data/README.md +4 -1
- data/docs/guide.md +1 -1
- data/lib/toys/acceptor.rb +10 -1
- data/lib/toys/arg_parser.rb +1 -0
- data/lib/toys/cli.rb +127 -107
- data/lib/toys/compat.rb +54 -3
- data/lib/toys/completion.rb +15 -5
- data/lib/toys/context.rb +22 -20
- data/lib/toys/core.rb +6 -2
- data/lib/toys/dsl/base.rb +2 -0
- data/lib/toys/dsl/flag.rb +23 -17
- data/lib/toys/dsl/flag_group.rb +11 -7
- data/lib/toys/dsl/positional_arg.rb +23 -13
- data/lib/toys/dsl/tool.rb +10 -6
- data/lib/toys/errors.rb +63 -8
- data/lib/toys/flag.rb +660 -651
- data/lib/toys/flag_group.rb +19 -6
- data/lib/toys/input_file.rb +9 -3
- data/lib/toys/loader.rb +129 -115
- data/lib/toys/middleware.rb +45 -21
- data/lib/toys/mixin.rb +8 -6
- data/lib/toys/positional_arg.rb +18 -17
- data/lib/toys/settings.rb +81 -67
- data/lib/toys/source_info.rb +33 -24
- data/lib/toys/standard_middleware/add_verbosity_flags.rb +2 -0
- data/lib/toys/standard_middleware/apply_config.rb +1 -0
- data/lib/toys/standard_middleware/handle_usage_errors.rb +1 -0
- data/lib/toys/standard_middleware/set_default_descriptions.rb +1 -0
- data/lib/toys/standard_middleware/show_help.rb +2 -0
- data/lib/toys/standard_middleware/show_root_version.rb +2 -0
- data/lib/toys/standard_mixins/bundler.rb +22 -14
- data/lib/toys/standard_mixins/exec.rb +31 -20
- data/lib/toys/standard_mixins/fileutils.rb +3 -1
- data/lib/toys/standard_mixins/gems.rb +21 -17
- data/lib/toys/standard_mixins/git_cache.rb +5 -7
- data/lib/toys/standard_mixins/highline.rb +8 -8
- data/lib/toys/standard_mixins/terminal.rb +5 -5
- data/lib/toys/standard_mixins/xdg.rb +5 -5
- data/lib/toys/template.rb +9 -7
- data/lib/toys/tool_definition.rb +209 -202
- data/lib/toys/utils/completion_engine.rb +7 -2
- data/lib/toys/utils/exec.rb +158 -127
- data/lib/toys/utils/gems.rb +81 -57
- data/lib/toys/utils/git_cache.rb +674 -45
- data/lib/toys/utils/help_text.rb +27 -3
- data/lib/toys/utils/terminal.rb +10 -2
- data/lib/toys/wrappable_string.rb +9 -2
- data/lib/toys-core.rb +14 -5
- metadata +4 -4
@@ -36,14 +36,6 @@ module Toys
|
|
36
36
|
#
|
37
37
|
KEY = ::Object.new.freeze
|
38
38
|
|
39
|
-
on_initialize do |*args|
|
40
|
-
require "toys/utils/gems"
|
41
|
-
Toys::Utils::Gems.activate("highline", "~> 2.0")
|
42
|
-
require "highline"
|
43
|
-
self[KEY] = ::HighLine.new(*args)
|
44
|
-
self[KEY].use_color = $stdout.tty?
|
45
|
-
end
|
46
|
-
|
47
39
|
##
|
48
40
|
# A tool-wide [HighLine](https://www.rubydoc.info/gems/highline/HighLine)
|
49
41
|
# instance
|
@@ -136,6 +128,14 @@ module Toys
|
|
136
128
|
def new_scope
|
137
129
|
highline.new_scope
|
138
130
|
end
|
131
|
+
|
132
|
+
on_initialize do |*args|
|
133
|
+
require "toys/utils/gems"
|
134
|
+
Toys::Utils::Gems.activate("highline", "~> 2.0")
|
135
|
+
require "highline"
|
136
|
+
self[KEY] = ::HighLine.new(*args)
|
137
|
+
self[KEY].use_color = $stdout.tty?
|
138
|
+
end
|
139
139
|
end
|
140
140
|
end
|
141
141
|
end
|
@@ -35,11 +35,6 @@ module Toys
|
|
35
35
|
#
|
36
36
|
KEY = ::Object.new.freeze
|
37
37
|
|
38
|
-
on_initialize do |**opts|
|
39
|
-
require "toys/utils/terminal"
|
40
|
-
self[KEY] = Utils::Terminal.new(**opts)
|
41
|
-
end
|
42
|
-
|
43
38
|
##
|
44
39
|
# A tool-wide terminal instance
|
45
40
|
# @return [Toys::Utils::Terminal]
|
@@ -139,6 +134,11 @@ module Toys
|
|
139
134
|
frame_length: frame_length, frames: frames, style: style,
|
140
135
|
&block)
|
141
136
|
end
|
137
|
+
|
138
|
+
on_initialize do |**opts|
|
139
|
+
require "toys/utils/terminal"
|
140
|
+
self[KEY] = Utils::Terminal.new(**opts)
|
141
|
+
end
|
142
142
|
end
|
143
143
|
end
|
144
144
|
end
|
@@ -33,11 +33,6 @@ module Toys
|
|
33
33
|
#
|
34
34
|
KEY = ::Object.new.freeze
|
35
35
|
|
36
|
-
on_initialize do
|
37
|
-
require "toys/utils/xdg"
|
38
|
-
self[KEY] = Utils::XDG.new
|
39
|
-
end
|
40
|
-
|
41
36
|
##
|
42
37
|
# Access XDG utility methods.
|
43
38
|
#
|
@@ -46,6 +41,11 @@ module Toys
|
|
46
41
|
def xdg
|
47
42
|
self[KEY]
|
48
43
|
end
|
44
|
+
|
45
|
+
on_initialize do
|
46
|
+
require "toys/utils/xdg"
|
47
|
+
self[KEY] = Utils::XDG.new
|
48
|
+
end
|
49
49
|
end
|
50
50
|
|
51
51
|
##
|
data/lib/toys/template.rb
CHANGED
@@ -84,13 +84,6 @@ module Toys
|
|
84
84
|
template_class
|
85
85
|
end
|
86
86
|
|
87
|
-
## @private
|
88
|
-
def self.included(mod)
|
89
|
-
return if mod.respond_to?(:on_expand)
|
90
|
-
mod.extend(ClassMethods)
|
91
|
-
mod.include(Context::Key)
|
92
|
-
end
|
93
|
-
|
94
87
|
##
|
95
88
|
# Class methods that will be added to a template class.
|
96
89
|
#
|
@@ -118,5 +111,14 @@ module Toys
|
|
118
111
|
#
|
119
112
|
attr_accessor :expansion
|
120
113
|
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# @private
|
117
|
+
#
|
118
|
+
def self.included(mod)
|
119
|
+
return if mod.respond_to?(:on_expand)
|
120
|
+
mod.extend(ClassMethods)
|
121
|
+
mod.include(Context::Key)
|
122
|
+
end
|
121
123
|
end
|
122
124
|
end
|
data/lib/toys/tool_definition.rb
CHANGED
@@ -11,9 +11,209 @@ module Toys
|
|
11
11
|
# tool is executed.
|
12
12
|
#
|
13
13
|
class ToolDefinition
|
14
|
+
##
|
15
|
+
# A Completion that implements the default algorithm for a tool.
|
16
|
+
#
|
17
|
+
class DefaultCompletion < Completion::Base
|
18
|
+
##
|
19
|
+
# Create a completion given configuration options.
|
20
|
+
#
|
21
|
+
# @param complete_subtools [Boolean] Whether to complete subtool names
|
22
|
+
# @param include_hidden_subtools [Boolean] Whether to include hidden
|
23
|
+
# subtools (i.e. those beginning with an underscore)
|
24
|
+
# @param complete_args [Boolean] Whether to complete positional args
|
25
|
+
# @param complete_flags [Boolean] Whether to complete flag names
|
26
|
+
# @param complete_flag_values [Boolean] Whether to complete flag values
|
27
|
+
# @param delegation_target [Array<String>,nil] Delegation target, or
|
28
|
+
# `nil` if none.
|
29
|
+
#
|
30
|
+
def initialize(complete_subtools: true, include_hidden_subtools: false,
|
31
|
+
complete_args: true, complete_flags: true, complete_flag_values: true,
|
32
|
+
delegation_target: nil)
|
33
|
+
super()
|
34
|
+
@complete_subtools = complete_subtools
|
35
|
+
@include_hidden_subtools = include_hidden_subtools
|
36
|
+
@complete_flags = complete_flags
|
37
|
+
@complete_args = complete_args
|
38
|
+
@complete_flag_values = complete_flag_values
|
39
|
+
@delegation_target = delegation_target
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Whether to complete subtool names
|
44
|
+
# @return [Boolean]
|
45
|
+
#
|
46
|
+
def complete_subtools?
|
47
|
+
@complete_subtools
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Whether to include hidden subtools
|
52
|
+
# @return [Boolean]
|
53
|
+
#
|
54
|
+
def include_hidden_subtools?
|
55
|
+
@include_hidden_subtools
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Whether to complete flags
|
60
|
+
# @return [Boolean]
|
61
|
+
#
|
62
|
+
def complete_flags?
|
63
|
+
@complete_flags
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Whether to complete positional args
|
68
|
+
# @return [Boolean]
|
69
|
+
#
|
70
|
+
def complete_args?
|
71
|
+
@complete_args
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Whether to complete flag values
|
76
|
+
# @return [Boolean]
|
77
|
+
#
|
78
|
+
def complete_flag_values?
|
79
|
+
@complete_flag_values
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Delegation target, or nil for none.
|
84
|
+
# @return [Array<String>] if there is a delegation target
|
85
|
+
# @return [nil] if there is no delegation target
|
86
|
+
#
|
87
|
+
attr_accessor :delegation_target
|
88
|
+
|
89
|
+
##
|
90
|
+
# Returns candidates for the current completion.
|
91
|
+
#
|
92
|
+
# @param context [Toys::Completion::Context] the current completion
|
93
|
+
# context including the string fragment.
|
94
|
+
# @return [Array<Toys::Completion::Candidate>] an array of candidates
|
95
|
+
#
|
96
|
+
def call(context)
|
97
|
+
candidates = valued_flag_candidates(context)
|
98
|
+
return candidates if candidates
|
99
|
+
candidates = subtool_or_arg_candidates(context)
|
100
|
+
candidates += plain_flag_candidates(context)
|
101
|
+
candidates += flag_value_candidates(context)
|
102
|
+
if delegation_target
|
103
|
+
delegate_tool = context.cli.loader.lookup_specific(delegation_target)
|
104
|
+
if delegate_tool
|
105
|
+
context = context.with(previous_words: delegation_target)
|
106
|
+
candidates += delegate_tool.completion.call(context)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
candidates
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def valued_flag_candidates(context)
|
115
|
+
return unless @complete_flag_values
|
116
|
+
arg_parser = context.arg_parser
|
117
|
+
return unless arg_parser.flags_allowed?
|
118
|
+
active_flag_def = arg_parser.active_flag_def
|
119
|
+
return if active_flag_def && active_flag_def.value_type == :required
|
120
|
+
match = /\A(--\w[?\w-]*)=(.*)\z/.match(context.fragment_prefix)
|
121
|
+
return unless match
|
122
|
+
flag_value_context = context.with(fragment_prefix: match[2])
|
123
|
+
flag_def = flag_value_context.tool.resolve_flag(match[1]).unique_flag
|
124
|
+
return [] unless flag_def
|
125
|
+
flag_def.value_completion.call(flag_value_context)
|
126
|
+
end
|
127
|
+
|
128
|
+
def subtool_or_arg_candidates(context)
|
129
|
+
return [] if context.arg_parser.active_flag_def
|
130
|
+
return [] if context.arg_parser.flags_allowed? && context.fragment.start_with?("-")
|
131
|
+
subtool_candidates(context) || arg_candidates(context)
|
132
|
+
end
|
133
|
+
|
134
|
+
def subtool_candidates(context)
|
135
|
+
return if !@complete_subtools || !context.args.empty?
|
136
|
+
tool_name, prefix, fragment = analyze_subtool_fragment(context)
|
137
|
+
return unless tool_name
|
138
|
+
subtools = context.cli.loader.list_subtools(tool_name,
|
139
|
+
include_hidden: @include_hidden_subtools)
|
140
|
+
return if subtools.empty?
|
141
|
+
candidates = []
|
142
|
+
subtools.each do |subtool|
|
143
|
+
name = subtool.simple_name
|
144
|
+
candidates << Completion::Candidate.new("#{prefix}#{name}") if name.start_with?(fragment)
|
145
|
+
end
|
146
|
+
candidates
|
147
|
+
end
|
148
|
+
|
149
|
+
def analyze_subtool_fragment(context)
|
150
|
+
tool_name = context.tool.full_name
|
151
|
+
prefix = ""
|
152
|
+
fragment = context.fragment
|
153
|
+
delims = context.cli.extra_delimiters
|
154
|
+
unless context.fragment_prefix.empty?
|
155
|
+
if !context.fragment_prefix.end_with?(":") || !delims.include?(":")
|
156
|
+
return [nil, nil, nil]
|
157
|
+
end
|
158
|
+
tool_name += context.fragment_prefix.split(":")
|
159
|
+
end
|
160
|
+
unless delims.empty?
|
161
|
+
delims_regex = ::Regexp.escape(delims)
|
162
|
+
if (match = /\A((.+)[#{delims_regex}])(.*)\z/.match(fragment))
|
163
|
+
fragment = match[3]
|
164
|
+
tool_name += match[2].split(/[#{delims_regex}]/)
|
165
|
+
prefix = match[1]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
[tool_name, prefix, fragment]
|
169
|
+
end
|
170
|
+
|
171
|
+
def arg_candidates(context)
|
172
|
+
return unless @complete_args
|
173
|
+
arg_def = context.arg_parser.next_arg_def
|
174
|
+
return [] unless arg_def
|
175
|
+
arg_def.completion.call(context)
|
176
|
+
end
|
177
|
+
|
178
|
+
def plain_flag_candidates(context)
|
179
|
+
return [] if !@complete_flags || context[:disable_flags]
|
180
|
+
arg_parser = context.arg_parser
|
181
|
+
return [] unless arg_parser.flags_allowed?
|
182
|
+
flag_def = arg_parser.active_flag_def
|
183
|
+
return [] if flag_def && flag_def.value_type == :required
|
184
|
+
return [] if context.fragment =~ /\A[^-]/ || !context.fragment_prefix.empty?
|
185
|
+
context.tool.flags.flat_map do |flag|
|
186
|
+
flag.flag_completion.call(context)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def flag_value_candidates(context)
|
191
|
+
return unless @complete_flag_values
|
192
|
+
arg_parser = context.arg_parser
|
193
|
+
flag_def = arg_parser.active_flag_def
|
194
|
+
return [] unless flag_def
|
195
|
+
return [] if @complete_flags && arg_parser.flags_allowed? &&
|
196
|
+
flag_def.value_type == :optional && context.fragment.start_with?("-")
|
197
|
+
flag_def.value_completion.call(context)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
##
|
202
|
+
# Tool-based settings class.
|
203
|
+
#
|
204
|
+
# The following settings are supported:
|
205
|
+
#
|
206
|
+
# * `propagate_helper_methods` (_Boolean_) - Whether subtools should
|
207
|
+
# inherit methods defined by parent tools. Defaults to `false`.
|
208
|
+
#
|
209
|
+
class Settings < ::Toys::Settings
|
210
|
+
settings_attr :propagate_helper_methods, default: false
|
211
|
+
end
|
212
|
+
|
14
213
|
##
|
15
214
|
# Create a new tool.
|
16
215
|
# Should be created only from the DSL via the Loader.
|
216
|
+
#
|
17
217
|
# @private
|
18
218
|
#
|
19
219
|
def initialize(parent, full_name, priority, source_root, middleware_stack, middleware_lookup,
|
@@ -40,6 +240,7 @@ module Toys
|
|
40
240
|
# Reset the definition of this tool, deleting all definition data but
|
41
241
|
# leaving named acceptors, mixins, and templates intact.
|
42
242
|
# Should be called only from the DSL.
|
243
|
+
#
|
43
244
|
# @private
|
44
245
|
#
|
45
246
|
def reset_definition
|
@@ -48,7 +249,7 @@ module Toys
|
|
48
249
|
@source_info = nil
|
49
250
|
@definition_finished = false
|
50
251
|
|
51
|
-
@desc = WrappableString.new
|
252
|
+
@desc = WrappableString.new
|
52
253
|
@long_desc = []
|
53
254
|
|
54
255
|
@default_data = {}
|
@@ -470,8 +671,8 @@ module Toys
|
|
470
671
|
##
|
471
672
|
# Include the given mixin in the tool class.
|
472
673
|
#
|
473
|
-
# The mixin must be given as a module. You can use {#lookup_mixin}
|
474
|
-
#
|
674
|
+
# The mixin must be given as a module. You can use {#lookup_mixin} to
|
675
|
+
# resolve named mixins.
|
475
676
|
#
|
476
677
|
# @param mod [Module] The mixin module
|
477
678
|
# @return [self]
|
@@ -1074,6 +1275,7 @@ module Toys
|
|
1074
1275
|
|
1075
1276
|
##
|
1076
1277
|
# Lookup the custom context directory in this tool and its ancestors.
|
1278
|
+
#
|
1077
1279
|
# @private
|
1078
1280
|
#
|
1079
1281
|
def lookup_custom_context_directory
|
@@ -1082,6 +1284,7 @@ module Toys
|
|
1082
1284
|
|
1083
1285
|
##
|
1084
1286
|
# Mark this tool as having at least one module included.
|
1287
|
+
#
|
1085
1288
|
# @private
|
1086
1289
|
#
|
1087
1290
|
def mark_includes_modules
|
@@ -1093,6 +1296,7 @@ module Toys
|
|
1093
1296
|
##
|
1094
1297
|
# Complete definition and run middleware configs. Should be called from
|
1095
1298
|
# the Loader only.
|
1299
|
+
#
|
1096
1300
|
# @private
|
1097
1301
|
#
|
1098
1302
|
def finish_definition(loader)
|
@@ -1114,6 +1318,7 @@ module Toys
|
|
1114
1318
|
|
1115
1319
|
##
|
1116
1320
|
# Run all initializers against a context. Called from the Runner.
|
1321
|
+
#
|
1117
1322
|
# @private
|
1118
1323
|
#
|
1119
1324
|
def run_initializers(context)
|
@@ -1125,6 +1330,7 @@ module Toys
|
|
1125
1330
|
##
|
1126
1331
|
# Check that the tool can still be defined. Should be called internally
|
1127
1332
|
# or from the DSL only.
|
1333
|
+
#
|
1128
1334
|
# @private
|
1129
1335
|
#
|
1130
1336
|
def check_definition_state(is_arg: false, is_method: false)
|
@@ -1143,205 +1349,6 @@ module Toys
|
|
1143
1349
|
self
|
1144
1350
|
end
|
1145
1351
|
|
1146
|
-
##
|
1147
|
-
# A Completion that implements the default algorithm for a tool.
|
1148
|
-
#
|
1149
|
-
class DefaultCompletion < Completion::Base
|
1150
|
-
##
|
1151
|
-
# Create a completion given configuration options.
|
1152
|
-
#
|
1153
|
-
# @param complete_subtools [Boolean] Whether to complete subtool names
|
1154
|
-
# @param include_hidden_subtools [Boolean] Whether to include hidden
|
1155
|
-
# subtools (i.e. those beginning with an underscore)
|
1156
|
-
# @param complete_args [Boolean] Whether to complete positional args
|
1157
|
-
# @param complete_flags [Boolean] Whether to complete flag names
|
1158
|
-
# @param complete_flag_values [Boolean] Whether to complete flag values
|
1159
|
-
# @param delegation_target [Array<String>,nil] Delegation target, or
|
1160
|
-
# `nil` if none.
|
1161
|
-
#
|
1162
|
-
def initialize(complete_subtools: true, include_hidden_subtools: false,
|
1163
|
-
complete_args: true, complete_flags: true, complete_flag_values: true,
|
1164
|
-
delegation_target: nil)
|
1165
|
-
super()
|
1166
|
-
@complete_subtools = complete_subtools
|
1167
|
-
@include_hidden_subtools = include_hidden_subtools
|
1168
|
-
@complete_flags = complete_flags
|
1169
|
-
@complete_args = complete_args
|
1170
|
-
@complete_flag_values = complete_flag_values
|
1171
|
-
@delegation_target = delegation_target
|
1172
|
-
end
|
1173
|
-
|
1174
|
-
##
|
1175
|
-
# Whether to complete subtool names
|
1176
|
-
# @return [Boolean]
|
1177
|
-
#
|
1178
|
-
def complete_subtools?
|
1179
|
-
@complete_subtools
|
1180
|
-
end
|
1181
|
-
|
1182
|
-
##
|
1183
|
-
# Whether to include hidden subtools
|
1184
|
-
# @return [Boolean]
|
1185
|
-
#
|
1186
|
-
def include_hidden_subtools?
|
1187
|
-
@include_hidden_subtools
|
1188
|
-
end
|
1189
|
-
|
1190
|
-
##
|
1191
|
-
# Whether to complete flags
|
1192
|
-
# @return [Boolean]
|
1193
|
-
#
|
1194
|
-
def complete_flags?
|
1195
|
-
@complete_flags
|
1196
|
-
end
|
1197
|
-
|
1198
|
-
##
|
1199
|
-
# Whether to complete positional args
|
1200
|
-
# @return [Boolean]
|
1201
|
-
#
|
1202
|
-
def complete_args?
|
1203
|
-
@complete_args
|
1204
|
-
end
|
1205
|
-
|
1206
|
-
##
|
1207
|
-
# Whether to complete flag values
|
1208
|
-
# @return [Boolean]
|
1209
|
-
#
|
1210
|
-
def complete_flag_values?
|
1211
|
-
@complete_flag_values
|
1212
|
-
end
|
1213
|
-
|
1214
|
-
##
|
1215
|
-
# Delegation target, or nil for none.
|
1216
|
-
# @return [Array<String>] if there is a delegation target
|
1217
|
-
# @return [nil] if there is no delegation target
|
1218
|
-
#
|
1219
|
-
attr_accessor :delegation_target
|
1220
|
-
|
1221
|
-
##
|
1222
|
-
# Returns candidates for the current completion.
|
1223
|
-
#
|
1224
|
-
# @param context [Toys::Completion::Context] the current completion
|
1225
|
-
# context including the string fragment.
|
1226
|
-
# @return [Array<Toys::Completion::Candidate>] an array of candidates
|
1227
|
-
#
|
1228
|
-
def call(context)
|
1229
|
-
candidates = valued_flag_candidates(context)
|
1230
|
-
return candidates if candidates
|
1231
|
-
candidates = subtool_or_arg_candidates(context)
|
1232
|
-
candidates += plain_flag_candidates(context)
|
1233
|
-
candidates += flag_value_candidates(context)
|
1234
|
-
if delegation_target
|
1235
|
-
delegate_tool = context.cli.loader.lookup_specific(delegation_target)
|
1236
|
-
if delegate_tool
|
1237
|
-
context = context.with(previous_words: delegation_target)
|
1238
|
-
candidates += delegate_tool.completion.call(context)
|
1239
|
-
end
|
1240
|
-
end
|
1241
|
-
candidates
|
1242
|
-
end
|
1243
|
-
|
1244
|
-
private
|
1245
|
-
|
1246
|
-
def valued_flag_candidates(context)
|
1247
|
-
return unless @complete_flag_values
|
1248
|
-
arg_parser = context.arg_parser
|
1249
|
-
return unless arg_parser.flags_allowed?
|
1250
|
-
active_flag_def = arg_parser.active_flag_def
|
1251
|
-
return if active_flag_def && active_flag_def.value_type == :required
|
1252
|
-
match = /\A(--\w[?\w-]*)=(.*)\z/.match(context.fragment_prefix)
|
1253
|
-
return unless match
|
1254
|
-
flag_value_context = context.with(fragment_prefix: match[2])
|
1255
|
-
flag_def = flag_value_context.tool.resolve_flag(match[1]).unique_flag
|
1256
|
-
return [] unless flag_def
|
1257
|
-
flag_def.value_completion.call(flag_value_context)
|
1258
|
-
end
|
1259
|
-
|
1260
|
-
def subtool_or_arg_candidates(context)
|
1261
|
-
return [] if context.arg_parser.active_flag_def
|
1262
|
-
return [] if context.arg_parser.flags_allowed? && context.fragment.start_with?("-")
|
1263
|
-
subtool_candidates(context) || arg_candidates(context)
|
1264
|
-
end
|
1265
|
-
|
1266
|
-
def subtool_candidates(context)
|
1267
|
-
return if !@complete_subtools || !context.args.empty?
|
1268
|
-
tool_name, prefix, fragment = analyze_subtool_fragment(context)
|
1269
|
-
return unless tool_name
|
1270
|
-
subtools = context.cli.loader.list_subtools(tool_name,
|
1271
|
-
include_hidden: @include_hidden_subtools)
|
1272
|
-
return if subtools.empty?
|
1273
|
-
candidates = []
|
1274
|
-
subtools.each do |subtool|
|
1275
|
-
name = subtool.simple_name
|
1276
|
-
candidates << Completion::Candidate.new("#{prefix}#{name}") if name.start_with?(fragment)
|
1277
|
-
end
|
1278
|
-
candidates
|
1279
|
-
end
|
1280
|
-
|
1281
|
-
def analyze_subtool_fragment(context)
|
1282
|
-
tool_name = context.tool.full_name
|
1283
|
-
prefix = ""
|
1284
|
-
fragment = context.fragment
|
1285
|
-
delims = context.cli.extra_delimiters
|
1286
|
-
unless context.fragment_prefix.empty?
|
1287
|
-
if !context.fragment_prefix.end_with?(":") || !delims.include?(":")
|
1288
|
-
return [nil, nil, nil]
|
1289
|
-
end
|
1290
|
-
tool_name += context.fragment_prefix.split(":")
|
1291
|
-
end
|
1292
|
-
unless delims.empty?
|
1293
|
-
delims_regex = ::Regexp.escape(delims)
|
1294
|
-
if (match = /\A((.+)[#{delims_regex}])(.*)\z/.match(fragment))
|
1295
|
-
fragment = match[3]
|
1296
|
-
tool_name += match[2].split(/[#{delims_regex}]/)
|
1297
|
-
prefix = match[1]
|
1298
|
-
end
|
1299
|
-
end
|
1300
|
-
[tool_name, prefix, fragment]
|
1301
|
-
end
|
1302
|
-
|
1303
|
-
def arg_candidates(context)
|
1304
|
-
return unless @complete_args
|
1305
|
-
arg_def = context.arg_parser.next_arg_def
|
1306
|
-
return [] unless arg_def
|
1307
|
-
arg_def.completion.call(context)
|
1308
|
-
end
|
1309
|
-
|
1310
|
-
def plain_flag_candidates(context)
|
1311
|
-
return [] if !@complete_flags || context[:disable_flags]
|
1312
|
-
arg_parser = context.arg_parser
|
1313
|
-
return [] unless arg_parser.flags_allowed?
|
1314
|
-
flag_def = arg_parser.active_flag_def
|
1315
|
-
return [] if flag_def && flag_def.value_type == :required
|
1316
|
-
return [] if context.fragment =~ /\A[^-]/ || !context.fragment_prefix.empty?
|
1317
|
-
context.tool.flags.flat_map do |flag|
|
1318
|
-
flag.flag_completion.call(context)
|
1319
|
-
end
|
1320
|
-
end
|
1321
|
-
|
1322
|
-
def flag_value_candidates(context)
|
1323
|
-
return unless @complete_flag_values
|
1324
|
-
arg_parser = context.arg_parser
|
1325
|
-
flag_def = arg_parser.active_flag_def
|
1326
|
-
return [] unless flag_def
|
1327
|
-
return [] if @complete_flags && arg_parser.flags_allowed? &&
|
1328
|
-
flag_def.value_type == :optional && context.fragment.start_with?("-")
|
1329
|
-
flag_def.value_completion.call(context)
|
1330
|
-
end
|
1331
|
-
end
|
1332
|
-
|
1333
|
-
##
|
1334
|
-
# Tool-based settings class.
|
1335
|
-
#
|
1336
|
-
# The following settings are supported:
|
1337
|
-
#
|
1338
|
-
# * `propagate_helper_methods` (_Boolean_) - Whether subtools should
|
1339
|
-
# inherit methods defined by parent tools. Defaults to `false`.
|
1340
|
-
#
|
1341
|
-
class Settings < ::Toys::Settings
|
1342
|
-
settings_attr :propagate_helper_methods, default: false
|
1343
|
-
end
|
1344
|
-
|
1345
1352
|
private
|
1346
1353
|
|
1347
1354
|
def create_class
|
@@ -54,6 +54,7 @@ module Toys
|
|
54
54
|
|
55
55
|
##
|
56
56
|
# Internal completion method designed for testing.
|
57
|
+
#
|
57
58
|
# @private
|
58
59
|
#
|
59
60
|
def run_internal(line)
|
@@ -78,7 +79,9 @@ module Toys
|
|
78
79
|
end
|
79
80
|
|
80
81
|
class << self
|
81
|
-
##
|
82
|
+
##
|
83
|
+
# @private
|
84
|
+
#
|
82
85
|
def split(line)
|
83
86
|
words = []
|
84
87
|
field = ::String.new
|
@@ -97,7 +100,9 @@ module Toys
|
|
97
100
|
words
|
98
101
|
end
|
99
102
|
|
100
|
-
##
|
103
|
+
##
|
104
|
+
# @private
|
105
|
+
#
|
101
106
|
def format_candidate(candidate, quote_type)
|
102
107
|
str = candidate.to_s
|
103
108
|
partial = candidate.is_a?(Completion::Candidate) ? candidate.partial? : false
|