completely 0.3.1 → 0.4.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: 6f19143967a28107018c600c7f302bfccd2cf34d70a88be661f68e340e515c07
4
- data.tar.gz: 6037bb0f6944627f97abf37c51f76d1db213b42402db092fa6c36fb257892c22
3
+ metadata.gz: c23c2c1184a5c69443fdd5dad73e60ba0820bf9b5f9f6eac75b111497688e16d
4
+ data.tar.gz: baa8d260f6837fd8594ab868fe5eadf503df0b8dedc53b29abb6d89bbb09bf4c
5
5
  SHA512:
6
- metadata.gz: c46ac169ab59595c67d3d8a8c320ea7fb56e78715fbc2dd55e4e20534c8543c66f0b62dda01a6802bbaf9f071a5ebd7ffa55a17c70443e05bba8ab8c3bedce71
7
- data.tar.gz: ac9a7a7934e115957271ec1e5cc736c0df29368f18da6f9eb409069f9690cb2594d6b9bdbf6d4fd18388ce79f7285e66a357d4bb241083ca083fd57102c95746
6
+ metadata.gz: ec8447973b868405cbe625496331664adfd3caf70b64bffb53cc3c6bbfd923081c9a27f561addb6e2260974664e8dfbf01ba1776cc996793933f944a2384867c
7
+ data.tar.gz: 718ba798f5c82c7c80a69afde32f66f610f45a874fb48ed2614f4672c359a34ba65436a30c8dc32754fa678bf324e9db67f45eac88b9277c70dd6bbe0f15b3af
data/README.md CHANGED
@@ -27,6 +27,13 @@ then this functionality is already integrated with it.
27
27
  $ gem install completely
28
28
  ```
29
29
 
30
+ or with homebrew:
31
+
32
+ ```bash
33
+ $ brew install brew-gem
34
+ $ brew gem install completely
35
+ ````
36
+
30
37
  ## Using the `completely` command line
31
38
 
32
39
  The `completely` command line works with a simple YAML configuration file as
@@ -47,7 +54,7 @@ for the auto complete process.
47
54
  You can save a sample YAML file by running:
48
55
 
49
56
  ```
50
- $ completely new
57
+ $ completely init
51
58
  ```
52
59
 
53
60
  This will generate a file named `completely.yaml` with this content:
@@ -159,6 +166,37 @@ mygit:
159
166
  The `2> /dev/null` is used so that if the command is executed in a directory
160
167
  without a git repository, it will still behave as expected.
161
168
 
169
+ ### Suggesting flag arguments
170
+
171
+ Adding a `*` wildcard in the middle of a pattern can be useful for suggesting
172
+ arguments for flags. For example:
173
+
174
+ ```yaml
175
+ mygit checkout:
176
+ - --branch
177
+ - -b
178
+
179
+ mygit checkout*--branch:
180
+ - $(git branch 2> /dev/null)
181
+
182
+ mygit checkout*-b:
183
+ - $(git branch 2> /dev/null)
184
+ ```
185
+
186
+ The above will suggest git branches for commands that end with `-b` or `--branch`.
187
+ To avoid code duplication, you may use YAML aliases, so the above can also be
188
+ written like this:
189
+
190
+ ```yaml
191
+ mygit checkout:
192
+ - --branch
193
+ - -b
194
+
195
+ mygit checkout*--branch: &branches
196
+ - $(git branch 2> /dev/null)
197
+
198
+ mygit checkout*-b: *branches
199
+ ```
162
200
 
163
201
  ## Using the generated completion scripts
164
202
 
@@ -168,8 +206,24 @@ In order to enable the completions, simply source the generated script:
168
206
  $ source completely.bash
169
207
  ```
170
208
 
171
- You may wish to add this to your `~/.bashrc` file to enable this for future
172
- sessions (just be sure to use absolute path).
209
+ In order to load these completions on startup, you may want to place them in
210
+ the completions directory of your operating system, which can be either of
211
+ these (whichever exists):
212
+
213
+ - `/usr/share/bash-completion/completions`
214
+ - `/usr/local/etc/bash_completion.d`
215
+
216
+ ## Testing and debugging completion scripts
217
+
218
+ You can use the built in completions script tester by running `completely test`.
219
+
220
+ This command lets you test any completions script, whether it was generated by
221
+ completely or not.
222
+
223
+ In addition, you can set the `COMPLETELY_DEBUG` environment variable to any value
224
+ in order to generate scripts with some additional debugging functionality. Run
225
+ `completely generate --help` for additional information.
226
+
173
227
 
174
228
  ## Using from within Ruby code
175
229
 
@@ -192,6 +246,9 @@ puts completions.script
192
246
  # Or, generate a function that echos the script
193
247
  puts completions.wrapper_function
194
248
  puts completions.wrapper_function "custom_function_name"
249
+
250
+ # Or, test the completions with the Tester object
251
+ p completions.tester.test "mygit status "
195
252
  ```
