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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d38eb48761e8c78265e4fe3de35b056a4b20a1c709ae92d1748b55bdaf26d78
4
- data.tar.gz: 632bd4541f75fadeff3ecb7f754c865e387a2282c4329719e47fa628b049ebab
3
+ metadata.gz: 5f85e448a2df37a8bc6231b839b8e56992432498384e6ea4c2e1060a9485c874
4
+ data.tar.gz: 898168ab4ed70e3e595de27c933432a085976ea81980c7bcc3572e6e2cc4c38c
5
5
  SHA512:
6
- metadata.gz: 671fd188f0ba01c1a32bf02d3d06ed5e9fd2e9e78f7e055d0cde9f687bb732a1913bef999f9e15e2d8d29837db8e996ea40dd7e65891bad03e92440999ba2839
7
- data.tar.gz: a4dd29acbf852ad3a746bb8ea47595a6b613ac8e12f407a1966165d3a3f86aadb7893295c743448574f12c9e417a7fef084845ceacac8f3782484fe33d7c1da6
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
- # Mapping of command usage strings to completely `<keyword>`s.
114
- USAGE_COMPLETIONS = {
115
- 'FILE' => '<file>',
116
- 'DIR' => '<directory>',
117
- 'HOST' => '<hostname>',
118
- 'USER' => '<user>'
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 (option_value_completion = USAGE_COMPLETIONS[option.value.usage])
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["#{command_name}*#{option.long}"] = [
148
- option_value_completion
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
@@ -3,6 +3,6 @@
3
3
  module CommandKit
4
4
  module Completion
5
5
  # command_kit-completion version
6
- VERSION = '0.1.1'
6
+ VERSION = '0.2.0'
7
7
  end
8
8
  end
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.1.1
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: 2023-12-18 00:00:00.000000000 Z
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.10
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