completely 0.1.1 → 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/README.md +68 -11
- data/lib/completely/command.rb +19 -4
- data/lib/completely/completions.rb +30 -5
- data/lib/completely/pattern.rb +50 -0
- data/lib/completely/sample.yaml +1 -0
- data/lib/completely/template.erb +5 -7
- data/lib/completely/version.rb +1 -1
- data/lib/completely.rb +1 -1
- 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: '0949e2f6df08b0582dc2efd748523bf63732f8c59a5ad41bd479e444568304d2'
|
4
|
+
data.tar.gz: fe1bf68cbec745eeed052c218f77e42040ae378c36fa99ad36e5d45c6c64a202
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a80c321109ac11ec6cc3be603d713e460fb838818c1fe2c56c2fdde9e903f1677fb0027a4dbfc1f0605123658181aa067b48f167c4061221bd85c754c0006f1b
|
7
|
+
data.tar.gz: a0d7283193046401a94971fcb7cd5f6e58b10087f6fe3b346f5a8d414c0f1252ef59cf9ee6f2ac338618652d54003e6cea9442948806a7b50832fa3c2bccc868
|
data/README.md
CHANGED
@@ -13,7 +13,10 @@ This tool is for you if:
|
|
13
13
|
|
14
14
|
1. You develop your own command line tools.
|
15
15
|
2. Your life feels empty without bash completions.
|
16
|
-
3. Bash completion scripts
|
16
|
+
3. Bash completion scripts seem overly complex to you.
|
17
|
+
|
18
|
+
Note that if you are building bash command line scripts with [bashly][bashly],
|
19
|
+
then this functionality is already integrated with it.
|
17
20
|
|
18
21
|
---
|
19
22
|
|
@@ -29,15 +32,18 @@ $ gem install completely
|
|
29
32
|
The `completely` command line works with a simple YAML configuration file as
|
30
33
|
input, and generates a bash completions script as output.
|
31
34
|
|
32
|
-
The configuration file is built like this:
|
35
|
+
The configuration file is built of blocks that look like this:
|
33
36
|
|
34
37
|
```yaml
|
35
38
|
pattern:
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
+
- --argument
|
40
|
+
- --param
|
41
|
+
- command
|
39
42
|
```
|
40
43
|
|
44
|
+
Each pattern contains an array of words (or functions) that will be suggested
|
45
|
+
for the auto complete process.
|
46
|
+
|
41
47
|
You can save a sample YAML file by running:
|
42
48
|
|
43
49
|
```
|
@@ -58,6 +64,7 @@ mygit status:
|
|
58
64
|
- --help
|
59
65
|
- --verbose
|
60
66
|
- --branch
|
67
|
+
- $(git branch 2> /dev/null)
|
61
68
|
|
62
69
|
mygit init:
|
63
70
|
- --bare
|
@@ -92,21 +99,66 @@ For more options (like setting input/output path), run
|
|
92
99
|
$ completely --help
|
93
100
|
```
|
94
101
|
|
95
|
-
### Suggesting files and
|
102
|
+
### Suggesting files, directories and other bash built-ins
|
96
103
|
|
97
|
-
|
104
|
+
In addition to specifying a simple array of completion words, you may use
|
105
|
+
the special syntax `<..>` to suggest more advanced functions.
|
98
106
|
|
99
|
-
|
100
|
-
|
107
|
+
```yaml
|
108
|
+
pattern:
|
109
|
+
- <file>
|
110
|
+
- <directory>
|
111
|
+
```
|
101
112
|
|
102
|
-
These
|
103
|
-
(when `<file>` is used) or just directories (when `<directory
|
113
|
+
These suggestions will add the list of files and directories
|
114
|
+
(when `<file>` is used) or just directories (when `<directory>` is used) to
|
104
115
|
the list of suggestions.
|
105
116
|
|
117
|
+
You may use any of the below keywords to add additional suggestions:
|
118
|
+
|
119
|
+
| Keyword | Meaning
|
120
|
+
|---------------|---------------------
|
121
|
+
| `<alias>` | Alias names
|
122
|
+
| `<arrayvar>` | Array variable names
|
123
|
+
| `<binding>` | Readline key binding names
|
124
|
+
| `<builtin>` | Names of shell builtin commands
|
125
|
+
| `<command>` | Command names
|
126
|
+
| `<directory>` | Directory names
|
127
|
+
| `<disabled>` | Names of disabled shell builtins
|
128
|
+
| `<enabled>` | Names of enabled shell builtins
|
129
|
+
| `<export>` | Names of exported shell variables
|
130
|
+
| `<file>` | File names
|
131
|
+
| `<function>` | Names of shell functions
|
132
|
+
| `<group>` | Group names
|
133
|
+
| `<helptopic>` | Help topics as accepted by the help builtin
|
134
|
+
| `<hostname>` | Hostnames, as taken from the file specified by the HOSTFILE shell variable
|
135
|
+
| `<job>` | Job names
|
136
|
+
| `<keyword>` | Shell reserved words
|
137
|
+
| `<running>` | Names of running jobs
|
138
|
+
| `<service>` | Service names
|
139
|
+
| `<signal>` | Signal names
|
140
|
+
| `<stopped>` | Names of stopped jobs
|
141
|
+
| `<user>` | User names
|
142
|
+
| `<variable>` | Names of all shell variables
|
143
|
+
|
106
144
|
For those interested in the technical details, any word between `<...>` will
|
107
145
|
simply be added using the [`compgen -A action`][compgen] function, so you can
|
108
146
|
in fact use any of its supported arguments.
|
109
147
|
|
148
|
+
### Suggesting custom dynamic suggestions
|
149
|
+
|
150
|
+
You can also use any command that outputs a whitespace-delimited list as a
|
151
|
+
suggestions list, by wrapping it in `$(..)`. For example, in order to add git
|
152
|
+
branches to your suggestions, use the following:
|
153
|
+
|
154
|
+
```yaml
|
155
|
+
mygit:
|
156
|
+
- $(git branch 2> /dev/null)
|
157
|
+
```
|
158
|
+
|
159
|
+
The `2> /dev/null` is used so that if the command is executed in a directory
|
160
|
+
without a git repository, it will still behave as expected.
|
161
|
+
|
110
162
|
|
111
163
|
## Using the generated completion scripts
|
112
164
|
|
@@ -136,6 +188,10 @@ completions = Completely::Completions.new input
|
|
136
188
|
|
137
189
|
# Generate the script
|
138
190
|
puts completions.script
|
191
|
+
|
192
|
+
# Or, generate a function that echos the script
|
193
|
+
puts completions.wrapper_function
|
194
|
+
puts completions.wrapper_function "custom_function_name"
|
139
195
|
```
|
140
196
|
|
141
197
|
|
@@ -148,3 +204,4 @@ to contribute, feel free to [open an issue][issues].
|
|
148
204
|
|
149
205
|
[issues]: https://github.com/DannyBen/completely/issues
|
150
206
|
[compgen]: https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html
|
207
|
+
[bashly]: https://bashly.dannyb.co/
|
data/lib/completely/command.rb
CHANGED
@@ -5,7 +5,7 @@ module Completely
|
|
5
5
|
|
6
6
|
usage "completely new [CONFIG_PATH]"
|
7
7
|
usage "completely preview [CONFIG_PATH --function NAME]"
|
8
|
-
usage "completely generate [CONFIG_PATH OUTPUT_PATH --function NAME]"
|
8
|
+
usage "completely generate [CONFIG_PATH OUTPUT_PATH --function NAME --wrap NAME]"
|
9
9
|
usage "completely (-h|--help|--version)"
|
10
10
|
|
11
11
|
command "new", "Create a new sample YAML configuration file"
|
@@ -13,16 +13,18 @@ module Completely
|
|
13
13
|
command "generate", "Generate the bash completion script to a file"
|
14
14
|
|
15
15
|
option "-f --function NAME", "Modify the name of the function in the generated script"
|
16
|
+
option "-w --wrap NAME", "Wrap the completion script inside a function that echos the script. This is useful if you wish to embed it directly in your script"
|
16
17
|
|
17
18
|
param "CONFIG_PATH", "Path to the YAML configuration file"
|
18
19
|
param "OUTPUT_PATH", "Path to the output bash script"
|
19
20
|
|
20
21
|
example "completely new"
|
21
22
|
example "completely new input.yaml"
|
22
|
-
example "completely preview --function
|
23
|
+
example "completely preview --function _my_completions"
|
23
24
|
example "completely generate"
|
24
25
|
example "completely generate input.yaml"
|
25
|
-
example "completely generate input.yaml output.sh -f
|
26
|
+
example "completely generate input.yaml output.sh -f _my_completions"
|
27
|
+
example "completely generate -w give_comps -f my_completions"
|
26
28
|
|
27
29
|
def new_command
|
28
30
|
if File.exist? config_path
|
@@ -35,11 +37,15 @@ module Completely
|
|
35
37
|
|
36
38
|
def preview_command
|
37
39
|
puts script
|
40
|
+
syntax_warning unless completions.valid?
|
38
41
|
end
|
39
42
|
|
40
43
|
def generate_command
|
41
|
-
|
44
|
+
wrap = args['--wrap']
|
45
|
+
output = wrap ? wrapper_function(wrap) : script
|
46
|
+
File.write output_path, output
|
42
47
|
say "Saved !txtpur!#{output_path}"
|
48
|
+
syntax_warning unless completions.valid?
|
43
49
|
end
|
44
50
|
|
45
51
|
private
|
@@ -64,9 +70,18 @@ module Completely
|
|
64
70
|
@script ||= completions.script
|
65
71
|
end
|
66
72
|
|
73
|
+
def wrapper_function(wrapper_name)
|
74
|
+
completions.wrapper_function wrapper_name
|
75
|
+
end
|
76
|
+
|
67
77
|
def completions
|
68
78
|
@completions ||= Completions.load(config_path, function_name: args['--function'])
|
69
79
|
end
|
70
80
|
|
81
|
+
def syntax_warning
|
82
|
+
say! "\n!txtred!WARNING:\nYour configuration is invalid."
|
83
|
+
say! "!txtred!All patterns must start with the same word."
|
84
|
+
end
|
85
|
+
|
71
86
|
end
|
72
87
|
end
|
@@ -15,12 +15,37 @@ module Completely
|
|
15
15
|
@config, @function_name = config, function_name
|
16
16
|
end
|
17
17
|
|
18
|
+
def patterns
|
19
|
+
@patterns ||= patterns!
|
20
|
+
end
|
21
|
+
|
22
|
+
def valid?
|
23
|
+
pattern_prefixes.uniq.count == 1
|
24
|
+
end
|
25
|
+
|
18
26
|
def script
|
19
27
|
ERB.new(template, trim_mode: '%-').result(binding)
|
20
28
|
end
|
21
29
|
|
30
|
+
def wrapper_function(name = nil)
|
31
|
+
name ||= "send_completions"
|
32
|
+
|
33
|
+
script_lines = script.split("\n").map do |line|
|
34
|
+
clean_line = line.gsub("'") { "\\'" }
|
35
|
+
%Q[ echo $'#{clean_line}']
|
36
|
+
end.join("\n")
|
37
|
+
|
38
|
+
"#{name}() {\n#{script_lines}\n}"
|
39
|
+
end
|
40
|
+
|
22
41
|
private
|
23
42
|
|
43
|
+
def patterns!
|
44
|
+
config.map do |text, completions|
|
45
|
+
Pattern.new text, completions
|
46
|
+
end.sort_by { |pattern| -pattern.length }
|
47
|
+
end
|
48
|
+
|
24
49
|
def template_path
|
25
50
|
@template_path ||= File.expand_path("template.erb", __dir__)
|
26
51
|
end
|
@@ -30,16 +55,16 @@ module Completely
|
|
30
55
|
end
|
31
56
|
|
32
57
|
def command
|
33
|
-
@command ||= config.keys.first
|
34
|
-
end
|
35
|
-
|
36
|
-
def patterns
|
37
|
-
@patterns ||= config.to_a.sort_by { |k, v| -k.size }.to_h
|
58
|
+
@command ||= config.keys.first.split(' ').first
|
38
59
|
end
|
39
60
|
|
40
61
|
def function_name
|
41
62
|
@function_name ||= "_#{command}_completions"
|
42
63
|
end
|
43
64
|
|
65
|
+
def pattern_prefixes
|
66
|
+
patterns.map &:prefix
|
67
|
+
end
|
68
|
+
|
44
69
|
end
|
45
70
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Completely
|
2
|
+
class Pattern
|
3
|
+
attr_reader :text, :completions
|
4
|
+
|
5
|
+
def initialize(text, completions)
|
6
|
+
@text = text
|
7
|
+
@completions = completions || []
|
8
|
+
end
|
9
|
+
|
10
|
+
def length
|
11
|
+
@length ||= text.size
|
12
|
+
end
|
13
|
+
|
14
|
+
def empty?
|
15
|
+
completions.empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
def words
|
19
|
+
@words ||= completions.reject { |w| w =~ /^<.*>$/ }
|
20
|
+
end
|
21
|
+
|
22
|
+
def actions
|
23
|
+
@actions ||= completions.filter_map do |word|
|
24
|
+
action = word[/^<(.+)>$/, 1]
|
25
|
+
"-A #{action}" if action
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def prefix
|
30
|
+
text.split(' ')[0]
|
31
|
+
end
|
32
|
+
|
33
|
+
def text_without_prefix
|
34
|
+
text.split(' ')[1..-1].join ' '
|
35
|
+
end
|
36
|
+
|
37
|
+
def compgen
|
38
|
+
@compgen ||= compgen!
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def compgen!
|
44
|
+
result = []
|
45
|
+
result << %Q[#{actions.join ' '}] if actions.any?
|
46
|
+
result << %Q[-W "#{words.join ' '}"] if words.any?
|
47
|
+
result.any? ? result.join(' ') : nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/completely/sample.yaml
CHANGED
data/lib/completely/template.erb
CHANGED
@@ -5,14 +5,12 @@
|
|
5
5
|
# Modifying it manually is not recommended
|
6
6
|
<%= function_name %>() {
|
7
7
|
local cur=${COMP_WORDS[COMP_CWORD]}
|
8
|
+
local comp_line="${COMP_WORDS[@]:1}"
|
8
9
|
|
9
|
-
case "$
|
10
|
-
% patterns.each do |pattern
|
11
|
-
% next
|
12
|
-
|
13
|
-
% functions = words.filter_map { |w| func = w[/^<(.+)>$/, 1] ; "-A #{func}" if func }
|
14
|
-
% flags = functions.any? ? "#{functions.join ' '} -W" : "-W"
|
15
|
-
'<%= pattern %>'*) COMPREPLY=($(compgen <%= flags %> "<%= clean_words %>" -- "$cur")) ;;
|
10
|
+
case "$comp_line" in
|
11
|
+
% patterns.each do |pattern|
|
12
|
+
% next if pattern.empty?
|
13
|
+
'<%= pattern.text_without_prefix %>'*) COMPREPLY=($(compgen <%= pattern.compgen %> -- "$cur")) ;;
|
16
14
|
% end
|
17
15
|
esac
|
18
16
|
}
|
data/lib/completely/version.rb
CHANGED
data/lib/completely.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: completely
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Danny Ben Shitrit
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colsole
|
@@ -51,6 +51,7 @@ files:
|
|
51
51
|
- lib/completely/cli.rb
|
52
52
|
- lib/completely/command.rb
|
53
53
|
- lib/completely/completions.rb
|
54
|
+
- lib/completely/pattern.rb
|
54
55
|
- lib/completely/sample.yaml
|
55
56
|
- lib/completely/template.erb
|
56
57
|
- lib/completely/version.rb
|
@@ -73,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
74
|
- !ruby/object:Gem::Version
|
74
75
|
version: '0'
|
75
76
|
requirements: []
|
76
|
-
rubygems_version: 3.2.
|
77
|
+
rubygems_version: 3.2.15
|
77
78
|
signing_key:
|
78
79
|
specification_version: 4
|
79
80
|
summary: Bash Completions Generator
|