196
253
 
197
254
 
@@ -1,11 +1,23 @@
1
1
  require 'mister_bin'
2
+ require 'completely/commands/init'
3
+ require 'completely/commands/preview'
4
+ require 'completely/commands/generate'
5
+ require 'completely/commands/test'
2
6
  require 'completely/version'
3
- require 'completely/command'
4
7
 
5
8
  module Completely
6
9
  class CLI
7
10
  def self.runner
8
- MisterBin::Runner.new handler: Command
11
+ runner = MisterBin::Runner.new version: Completely::VERSION,
12
+ header: "Completely - Bash Completions Generator",
13
+ footer: "Run !txtpur!completely COMMAND --help!txtrst! for more information"
14
+
15
+ runner.route 'init', to: Commands::Init
16
+ runner.route 'preview', to: Commands::Preview
17
+ runner.route 'generate', to: Commands::Generate
18
+ runner.route 'test', to: Commands::Test
19
+
20
+ runner
9
21
  end
10
22
  end
11
23
  end
@@ -0,0 +1,53 @@
1
+ require 'mister_bin'
2
+
3
+ module Completely
4
+ module Commands
5
+ class Base < MisterBin::Command
6
+
7
+ class << self
8
+ def param_config_path
9
+ param "CONFIG_PATH", "Path to the YAML configuration file [default: completely.yaml]\nCan also be set by an environment variable"
10
+ end
11
+
12
+ def option_function
13
+ option "-f --function NAME", "Modify the name of the function in the generated script"
14
+ end
15
+
16
+ def environment_config_path
17
+ environment "COMPLETELY_CONFIG_PATH", "Path to a completely configuration file [default: completely.yaml]"
18
+ end
19
+
20
+ def environment_debug
21
+ environment "COMPLETELY_DEBUG", "It not empty, the generated script will include an additional debugging snippet that outputs the compline and current word to a text file when a completion is requested"
22
+ end
23
+ end
24
+
25
+ protected
26
+
27
+ def script
28
+ @script ||= completions.script
29
+ end
30
+
31
+ def completions
32
+ @completions ||= Completions.load(config_path, function_name: args['--function'])
33
+ end
34
+
35
+ def config_path
36
+ @config_path ||= args['CONFIG_PATH'] || ENV['COMPLETELY_CONFIG_PATH'] || 'completely.yaml'
37
+ end
38
+
39
+ def script_path
40
+ @script_path ||= args['SCRIPT_PATH'] || ENV['COMPLETELY_SCRIPT_PATH'] || "#{config_basename}.bash"
41
+ end
42
+
43
+ def config_basename
44
+ File.basename config_path, File.extname(config_path)
45
+ end
46
+
47
+ def syntax_warning
48
+ say! "\n!txtred!WARNING:\nYour configuration is invalid."
49
+ say! "!txtred!All patterns must start with the same word."
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,37 @@
1
+ require 'completely/commands/base'
2
+
3
+ module Completely
4
+ module Commands
5
+ class Generate < Base
6
+ help "Generate the bash completion script to a file"
7
+
8
+ usage "completely generate [CONFIG_PATH SCRIPT_PATH --function NAME --wrap NAME]"
9
+ usage "completely generate (-h|--help)"
10
+
11
+ option_function
12
+ 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"
13
+
14
+ param_config_path
15
+ param "SCRIPT_PATH", "Path to the output bash script. When not provided, the name of the input file will be used with a .bash extension\nCan also be set by an environment variable"
16
+
17
+ environment_config_path
18
+ environment "COMPLETELY_SCRIPT_PATH", "Path to the output bash script"
19
+ environment_debug
20
+
21
+ def run
22
+ wrap = args['--wrap']
23
+ output = wrap ? wrapper_function(wrap) : script
24
+ File.write script_path, output
25
+ say "Saved !txtpur!#{script_path}"
26
+ syntax_warning unless completions.valid?
27
+ end
28
+
29
+ private
30
+
31
+ def wrapper_function(wrapper_name)
32
+ completions.wrapper_function wrapper_name
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,35 @@
1
+ require 'completely/commands/base'
2
+
3
+ module Completely
4
+ module Commands
5
+ class Init < Base
6
+ help "Create a new sample YAML configuration file"
7
+
8
+ usage "completely init [CONFIG_PATH]"
9
+ usage "completely init (-h|--help)"
10
+
11
+ param_config_path
12
+ environment_config_path
13
+
14
+ def run
15
+ if File.exist? config_path
16
+ raise "File already exists: #{config_path}"
17
+ else
18
+ File.write config_path, sample
19
+ say "Saved !txtpur!#{config_path}"
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def sample
26
+ @sample ||= File.read sample_path
27
+ end
28
+
29
+ def sample_path
30
+ @sample_path ||= File.expand_path "../templates/sample.yaml", __dir__
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,22 @@
1
+ require 'completely/commands/base'
2
+
3
+ module Completely
4
+ module Commands
5
+ class Preview < Base
6
+ help "Generate the bash completion script to STDOUT"
7
+
8
+ usage "completely preview [CONFIG_PATH --function NAME]"
9
+ usage "completely preview (-h|--help)"
10
+
11
+ option_function
12
+ param_config_path
13
+ environment_config_path
14
+ environment_debug
15
+
16
+ def run
17
+ puts script
18
+ syntax_warning unless completions.valid?
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,69 @@
1
+ require 'completely/commands/base'
2
+
3
+ module Completely
4
+ module Commands
5
+ class Test < Base
6
+ summary "Test completions"
7
+
8
+ help <<~EOF
9
+ This command can be used to test that any completion script (either generated by compeltely or not) responds with the right completions.
10
+
11
+ In order to test on a completely configuration file other than 'completely.yaml', set the COMPLETELY_CONFIG_PATH environemnt variable.
12
+
13
+ In order to test on an arbitrary completions script, set the COMPLETELY_SCRIPT_PATH and optionally the COMPLETELY_SCRIPT_FUNCTION environment variables.
14
+ EOF
15
+
16
+ usage "completely test COMPLINE"
17
+ usage "completely test (-h|--help)"
18
+
19
+ param "COMPLINE", "The command to test completions for. This will be handled as if a TAB was pressed immediately at the end of it, so the last word is considered the active cursor. If you wish to complete for the next word instead, end your command with a space."
20
+
21
+ environment_config_path
22
+ environment "COMPLETELY_SCRIPT_PATH", "Path to a completions script. When set, this script will be tested instead of the completely configuration file"
23
+ environment "COMPLETELY_SCRIPT_FUNCTION", "The main completion function to call when using a custom script. If not set, the basename of the script path will be used, prefixed by an underscore"
24
+ environment_debug
25
+
26
+ example %q[completely test "mygit pu"]
27
+ example %q[completely test "mygit pull "]
28
+ example <<~EOF
29
+ COMPLETELY_SCRIPT_PATH=/usr/share/bash-completion/completions/chown \\
30
+ completely test "chown --"
31
+ EOF
32
+
33
+ attr_reader :config, :script_path, :script_function
34
+
35
+ def run
36
+ set_vars
37
+ puts tester.test(compline).join "\n"
38
+ end
39
+
40
+ private
41
+
42
+ def compline
43
+ args['COMPLINE']
44
+ end
45
+
46
+ def tester
47
+ if config
48
+ completions = Completions.load config
49
+ completions.tester
50
+ else
51
+ Tester.new script_path: script_path, function_name: script_function
52
+ end
53
+ end
54
+
55
+ def set_vars
56
+ if ENV['COMPLETELY_CONFIG_PATH']
57
+ @config = ENV['COMPLETELY_CONFIG_PATH']
58
+ elsif ENV['COMPLETELY_SCRIPT_PATH']
59
+ @script_path = ENV['COMPLETELY_SCRIPT_PATH']
60
+ @script_function = ENV['COMPLETELY_SCRIPT_FUNCTION'] || "_#{File.basename(script_path)}"
61
+ elsif File.exist? 'completely.yaml'
62
+ @config = 'completely.yaml'
63
+ else
64
+ raise "Please set the proper environment variables or run in a folder with completely.yaml"
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -10,7 +10,9 @@ module Completely
10
10
  begin
