command_kit-completion 0.1.1 → 0.2.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 +14 -0
- data/lib/command_kit/completion/task.rb +38 -13
- data/lib/command_kit/completion/version.rb +1 -1
- data/spec/task_spec.rb +196 -10
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f85e448a2df37a8bc6231b839b8e56992432498384e6ea4c2e1060a9485c874
|
4
|
+
data.tar.gz: 898168ab4ed70e3e595de27c933432a085976ea81980c7bcc3572e6e2cc4c38c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45ceb26079e0d5caf31e94ea0851fc30e5175661491bed0d6da4f57feb3bc37352ef48e9f7d817f5dced1825db2aa94e0500387a8175dde6b805921c62453ab6
|
7
|
+
data.tar.gz: 8858593122d06c2e4fff8d5f78fae75cd8f23665732131d36eb2fd9c52a51e94a8aa5fe3920b5b622a4f03a16360f442b79e6fd5a9b1c96cf78389c1871a6872
|
data/ChangeLog.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
### 0.2.0 / 2024-04-26
|
2
|
+
|
3
|
+
* Also generate completion rules for option's short flags.
|
4
|
+
* Also generate `<file>`, `<directory>`, `<hostname>`, and `<user>` completion
|
5
|
+
rules for options who's value is named `FILE`, `DIR`, `HOST`, `USER`
|
6
|
+
(or ends in `_FILE`, `_DIR`, `_HOST`, `_USER`), respectively.
|
7
|
+
* Also generate `<file>`, `<directory>`, `<hostname>`, and `<user>` completion
|
8
|
+
rules for the command's first argument if it's named `FILE`, `DIR`, `HOST`,
|
9
|
+
`USER` (or ends in `_FILE`, `_DIR`, `_HOST`, `_USER`), respectively.
|
10
|
+
|
11
|
+
### 0.1.2 / 2023-12-18
|
12
|
+
|
13
|
+
* Fix namespace conflict between `FileUtils` and `CommandKit::FileUtils`.
|
14
|
+
|
1
15
|
### 0.1.1 / 2023-12-18
|
2
16
|
|
3
17
|
* Ensure that the parent directory of the output file exists before writing to
|
@@ -90,7 +90,7 @@ module CommandKit
|
|
90
90
|
completions.script
|
91
91
|
end
|
92
92
|
|
93
|
-
FileUtils.mkdir_p(File.dirname(@output_file))
|
93
|
+
::FileUtils.mkdir_p(File.dirname(@output_file))
|
94
94
|
File.write(@output_file,shell_script)
|
95
95
|
end
|
96
96
|
|
@@ -110,13 +110,25 @@ module CommandKit
|
|
110
110
|
Object.const_get(@class_name)
|
111
111
|
end
|
112
112
|
|
113
|
-
#
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
113
|
+
#
|
114
|
+
# Maps the argument name strings to completely suggestion `<keyword>`s.
|
115
|
+
#
|
116
|
+
# @param [String] arg
|
117
|
+
# The argument name.
|
118
|
+
#
|
119
|
+
# @return [String, nil]
|
120
|
+
# The suggestion keyword for the argument name.
|
121
|
+
#
|
122
|
+
# @since 0.2.0
|
123
|
+
#
|
124
|
+
def suggestion_for_argument(arg)
|
125
|
+
case arg
|
126
|
+
when /\AFILE\z|_FILE\z/ then '<file>'
|
127
|
+
when /\ADIR\z|_DIR\z/ then '<directory>'
|
128
|
+
when /\AHOST\z|_HOST\z/ then '<hostname>'
|
129
|
+
when /\AUSER\z|_USER\z/ then '<user>'
|
130
|
+
end
|
131
|
+
end
|
120
132
|
|
121
133
|
#
|
122
134
|
# Generates the completion rules for the given [command_kit] command
|
@@ -139,20 +151,26 @@ module CommandKit
|
|
139
151
|
# add all long option flags
|
140
152
|
command_class.options.each_value do |option|
|
141
153
|
completions[command_name] << option.long
|
154
|
+
completions[command_name] << option.short if option.short
|
142
155
|
|
143
156
|
if option.value
|
144
|
-
if (
|
157
|
+
if (suggestion = suggestion_for_argument(option.value.usage))
|
158
|
+
command_pattern = "#{command_name}*#{option.long}"
|
159
|
+
|
145
160
|
# add a special rule if the option's value USAGE maps to a
|
146
161
|
# 'completely' completion keyword (ex: `FILE` -> `<file>`).
|
147
|
-
completions[
|
148
|
-
|
149
|
-
|
162
|
+
completions[command_pattern] = [suggestion]
|
163
|
+
|
164
|
+
if option.short
|
165
|
+
# also add another rule with the option's short flag
|
166
|
+
completions["#{command_name}*#{option.short}"] = [suggestion]
|
167
|
+
end
|
150
168
|
end
|
151
169
|
end
|
152
170
|
end
|
153
171
|
end
|
154
172
|
|
155
|
-
# sub-commands
|
173
|
+
# sub-commands / first argument
|
156
174
|
if command_class.include?(CommandKit::Commands)
|
157
175
|
command_class.commands.each do |subcommand_name,subcommand|
|
158
176
|
# add all sub-command names
|
@@ -165,6 +183,13 @@ module CommandKit
|
|
165
183
|
end
|
166
184
|
|
167
185
|
completions[command_name].concat(command_class.command_aliases.keys)
|
186
|
+
elsif command_class.include?(CommandKit::Arguments)
|
187
|
+
if (argument = command_class.arguments.values.first)
|
188
|
+
if (suggestion = suggestion_for_argument(argument.usage))
|
189
|
+
# add a suggestion for the first argument
|
190
|
+
completions[command_name] << suggestion
|
191
|
+
end
|
192
|
+
end
|
168
193
|
end
|
169
194
|
|
170
195
|
# filter out any command's that have no options/sub-commands
|
data/spec/task_spec.rb
CHANGED
@@ -219,6 +219,140 @@ describe CommandKit::Completion::Task do
|
|
219
219
|
end
|
220
220
|
end
|
221
221
|
|
222
|
+
context "when the command class includes CommandKit::Arguments" do
|
223
|
+
context "and has at least one argument" do
|
224
|
+
context "and it's named FILE" do
|
225
|
+
class TestCommandWithFILEArgument < CommandKit::Command
|
226
|
+
|
227
|
+
command_name 'test'
|
228
|
+
|
229
|
+
option :foo, desc: 'Foo option'
|
230
|
+
|
231
|
+
argument :bar, usage: 'FILE', desc: 'Bar option'
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
let(:command_class) { TestCommandWithFILEArgument }
|
236
|
+
|
237
|
+
it "must add '<file>' to the command's completion rule" do
|
238
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
239
|
+
{
|
240
|
+
"test" => %w[--foo <file>]
|
241
|
+
}
|
242
|
+
)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
context "and it's named DIR" do
|
247
|
+
class TestCommandWithDIRArgument < CommandKit::Command
|
248
|
+
|
249
|
+
command_name 'test'
|
250
|
+
|
251
|
+
option :foo, desc: 'Foo option'
|
252
|
+
|
253
|
+
argument :bar, usage: 'DIR', desc: 'Bar option'
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
let(:command_class) { TestCommandWithDIRArgument }
|
258
|
+
|
259
|
+
it "must add '<directory>' to the command's completion rule" do
|
260
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
261
|
+
{
|
262
|
+
"test" => %w[--foo <directory>]
|
263
|
+
}
|
264
|
+
)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
context "and it's named HOST" do
|
269
|
+
class TestCommandWithHOSTArgument < CommandKit::Command
|
270
|
+
|
271
|
+
command_name 'test'
|
272
|
+
|
273
|
+
option :foo, desc: 'Foo option'
|
274
|
+
|
275
|
+
argument :bar, usage: 'HOST', desc: 'Bar option'
|
276
|
+
|
277
|
+
end
|
278
|
+
|
279
|
+
let(:command_class) { TestCommandWithHOSTArgument }
|
280
|
+
|
281
|
+
it "must add '<hostname>' to the command's completion rule" do
|
282
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
283
|
+
{
|
284
|
+
"test" => %w[--foo <hostname>]
|
285
|
+
}
|
286
|
+
)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
context "and it's named USER" do
|
291
|
+
class TestCommandWithUSERArgument < CommandKit::Command
|
292
|
+
|
293
|
+
command_name 'test'
|
294
|
+
|
295
|
+
option :foo, desc: 'Foo option'
|
296
|
+
|
297
|
+
argument :bar, usage: 'USER', desc: 'Bar option'
|
298
|
+
|
299
|
+
end
|
300
|
+
|
301
|
+
let(:command_class) { TestCommandWithUSERArgument }
|
302
|
+
|
303
|
+
it "must add '<user>' to the command's completion rule" do
|
304
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
305
|
+
{
|
306
|
+
"test" => %w[--foo <user>]
|
307
|
+
}
|
308
|
+
)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
context "but it's named something else" do
|
313
|
+
class TestCommandWithArgument < CommandKit::Command
|
314
|
+
|
315
|
+
command_name 'test'
|
316
|
+
|
317
|
+
option :foo, desc: 'Foo option'
|
318
|
+
|
319
|
+
argument :bar, usage: 'BAR', desc: 'Bar option'
|
320
|
+
|
321
|
+
end
|
322
|
+
|
323
|
+
let(:command_class) { TestCommandWithArgument }
|
324
|
+
|
325
|
+
it "must not add additional suggestions to the command's completion rule" do
|
326
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
327
|
+
{
|
328
|
+
"test" => %w[--foo]
|
329
|
+
}
|
330
|
+
)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
context "but has no arguments" do
|
336
|
+
class TestCommandWithoutArguments < CommandKit::Command
|
337
|
+
|
338
|
+
command_name 'test'
|
339
|
+
|
340
|
+
option :foo, desc: 'Foo option'
|
341
|
+
|
342
|
+
end
|
343
|
+
|
344
|
+
let(:command_class) { TestCommandWithoutArguments }
|
345
|
+
|
346
|
+
it "must not add additional suggestions" do
|
347
|
+
expect(subject.completion_rules_for(command_class)).to eq(
|
348
|
+
{
|
349
|
+
"test" => %w[--foo]
|
350
|
+
}
|
351
|
+
)
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
222
356
|
context "when the command class includes CommandKit::Commands" do
|
223
357
|
class TestCommandWithSubCommands < CommandKit::Command
|
224
358
|
include CommandKit::Commands
|
@@ -259,7 +393,7 @@ describe CommandKit::Completion::Task do
|
|
259
393
|
it "must add completion rules for the other commands" do
|
260
394
|
expect(subject.completion_rules_for(command_class)).to eq(
|
261
395
|
{
|
262
|
-
"test" => %w[--global-option help foo bar],
|
396
|
+
"test" => %w[--global-option -g help foo bar],
|
263
397
|
"test foo" => %w[--foo-opt1 --foo-opt2],
|
264
398
|
"test bar" => %w[--bar-opt1 --bar-opt2]
|
265
399
|
}
|
@@ -309,7 +443,7 @@ describe CommandKit::Completion::Task do
|
|
309
443
|
it "must include the command aliases in the completion rules" do
|
310
444
|
expect(subject.completion_rules_for(command_class)).to eq(
|
311
445
|
{
|
312
|
-
"test" => %w[--global-option help foo bar foo2 bar2],
|
446
|
+
"test" => %w[--global-option -g help foo bar foo2 bar2],
|
313
447
|
"test foo" => %w[--foo-opt1 --foo-opt2],
|
314
448
|
"test bar" => %w[--bar-opt1 --bar-opt2]
|
315
449
|
}
|
@@ -349,7 +483,7 @@ describe CommandKit::Completion::Task do
|
|
349
483
|
it "must omit the command from the completion rules" do
|
350
484
|
expect(subject.completion_rules_for(command_class)).to eq(
|
351
485
|
{
|
352
|
-
"test" => %w[--global-option help foo bar],
|
486
|
+
"test" => %w[--global-option -g help foo bar],
|
353
487
|
"test foo" => %w[--foo-opt1 --foo-opt2]
|
354
488
|
}
|
355
489
|
)
|
@@ -423,7 +557,7 @@ describe CommandKit::Completion::Task do
|
|
423
557
|
it "must recursively include completion rules for the sub-sub-commands" do
|
424
558
|
expect(subject.completion_rules_for(command_class)).to eq(
|
425
559
|
{
|
426
|
-
"test" => %w[--global-option help foo bar],
|
560
|
+
"test" => %w[--global-option -g help foo bar],
|
427
561
|
"test foo" => %w[--foo-opt1 --foo-opt2],
|
428
562
|
"test bar" => %w[--bar-opt1 --bar-opt2 help baz qux],
|
429
563
|
"test bar baz" => %w[--baz-opt1 --baz-opt2],
|
@@ -435,14 +569,65 @@ describe CommandKit::Completion::Task do
|
|
435
569
|
end
|
436
570
|
end
|
437
571
|
|
572
|
+
describe "#suggestion_for_argument" do
|
573
|
+
context "when given 'FILE'" do
|
574
|
+
it "must return '<file>'" do
|
575
|
+
expect(subject.suggestion_for_argument('FILE')).to eq('<file>')
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
579
|
+
context "when the string ends with '_FILE'" do
|
580
|
+
it "must return '<file>'" do
|
581
|
+
expect(subject.suggestion_for_argument('FOO_FILE')).to eq('<file>')
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
context "when given 'DIR'" do
|
586
|
+
it "must return '<directory>'" do
|
587
|
+
expect(subject.suggestion_for_argument('DIR')).to eq('<directory>')
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
context "when the string ends with '_DIR'" do
|
592
|
+
it "must return '<directory>'" do
|
593
|
+
expect(subject.suggestion_for_argument('FOO_DIR')).to eq('<directory>')
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
context "when given 'HOST'" do
|
598
|
+
it "must return '<hostname>'" do
|
599
|
+
expect(subject.suggestion_for_argument('HOST')).to eq('<hostname>')
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
context "when the string ends with '_HOST'" do
|
604
|
+
it "must return '<hostname>'" do
|
605
|
+
expect(subject.suggestion_for_argument('FOO_HOST')).to eq('<hostname>')
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
context "when given 'USER'" do
|
610
|
+
it "must return '<user>'" do
|
611
|
+
expect(subject.suggestion_for_argument('USER')).to eq('<user>')
|
612
|
+
end
|
613
|
+
end
|
614
|
+
|
615
|
+
context "when the string ends with '_USER'" do
|
616
|
+
it "must return '<user>'" do
|
617
|
+
expect(subject.suggestion_for_argument('FOO_USER')).to eq('<user>')
|
618
|
+
end
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
438
622
|
describe "#completion_rules" do
|
439
623
|
it "must load the class from #class_file and return the generated completion rules for it" do
|
440
624
|
expect(subject.completion_rules).to eq(
|
441
625
|
{
|
442
|
-
"foo" => %w[--config-file help config list update ls up],
|
626
|
+
"foo" => %w[--config-file -C help config list update ls up],
|
443
627
|
"foo config" => %w[help get set],
|
444
|
-
"foo update" => %w[--quiet],
|
445
|
-
"foo*--config-file" => %w[<file>]
|
628
|
+
"foo update" => %w[--quiet -q],
|
629
|
+
"foo*--config-file" => %w[<file>],
|
630
|
+
"foo*-C" => %w[<file>]
|
446
631
|
}
|
447
632
|
)
|
448
633
|
end
|
@@ -462,10 +647,11 @@ describe CommandKit::Completion::Task do
|
|
462
647
|
it "must merge the additional completion rules with the generated ones" do
|
463
648
|
expect(subject.completion_rules).to eq(
|
464
649
|
{
|
465
|
-
"foo" => %w[--config-file help config list update ls up],
|
650
|
+
"foo" => %w[--config-file -C help config list update ls up],
|
466
651
|
"foo config" => %w[help get set],
|
467
|
-
"foo update" => ['--quiet', '$(foo list)'],
|
468
|
-
"foo*--config-file" => %w[<file>]
|
652
|
+
"foo update" => ['--quiet', '-q', '$(foo list)'],
|
653
|
+
"foo*--config-file" => %w[<file>],
|
654
|
+
"foo*-C" => %w[<file>]
|
469
655
|
}
|
470
656
|
)
|
471
657
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: command_kit-completion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Postmodern
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-04-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: command_kit
|
@@ -110,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
110
|
- !ruby/object:Gem::Version
|
111
111
|
version: '0'
|
112
112
|
requirements: []
|
113
|
-
rubygems_version: 3.4.
|
113
|
+
rubygems_version: 3.4.19
|
114
114
|
signing_key:
|
115
115
|
specification_version: 4
|
116
116
|
summary: Generate shell completions for command_kit commands
|