completely 0.1.0 → 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: 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