command_kit-completion 0.2.0 → 0.3.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/.github/workflows/ruby.yml +4 -3
- data/ChangeLog.md +10 -0
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/lib/command_kit/completion/task.rb +62 -13
- data/lib/command_kit/completion/version.rb +1 -1
- data/spec/fixtures/additional_rules_with_aliases.yml +4 -0
- data/spec/task_spec.rb +91 -17
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 721a31416806fcf1375dfa9060827013fbde3ffc06f0d9916f31c5602d4386f7
|
4
|
+
data.tar.gz: e6bb27f5dd650bfb26b9fda270bb66a97c7c260cbaa45b3a520a93aa53594567
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e9820c5f5ae32b4f9672d9b05bec71b86e0a66a9a8ae873e74346d65fe2d5b8d37c205921689d7c842d30e1d8411328fc5181da61b57abe71fbd31518485229
|
7
|
+
data.tar.gz: 855fd91e1a677a359f62f1ebcc38350e6308e5451cfa7d69dea172ec3d88c015a2323e1b7d6559f64cd6667bd1c5ac2489d62644523e39bf80f8a2628bd64621
|
data/.github/workflows/ruby.yml
CHANGED
data/ChangeLog.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
### 0.3.0 / 2024-12-16
|
2
|
+
|
3
|
+
* Generate `<file>` and `<directory>` completion rules for arguments named
|
4
|
+
`PATH` or ending in `_PATH`, so they can tab complete both files and
|
5
|
+
directories.
|
6
|
+
|
7
|
+
### 0.2.1 / 2024-04-29
|
8
|
+
|
9
|
+
* Support loading YAML input files that contain YAML aliases.
|
10
|
+
|
1
11
|
### 0.2.0 / 2024-04-26
|
2
12
|
|
3
13
|
* Also generate completion rules for option's short flags.
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -10,37 +10,61 @@ require 'fileutils'
|
|
10
10
|
|
11
11
|
module CommandKit
|
12
12
|
module Completion
|
13
|
+
#
|
14
|
+
# `command_kit-completion` rake task.
|
15
|
+
#
|
16
|
+
# ## Example
|
17
|
+
#
|
18
|
+
# require 'command_kit/completion/task'
|
19
|
+
# CommandKit::Completion::Task.new(
|
20
|
+
# class_file: './examples/cli',
|
21
|
+
# class_name: 'Foo::CLI',
|
22
|
+
# output_file: 'completion.sh'
|
23
|
+
# )
|
24
|
+
#
|
13
25
|
class Task < Rake::TaskLib
|
14
26
|
|
15
27
|
# The file that the command_kit CLI is defined in.
|
16
28
|
#
|
17
29
|
# @return [String]
|
30
|
+
#
|
31
|
+
# @api private
|
18
32
|
attr_reader :class_file
|
19
33
|
|
20
34
|
# The class name of the command_kit CLI.
|
21
35
|
#
|
22
36
|
# @return [String]
|
37
|
+
#
|
38
|
+
# @api private
|
23
39
|
attr_reader :class_name
|
24
40
|
|
25
41
|
# The output file to write the shell completions to.
|
26
42
|
#
|
27
43
|
# @return [String]
|
44
|
+
#
|
45
|
+
# @api private
|
28
46
|
attr_reader :output_file
|
29
47
|
|
30
48
|
# Optional input YAML file to read additional shell completions from.
|
31
49
|
#
|
32
50
|
# @return [String, nil]
|
51
|
+
#
|
52
|
+
# @api private
|
33
53
|
attr_reader :input_file
|
34
54
|
|
35
55
|
# Specifies whether the shell completion logic should be wrapped in a
|
36
56
|
# function.
|
37
57
|
#
|
38
58
|
# @return [Boolean]
|
59
|
+
#
|
60
|
+
# @api private
|
39
61
|
attr_reader :wrap_function
|
40
62
|
|
41
63
|
# Optional function name to wrap the shell completions within.
|
42
64
|
#
|
43
65
|
# @return [String, nil]
|
66
|
+
#
|
67
|
+
# @api private
|
44
68
|
attr_reader :function_name
|
45
69
|
|
46
70
|
#
|
@@ -61,6 +85,8 @@ module CommandKit
|
|
61
85
|
#
|
62
86
|
# [completely examples]: https://github.com/DannyBen/completely?tab=readme-ov-file#using-the-completely-command-line
|
63
87
|
#
|
88
|
+
# @api public
|
89
|
+
#
|
64
90
|
def initialize(class_file: ,
|
65
91
|
class_name: ,
|
66
92
|
output_file: ,
|
@@ -81,6 +107,8 @@ module CommandKit
|
|
81
107
|
#
|
82
108
|
# Defines the `command_kit:completion` task.
|
83
109
|
#
|
110
|
+
# @api private
|
111
|
+
#
|
84
112
|
def define
|
85
113
|
task(@output_file) do
|
86
114
|
completions = Completely::Completions.new(completion_rules)
|
@@ -105,28 +133,45 @@ module CommandKit
|
|
105
133
|
#
|
106
134
|
# @return [Class]
|
107
135
|
#
|
136
|
+
# @api private
|
137
|
+
#
|
108
138
|
def load_class
|
109
139
|
require(@class_file)
|
110
140
|
Object.const_get(@class_name)
|
111
141
|
end
|
112
142
|
|
143
|
+
#
|
144
|
+
# Loads the completion rules from the {#input_file}.
|
145
|
+
#
|
146
|
+
# @return [Hash]
|
147
|
+
# The completion rules from the {#input_file}.
|
148
|
+
#
|
149
|
+
# @api private
|
150
|
+
#
|
151
|
+
def load_input_file
|
152
|
+
YAML.load_file(@input_file, aliases: true)
|
153
|
+
end
|
154
|
+
|
113
155
|
#
|
114
156
|
# Maps the argument name strings to completely suggestion `<keyword>`s.
|
115
157
|
#
|
116
158
|
# @param [String] arg
|
117
159
|
# The argument name.
|
118
160
|
#
|
119
|
-
# @return [String
|
161
|
+
# @return [Array<String>, nil]
|
120
162
|
# The suggestion keyword for the argument name.
|
121
163
|
#
|
122
|
-
# @since 0.
|
164
|
+
# @since 0.3.0
|
165
|
+
#
|
166
|
+
# @api private
|
123
167
|
#
|
124
|
-
def
|
168
|
+
def suggestions_for_argument(arg)
|
125
169
|
case arg
|
126
|
-
when /\AFILE\z|_FILE\z/ then
|
127
|
-
when /\ADIR\z|_DIR\z/ then
|
128
|
-
when /\
|
129
|
-
when /\
|
170
|
+
when /\AFILE\z|_FILE\z/ then %w[<file>]
|
171
|
+
when /\ADIR\z|_DIR\z/ then %w[<directory>]
|
172
|
+
when /\APATH\z|_PATH\z/ then %w[<file> <directory>]
|
173
|
+
when /\AHOST\z|_HOST\z/ then %w[<hostname>]
|
174
|
+
when /\AUSER\z|_USER\z/ then %w[<user>]
|
130
175
|
end
|
131
176
|
end
|
132
177
|
|
@@ -142,6 +187,8 @@ module CommandKit
|
|
142
187
|
# @return [Hash{String => Array<String>}]
|
143
188
|
# The completion rules for the command class and any sub-commands.
|
144
189
|
#
|
190
|
+
# @api private
|
191
|
+
#
|
145
192
|
def completion_rules_for(command_class)
|
146
193
|
command_name = command_class.command_name
|
147
194
|
completions = {command_name => []}
|
@@ -154,16 +201,16 @@ module CommandKit
|
|
154
201
|
completions[command_name] << option.short if option.short
|
155
202
|
|
156
203
|
if option.value
|
157
|
-
if (
|
204
|
+
if (suggestions = suggestions_for_argument(option.value.usage))
|
158
205
|
command_pattern = "#{command_name}*#{option.long}"
|
159
206
|
|
160
207
|
# add a special rule if the option's value USAGE maps to a
|
161
208
|
# 'completely' completion keyword (ex: `FILE` -> `<file>`).
|
162
|
-
completions[command_pattern] =
|
209
|
+
completions[command_pattern] = suggestions
|
163
210
|
|
164
211
|
if option.short
|
165
212
|
# also add another rule with the option's short flag
|
166
|
-
completions["#{command_name}*#{option.short}"] =
|
213
|
+
completions["#{command_name}*#{option.short}"] = suggestions
|
167
214
|
end
|
168
215
|
end
|
169
216
|
end
|
@@ -185,9 +232,9 @@ module CommandKit
|
|
185
232
|
completions[command_name].concat(command_class.command_aliases.keys)
|
186
233
|
elsif command_class.include?(CommandKit::Arguments)
|
187
234
|
if (argument = command_class.arguments.values.first)
|
188
|
-
if (
|
235
|
+
if (suggestions = suggestions_for_argument(argument.usage))
|
189
236
|
# add a suggestion for the first argument
|
190
|
-
completions[command_name]
|
237
|
+
completions[command_name].concat(suggestions)
|
191
238
|
end
|
192
239
|
end
|
193
240
|
end
|
@@ -206,12 +253,14 @@ module CommandKit
|
|
206
253
|
#
|
207
254
|
# @return [Hash{String => Array<String>}]
|
208
255
|
#
|
256
|
+
# @api private
|
257
|
+
#
|
209
258
|
def completion_rules
|
210
259
|
completion_rules = completion_rules_for(load_class)
|
211
260
|
|
212
261
|
if @input_file
|
213
262
|
# load the additional rules from the input file
|
214
|
-
additional_completion_rules =
|
263
|
+
additional_completion_rules = load_input_file
|
215
264
|
|
216
265
|
# merge the additional completion rules
|
217
266
|
additional_completion_rules.each do |command_string,completions|
|
data/spec/task_spec.rb
CHANGED
@@ -69,6 +69,42 @@ describe CommandKit::Completion::Task do
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
+
describe "#load_input_file" do
|
73
|
+
let(:input_file) { File.join(fixtures_dir,'additional_rules.yml') }
|
74
|
+
|
75
|
+
subject do
|
76
|
+
described_class.new(
|
77
|
+
class_file: class_file,
|
78
|
+
class_name: class_name,
|
79
|
+
input_file: input_file,
|
80
|
+
output_file: output_file
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "must load the YAML from the input file" do
|
85
|
+
expect(subject.load_input_file).to eq(
|
86
|
+
{
|
87
|
+
'foo update' => ['$(foo list)']
|
88
|
+
}
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
context "when the input file contains YAML aliases" do
|
93
|
+
let(:input_file) do
|
94
|
+
File.join(fixtures_dir,'additional_rules_with_aliases.yml')
|
95
|
+
end
|
96
|
+
|
97
|
+
it "must support parsing YAML aliases" do
|
98
|
+
expect(subject.load_input_file).to eq(
|
99
|
+
{
|
100
|
+
'foo update' => ['$(foo list)'],
|
101
|
+
'foo up'=> ['$(foo list)']
|
102
|
+
}
|
103
|
+
)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
72
108
|
describe "#completion_rules_for" do
|
73
109
|
context "when given a simple CommandKit::Command class" do
|
74
110
|
class TestBasicCommand < CommandKit::Command
|
@@ -569,52 +605,90 @@ describe CommandKit::Completion::Task do
|
|
569
605
|
end
|
570
606
|
end
|
571
607
|
|
572
|
-
describe "#
|
608
|
+
describe "#suggestions_for_argument" do
|
573
609
|
context "when given 'FILE'" do
|
574
|
-
it "must return '<file>'" do
|
575
|
-
expect(subject.
|
610
|
+
it "must return ['<file>']" do
|
611
|
+
expect(subject.suggestions_for_argument('FILE')).to eq(
|
612
|
+
%w[<file>]
|
613
|
+
)
|
576
614
|
end
|
577
615
|
end
|
578
616
|
|
579
617
|
context "when the string ends with '_FILE'" do
|
580
|
-
it "must return '<file>'" do
|
581
|
-
expect(subject.
|
618
|
+
it "must return ['<file>']" do
|
619
|
+
expect(subject.suggestions_for_argument('FOO_FILE')).to eq(
|
620
|
+
%w[<file>]
|
621
|
+
)
|
582
622
|
end
|
583
623
|
end
|
584
624
|
|
585
625
|
context "when given 'DIR'" do
|
586
|
-
it "must return '<directory>'" do
|
587
|
-
expect(subject.
|
626
|
+
it "must return ['<directory>']" do
|
627
|
+
expect(subject.suggestions_for_argument('DIR')).to eq(
|
628
|
+
%w[<directory>]
|
629
|
+
)
|
588
630
|
end
|
589
631
|
end
|
590
632
|
|
591
633
|
context "when the string ends with '_DIR'" do
|
592
|
-
it "must return '<directory>'" do
|
593
|
-
expect(subject.
|
634
|
+
it "must return ['<directory>']" do
|
635
|
+
expect(subject.suggestions_for_argument('FOO_DIR')).to eq(
|
636
|
+
%w[<directory>]
|
637
|
+
)
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
context "when given 'PATH'" do
|
642
|
+
it "must return ['<file>', '<directory>']" do
|
643
|
+
expect(subject.suggestions_for_argument('PATH')).to eq(
|
644
|
+
%w[
|
645
|
+
<file>
|
646
|
+
<directory>
|
647
|
+
]
|
648
|
+
)
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
context "when the string ends with '_PATH'" do
|
653
|
+
it "must return ['<file>', '<directory>']" do
|
654
|
+
expect(subject.suggestions_for_argument('FOO_PATH')).to eq(
|
655
|
+
%w[
|
656
|
+
<file>
|
657
|
+
<directory>
|
658
|
+
]
|
659
|
+
)
|
594
660
|
end
|
595
661
|
end
|
596
662
|
|
597
663
|
context "when given 'HOST'" do
|
598
|
-
it "must return '<hostname>'" do
|
599
|
-
expect(subject.
|
664
|
+
it "must return ['<hostname>']" do
|
665
|
+
expect(subject.suggestions_for_argument('HOST')).to eq(
|
666
|
+
%w[<hostname>]
|
667
|
+
)
|
600
668
|
end
|
601
669
|
end
|
602
670
|
|
603
671
|
context "when the string ends with '_HOST'" do
|
604
|
-
it "must return '<hostname>'" do
|
605
|
-
expect(subject.
|
672
|
+
it "must return ['<hostname>']" do
|
673
|
+
expect(subject.suggestions_for_argument('FOO_HOST')).to eq(
|
674
|
+
%w[<hostname>]
|
675
|
+
)
|
606
676
|
end
|
607
677
|
end
|
608
678
|
|
609
679
|
context "when given 'USER'" do
|
610
|
-
it "must return '<user>'" do
|
611
|
-
expect(subject.
|
680
|
+
it "must return ['<user>']" do
|
681
|
+
expect(subject.suggestions_for_argument('USER')).to eq(
|
682
|
+
%w[<user>]
|
683
|
+
)
|
612
684
|
end
|
613
685
|
end
|
614
686
|
|
615
687
|
context "when the string ends with '_USER'" do
|
616
|
-
it "must return '<user>'" do
|
617
|
-
expect(subject.
|
688
|
+
it "must return ['<user>']" do
|
689
|
+
expect(subject.suggestions_for_argument('FOO_USER')).to eq(
|
690
|
+
%w[<user>]
|
691
|
+
)
|
618
692
|
end
|
619
693
|
end
|
620
694
|
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.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Postmodern
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: command_kit
|
@@ -84,6 +84,7 @@ files:
|
|
84
84
|
- lib/command_kit/completion/task.rb
|
85
85
|
- lib/command_kit/completion/version.rb
|
86
86
|
- spec/fixtures/additional_rules.yml
|
87
|
+
- spec/fixtures/additional_rules_with_aliases.yml
|
87
88
|
- spec/spec_helper.rb
|
88
89
|
- spec/task_spec.rb
|
89
90
|
homepage: https://github.com/postmodern/command_kit-completion#readme
|
@@ -110,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
111
|
- !ruby/object:Gem::Version
|
111
112
|
version: '0'
|
112
113
|
requirements: []
|
113
|
-
rubygems_version: 3.
|
114
|
+
rubygems_version: 3.5.22
|
114
115
|
signing_key:
|
115
116
|
specification_version: 4
|
116
117
|
summary: Generate shell completions for command_kit commands
|