make commandline-tab-completion available
Here is a quick script that spits out options for tab-completion of most of the schleuder-cli commands.
It will live-query the list of lists, subscriptions or keys to suggest possible values.
Not sure if this can be added to a debian-package? A quick search yielded no results on what the policy or strategy would be?
There are some hints on how to set completion up for a local user in BASH and ZSH on top of the script.
I'm thankful for all kind of feedback, since this is my very first attempt in shell-completion.
File: schleuder-cli-completion.rb
#!/usr/bin/env ruby
# activate via:
# in BASH
# complete -C "/path/to/schleuder-cli-completion.rb" -o default schleuder-cli
# in ZSH
# function _schleueder-cli-completion() {
# read -l
# local cl="$REPLY"
# reply=(`COMP_LINE="$cl" /path/to/schleuder-cli-completion.rb`)
# }
# compctl -K _schleueder-cli-completion schleuder-cli
class SchleuderCliCompletion
def initialize(command_line)
@tokens = command_line.split(/\s+/).drop(1)
@command = extract_command(@tokens)
@subcommand = extract_subcommand(@tokens)
@listname = extract_listname(@tokens)
@value_after_listname = extract_value_after_listname(@tokens)
end
def extract_command(tokens)
return unless tokens.size >= 1
if tree.keys.include?(tokens.first)
tokens.first
else
@filter_string = tokens.first
nil
end
end
def extract_subcommand(tokens)
return unless tokens.size >= 2 && @command
if tree[@command].keys.include?(tokens[1])
tokens[1]
else
@filter_string = tokens[1]
nil
end
end
def extract_listname(tokens)
return unless tokens.size >= 3 && @command && @subcommand
if tokens[2] =~ /^.+@.+\.[^.]+/
tokens[2]
else
@filter_string = tokens[2]
nil
end
end
def extract_value_after_listname(tokens)
return unless tokens.size >= 4 && @command && @subcommand && @listname
if tokens[3] =~ /^.+@.+\.[^.]+/ || list_options.include?(tokens[3])
tokens[3]
else
@filter_string = tokens[3]
nil
end
end
def suggestions
# puts "c: #{@command}, s: #{@subcommand}, l: #{@listname}, val: #{@value_after_listname}, fs: #{@filter_string}"
return '' unless options.to_a.any?
@filter_string ? options.grep(/^#{@filter_string}/) : options
end
def options
if @command && @subcommand && @listname
return options_after_listname(@command, @subcommand, @listname)
end
if @command && @subcommand
return options_for_subcommand(@command, @subcommand)
end
return tree[@command].keys if @command
tree.keys
end
def options_for_subcommand(command, subcommand)
next_argument = tree[command][subcommand]
if next_argument == 'listname' ||
(next_argument.is_a?(Hash) && next_argument.keys.first == 'listname')
return list_of_lists
end
if next_argument == 'command'
return tree[command].keys - ['help']
end
end
def options_after_listname(command, subcommand, listname)
if command == 'subscriptions' &&
%w[set show].include?(subcommand) &&
@value_after_listname
@filter_string = @tokens[4]
return subscription_options
end
if command == 'subscriptions' && %w[set show delete].include?(subcommand)
return list_of_subscriptions(listname)
end
if command == 'lists' && %w[set show].include?(subcommand)
return list_options
end
if command == 'keys' && %w[delete export].include?(subcommand)
return list_of_fingerprints(listname)
end
end
def list_of_lists
`schleuder-cli lists list`.split(/\n/)
# %w[abc@listserver.com cde@listserver.de efg@listserver.org]
end
def list_of_subscriptions(listname)
`schleuder-cli subscriptions list #{listname}`
.split(/\n/)
.map { |l| l.sub(/\s.*\z/, '') }
# %w[abc@usermail.com cde@usermail.de efg@usermail.org]
end
def list_of_fingerprints(listname)
`schleuder-cli keys list #{listname}`
.split(/\n/)
.map { |l| l.sub(/\s.*\z/, '') }
# %w[acab bcda acad]
end
def tree
{
'help' => {
'keys' => nil,
'lists' => nil,
'subscriptions' => nil
},
'keys' => {
'check' => 'listname',
'delete' => { 'listname' => 'fingerprint' },
'export' => { 'listname' => 'fingerprint' },
'help' => 'command',
'import' => 'listname',
'list' => 'listname'
},
'lists' => {
'delete' => 'listname',
'help' => 'command',
'list' => nil,
'list-options' => nil,
'new' => nil,
'send-list-key-to-subscriptions' => 'listname',
'set' => { 'listname' => { 'option' => 'value' } },
'show' => { 'listname' => 'option' }
},
'subscriptions' => {
'delete' => { 'listname' => 'username' },
'help' => 'command',
'list' => 'listname',
'list-options' => nil,
'new' => 'listname',
'set' => { 'listname' => { 'username' => { 'option' => 'value' } } },
'show' => { 'listname' => { 'username' => 'option' } }
},
'version' => {}
}
end
def list_options
%w[
bounces_drop_all
bounces_drop_on_headers
bounces_notify_admins
forward_all_incoming_to_admins
headers_to_meta
include_list_headers
include_openpgp_header
internal_footer
keep_msgid
keywords_admin_notify
keywords_admin_only
language
log_level
logfiles_to_keep
max_message_size_kb
openpgp_header_preference
public_footer
receive_admin_only
receive_authenticated_only
receive_encrypted_only
receive_from_subscribed_emailaddresses_only
receive_signed_only
send_encrypted_only
subject_prefix
subject_prefix_in
subject_prefix_out
]
end
def subscription_options
%w[
fingerprint
admin
delivery_enabled
]
end
end
command_line = ENV.fetch('COMP_LINE')
puts SchleuderCliCompletion.new(command_line).suggestions
Edited by init void