11
11
  data = YAML.load_file config_path, aliases: true
12
12
  rescue ArgumentError
13
+ # :nocov:
13
14
  data = YAML.load_file config_path
15
+ # :nocov:
14
16
  end
15
17
 
16
18
  new data, function_name: function_name
@@ -44,6 +46,10 @@ module Completely
44
46
  "#{name}() {\n#{script_lines}\n}"
45
47
  end
46
48
 
49
+ def tester
50
+ @tester ||= Tester.new script: script, function_name: function_name
51
+ end
52
+
47
53
  private
48
54
 
49
55
  def patterns!
@@ -53,7 +59,7 @@ module Completely
53
59
  end
54
60
 
55
61
  def template_path
56
- @template_path ||= File.expand_path("template.erb", __dir__)
62
+ @template_path ||= File.expand_path("templates/template.erb", __dir__)
57
63
  end
58
64
 
59
65
  def template
@@ -30,8 +30,18 @@ module Completely
30
30
  text.split(' ')[0]
31
31
  end
32
32
 
33
+ def case_string
34
+ if text_without_prefix.empty?
35
+ "*"
36
+ elsif text_without_prefix.include? "*"
37
+ %Q['#{text_without_prefix.gsub "*", "'*'"}']
38
+ else
39
+ %Q['#{text_without_prefix}'*]
40
+ end
41
+ end
42
+
33
43
  def text_without_prefix
