completely 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd3ae4ec92d7318bd4ef32fdd465d9bff3341931f5f965d2db8f263c1b95e38b
4
- data.tar.gz: 01ccb2fa2e1f050b7a45944b552590fad6aab9bafc90ef4cb98b8d6284200392
3
+ metadata.gz: 54ee6b84395ab00c6d0fdde61065b9843b178947a7569cea41cead7b149ef55b
4
+ data.tar.gz: 3dd72641e530c42b0642b5861f1b38c219b5931846ed2da7fb20648563954094
5
5
  SHA512:
6
- metadata.gz: fd06256b9cb4c42364d118ea1392b180ef662e98b2ea9c6b24ca815f5fa5cf1f16d6c0a6792090c9bc5f376ab7dfb04e9b8c732cb83292140acb59676d6090a9
7
- data.tar.gz: b1985849259627803ebe3f7c56b4adc98137456b172fb36cbf1379b4677257dca6cc671d85a12106596fb246de02aad07c5e9d51c5dd0abc7301518d9b7529b2
6
+ metadata.gz: b8f2ffa6f7f8303e827c8bb894accf1d97ae0e012f46d495dcfab280836ffd5ae8aa0418b95450a41642bb1fcabb9b2ee2d54ef037f88e43f048a6014ae4acff
7
+ data.tar.gz: 94f01f524b7ffc8bf5ca910594e203f1579bccc0910795ca2a74cf64af5838dab1b023a250f017da9c0c2798c68ac71149657c14a3f587a32a30268843fdd815
data/README.md CHANGED
@@ -2,41 +2,48 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/completely.svg)](https://badge.fury.io/rb/completely)
4
4
  [![Build Status](https://github.com/DannyBen/completely/workflows/Test/badge.svg)](https://github.com/DannyBen/completely/actions?query=workflow%3ATest)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/6c021b8309ac796c3919/maintainability)](https://codeclimate.com/github/DannyBen/completely/maintainability)
5
6
 
6
7
  ---
7
8
 
8
9
  Completely is a command line utility and a Ruby library that lets you generate
9
10
  bash completion scripts from simple YAML configuration.
10
11
 
11
- This tool is for you it:
12
+ This tool is for you if:
12
13
 
13
14
  1. You develop your own command line tools.
14
15
  2. Your life feels empty without bash completions.
15
- 3. Bash completion scripts scare you.
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.
16
20
 
17
21
  ---
18
22
 
19
23
 
20
24
  ## Install
21
25
 
22
- ```
26
+ ```bash
23
27
  $ gem install completely
24
28
  ```
25
29
 
26
- ## Usage
30
+ ## Using the `completely` command line
27
31
 
28
32
  The `completely` command line works with a simple YAML configuration file as
29
33
  input, and generates a bash completions script as output.
30
34
 
31
- The configuration file is built like this:
35
+ The configuration file is built of blocks that look like this:
32
36
 
33
37
  ```yaml
34
38
  pattern:
35
- - --argument
36
- - --param
37
- - command
39
+ - --argument
40
+ - --param
41
+ - command
38
42
  ```
39
43
 
44
+ Each pattern contains an array of words (or functions) that will be suggested
45
+ for the auto complete process.
46
+
40
47
  You can save a sample YAML file by running:
41
48
 
42
49
  ```
@@ -57,6 +64,7 @@ mygit status:
57
64
  - --help
58
65
  - --verbose
59
66
  - --branch
67
+ - $(git branch 2> /dev/null)
60
68
 
61
69
  mygit init:
62
70
  - --bare
@@ -78,7 +86,7 @@ follows it will be suggested as completions.
78
86
 
79
87
  To generate the bash script, simply run:
80
88
 
81
- ```
89
+ ```bash
82
90
  $ completely generate
83
91
 
84
92
  # or, to just preview it without saving:
@@ -87,37 +95,105 @@ $ completely preview
87
95
 
88
96
  For more options (like setting input/output path), run
89
97
 
90
- ```
98
+ ```bash
91
99
  $ completely --help
92
100
  ```
93
101
 
94
- ### Suggesting files and directories
102
+ ### Suggesting files, directories and other bash built-ins
95
103
 
96
- You may have noticed that the sample file contains two special entries:
104
+ In addition to specifying a simple array of completion words, you may use
105
+ the special syntax `<..>` to suggest more advanced functions.
97
106
 
98
- - `<file>`
99
- - `<directory>`
107
+ ```yaml
108
+ pattern:
109
+ - <file>
110
+ - <directory>
111
+ ```
100
112
 
101
- These patterns will add the list of files and directories
102
- (when `<file>` is used) or just directories (when `<directory` is used) to
113
+ These suggestions will add the list of files and directories
114
+ (when `<file>` is used) or just directories (when `<directory>` is used) to
103
115
  the list of suggestions.
104
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
+
105
144
  For those interested in the technical details, any word between `<...>` will
106
145
  simply be added using the [`compgen -A action`][compgen] function, so you can
107
146
  in fact use any of its supported arguments.
108
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.
109
161
 
110
- ### Using the generated completion scripts
162
+
163
+ ## Using the generated completion scripts
111
164
 
112
165
  In order to enable the completions, simply source the generated script:
113
166
 
114
- ```
167
+ ```bash
115
168
  $ source completely.bash
116
169
  ```
117
170
 
118
171
  You may wish to add this to your `~/.bashrc` file to enable this for future
119
172
  sessions (just be sure to use absolute path).
120
173
 
174
+ ## Using from within Ruby code
175
+
176
+ ```ruby
177
+ require 'completely'
178
+
179
+ # Load from file
180
+ completions = Completely::Completions.load "input.yaml"
181
+
182
+ # Or, from a hash
183
+ input = {
184
+ "mygit" => %w[--help --version status init commit],
185
+ "mygit status" => %w[--help --verbose --branch]
186
+ }
187
+ completions = Completely::Completions.new input
188
+
189
+ # Generate the script
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"
195
+ ```
196
+
121
197
 
122
198
  ## Contributing / Support
123
199
 
@@ -128,3 +204,4 @@ to contribute, feel free to [open an issue][issues].
128
204
 
129
205
  [issues]: https://github.com/DannyBen/completely/issues
130
206
  [compgen]: https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html
207
+ [bashly]: https://bashly.dannyb.co/
@@ -1,6 +1,6 @@
1
1
  require 'mister_bin'
2
- require 'completely/command'
3
2
  require 'completely/version'
3
+ require 'completely/command'
4
4
 
5
5
  module Completely
6
6
  class CLI
@@ -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 my_completions"
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 my_completions"
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
- File.write output_path, script
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
@@ -9,6 +9,7 @@ mygit status:
9
9
  - --help
10
10
  - --verbose
11
11
  - --branch
12
+ - $(git branch 2> /dev/null)
12
13
 
13
14
  mygit init:
14
15
  - --bare
@@ -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 "$COMP_LINE" in
10
- % patterns.each do |pattern, words|
11
- % next unless words
12
- % clean_words = words.reject { |w| w =~ /^<.*>$/ }.join " "
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
  }
@@ -1,3 +1,3 @@
1
1
  module Completely
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/completely.rb CHANGED
@@ -1,9 +1,7 @@
1
- require 'requires'
2
-
3
1
  if ENV['BYEBUG']
4
2
  require 'byebug'
5
3
  require 'lp'
6
4
  end
7
5
 
8
- # requires 'completely'
6
+ require 'completely/pattern'
9
7
  require 'completely/completions'
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.1.0
4
+ version: 0.2.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: 2021-07-20 00:00:00.000000000 Z
11
+ date: 2021-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colsole
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.7'
41
- - !ruby/object:Gem::Dependency
42
- name: requires
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '0.1'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '0.1'
55
41
  description: Generate bash completion scripts using simple YAML configuration
56
42
  email: db@dannyben.com
57
43
  executables:
@@ -65,6 +51,7 @@ files:
65
51
  - lib/completely/cli.rb
66
52
  - lib/completely/command.rb
67
53
  - lib/completely/completions.rb
54
+ - lib/completely/pattern.rb
68
55
  - lib/completely/sample.yaml
69
56
  - lib/completely/template.erb
70
57
  - lib/completely/version.rb
@@ -87,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
87
74
  - !ruby/object:Gem::Version
88
75
  version: '0'
89
76
  requirements: []
90
- rubygems_version: 3.2.16
77
+ rubygems_version: 3.2.25
91
78
  signing_key:
92
79
  specification_version: 4
93
80
  summary: Bash Completions Generator