34
- text.split(' ')[1..-1].join ' '
44
+ @text_without_prefix ||= text.split(' ')[1..-1].join ' '
35
45
  end
36
46
 
37
47
  def compgen
@@ -0,0 +1,33 @@
1
+ # <%= "#{command} completion".ljust 56 %> -*- shell-script -*-
2
+
3
+ # This bash completions script was generated by
4
+ # completely (https://github.com/dannyben/completely)
5
+ # Modifying it manually is not recommended
6
+
7
+ <%= function_name %>() {
8
+ local cur compline
9
+ _init_completion -s || return
10
+
11
+ cur=${COMP_WORDS[COMP_CWORD]}
12
+ compline="${COMP_WORDS[@]:1:$COMP_CWORD-1}"
13
+
14
+ % if ENV['COMPLETELY_DEBUG']
15
+ if [[ -n "$COMPLETELY_DEBUG" ]]; then
16
+ echo "compline: '$compline'" > 'completely-debug.txt'
17
+ echo "cur: '$cur'" >> 'completely-debug.txt'
18
+ fi
19
+
20
+ %end
21
+ case "$compline" in
22
+ % patterns.each do |pattern|
23
+ % next if pattern.empty?
24
+ <%= pattern.case_string %>)
25
+ COMPREPLY=($(compgen <%= pattern.compgen %> -- "$cur"))
26
+ ;;
27
+
28
+ % end
29
+ esac
30
+ } &&
31
+ complete -F <%= function_name %> <%= command %>
32
+
33
+ # ex: filetype=sh
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+ <%= script || %Q[source "#{absolute_script_path}"] %>
3
+
4
+ # END OF COMPLETION SCRIPT
5
+
6
+ source /usr/share/bash-completion/bash_completion
7
+ COMP_WORDS=( <%= compline %> )
8
+ COMP_LINE="<%= compline %>"
9
+ COMP_POINT=${#COMP_LINE}
10
+ COMP_CWORD=<%= cword %>
11
+
12
+ <%= function_name %>
13
+ echo "${COMPREPLY[*]}"
@@ -0,0 +1,48 @@
1
+ require 'erb'
2
+ require 'tempfile'
3
+
4
+ module Completely
5
+ class Tester
6
+ attr_reader :script, :script_path, :function_name, :cword, :compline
7
+
8
+ def initialize(script: nil, script_path: nil, function_name: )
9
+ @script, @script_path, @function_name = script, script_path, function_name
10
+ end
11
+
12
+ def test(compline)
13
+ Tempfile.create "completely-tester" do |f|
14
+ f << tester_script(compline)
15
+ f.flush
16
+ `bash #{f.path}`
17
+ end.split " "
18
+ end
19
+
20
+ def tester_script(compline)
21
+ set_compline_vars compline
22
+ ERB.new(template, trim_mode: '%-').result(binding)
23
+ end
24
+
25
+ protected
26
+
27
+ def set_compline_vars(compline)
28
+ @compline = compline
29
+ @cword = compline.split(' ').size - 1
30
+ @cword += 1 if compline.end_with? ' '
31
+ end
32
+
33
+ def absolute_script_path
34
+ @absolute_script_path ||= begin
35
+ script_path ? File.expand_path(script_path) : nil
36
+ end
37
+ end
38
+
39
+ def template_path
40
+ @template_path ||= File.expand_path "templates/tester-template.erb", __dir__
41
+ end
42
+
43
+ def template
44
+ @template ||= File.read template_path
45
+ end
46
+
47
+ end
48
+ end
@@ -1,3 +1,3 @@
1
1
  module Completely
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/completely.rb CHANGED
@@ -5,3 +5,4 @@ end
5
5
 
6
6
  require 'completely/pattern'
7
7
  require 'completely/completions'
8
+ require 'completely/tester'
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.3.1
4
+ version: 0.4.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: 2022-02-20 00:00:00.000000000 Z
11
+ date: 2022-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colsole
@@ -49,11 +49,17 @@ files:
49
49
  - bin/completely
50
50
  - lib/completely.rb
51
51
  - lib/completely/cli.rb
52
- - lib/completely/command.rb
52
+ - lib/completely/commands/base.rb
53
+ - lib/completely/commands/generate.rb
54
+ - lib/completely/commands/init.rb
55
+ - lib/completely/commands/preview.rb
56
+ - lib/completely/commands/test.rb
53
57
  - lib/completely/completions.rb
54
58
  - lib/completely/pattern.rb
55
- - lib/completely/sample.yaml
56
- - lib/completely/template.erb
59
+ - lib/completely/templates/sample.yaml
60
+ - lib/completely/templates/template.erb
61
+ - lib/completely/templates/tester-template.erb
62
+ - lib/completely/tester.rb
57
63
  - lib/completely/version.rb
58
64
  homepage: https://github.com/dannyben/completely
59
65
  licenses:
@@ -74,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
74
80
  - !ruby/object:Gem::Version
75
81
  version: '0'
76
82
  requirements: []
77
- rubygems_version: 3.2.15
83
+ rubygems_version: 3.3.3
78
84
  signing_key:
79
85
  specification_version: 4
80
86
  summary: Bash Completions Generator
@@ -1,87 +0,0 @@
1
- module Completely
2
- class Command < MisterBin::Command
3
- help "Bash completion script generator"
4
- version Completely::VERSION
5
-
6
- usage "completely new [CONFIG_PATH]"
7
- usage "completely preview [CONFIG_PATH --function NAME]"
8
- usage "completely generate [CONFIG_PATH OUTPUT_PATH --function NAME --wrap NAME]"
9
- usage "completely (-h|--help|--version)"
10
-
11
- command "new", "Create a new sample YAML configuration file"
12
- command "preview", "Generate the bash completion script to STDOUT"
13
- command "generate", "Generate the bash completion script to a file"
14
-
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"
17
-
18
- param "CONFIG_PATH", "Path to the YAML configuration file"
19
- param "OUTPUT_PATH", "Path to the output bash script"
20
-
21
- example "completely new"
22
- example "completely new input.yaml"
23
- example "completely preview --function _my_completions"
24
- example "completely generate"
25
- example "completely generate input.yaml"
26
- example "completely generate input.yaml output.sh -f _my_completions"
27
- example "completely generate -w give_comps -f my_completions"
28
-
29
- def new_command
30
- if File.exist? config_path
31
- raise "File already exists: #{config_path}"
32
- else
33
- File.write config_path, sample
34
- say "Saved !txtpur!#{config_path}"
35
- end
36
- end
37
-
38
- def preview_command
39
- puts script
40
- syntax_warning unless completions.valid?
41
- end
42
-
43
- def generate_command
44
- wrap = args['--wrap']
45
- output = wrap ? wrapper_function(wrap) : script
46
- File.write output_path, output
47
- say "Saved !txtpur!#{output_path}"
48
- syntax_warning unless completions.valid?
49
- end
50
-
51
- private
52
-
53
- def config_path
54
- @config_path ||= args['CONFIG_PATH'] || "completely.yaml"
55
- end
56
-
57
- def output_path
58
- @output_path ||= args['OUTPUT_PATH'] || "completely.bash"
59
- end
60
-
61
- def sample
62
- @sample ||= File.read(sample_path)
63
- end
64
-
65
- def sample_path
66
- @sample_path ||= File.expand_path("sample.yaml", __dir__)
67
- end
68
-
69
- def script
70
- @script ||= completions.script
71
- end
72
-
73
- def wrapper_function(wrapper_name)
74
- completions.wrapper_function wrapper_name
75
- end
76
-
77
- def completions
78
- @completions ||= Completions.load(config_path, function_name: args['--function'])
79
- end
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
-
86
- end
87
- end
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env bash
2
-
3
- # This bash completions script was generated by
4
- # completely (https://github.com/dannyben/completely)
5
- # Modifying it manually is not recommended
6
- <%= function_name %>() {
7
- local cur=${COMP_WORDS[COMP_CWORD]}
8
- local comp_line="${COMP_WORDS[@]:1}"
9
-
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")) ;;
14
- % end
15
- esac
16
- }
17
-
18
- complete -F <%= function_name %> <%= command %>