Skip to content

Commit

Permalink
Add code to generate bash completion script.
Browse files Browse the repository at this point in the history
  • Loading branch information
sjohannes committed Apr 27, 2017
1 parent b47fc1e commit 609db72
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ data/plugins
po/*/
po/POTFILES.in

/exaile.bash-completion

backup.bzr
random
exaile-dist.tar.bz2
Expand Down
18 changes: 16 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,22 @@ MANPREFIX ?= $(PREFIX)/share
ETCDIR := $(shell [ "$(PREFIX)" = "/usr" ] && echo /etc || echo "$(PREFIX)/etc")
XDGCONFDIR ?= $(ETCDIR)/xdg

# Find bash-completion's completions directory, first by checking pkg-config,
# then using a hard-coded path. Override BASHCOMPDIR if it's still wrong for
# your OS.
BASHCOMPDIR := $(shell pkg-config --define-variable=prefix="$(PREFIX)" \
--variable=completionsdir bash-completion 2> /dev/null \
|| echo "$(PREFIX)/share/bash-completion/completions")

EXAILEBINDIR = $(DESTDIR)$(EPREFIX)/bin
EXAILELIBDIR = $(DESTDIR)$(LIBINSTALLDIR)/exaile
EXAILESHAREDIR = $(DESTDIR)$(DATADIR)/exaile
EXAILECONFDIR = $(DESTDIR)$(XDGCONFDIR)/exaile
EXAILEMANDIR = $(DESTDIR)$(MANPREFIX)/man

.PHONY: dist test coverage clean sanitycheck
.PHONY: dist test completion coverage clean sanitycheck

all: compile locale manpage
all: compile completion locale manpage
@echo "Ready to install..."

# The no_locale stuff is by request of BSD people, please ensure
Expand Down Expand Up @@ -68,6 +75,7 @@ make-install-dirs:
mkdir -p $(DESTDIR)$(DATADIR)/applications
mkdir -p $(DESTDIR)$(DATADIR)/dbus-1/services
mkdir -p $(EXAILEMANDIR)/man1
mkdir -p $(DESTDIR)$(BASHCOMPDIR)
mkdir -p $(EXAILECONFDIR)

uninstall:
Expand All @@ -79,6 +87,7 @@ uninstall:
rm -f $(DESTDIR)$(DATADIR)/pixmaps/exaile.png
rm -f $(DESTDIR)$(DATADIR)/dbus-1/services/org.exaile.Exaile.service
rm -f $(EXAILEMANDIR)/man1/exaile.1.gz
rm -f $(DESTDIR)$(BASHCOMPDIR)/exaile
$(MAKE) -C plugins uninstall
find $(DESTDIR)$(DATADIR)/locale -name "exaile.mo" -exec rm -f {} \;

Expand Down Expand Up @@ -137,6 +146,7 @@ install-target: make-install-dirs
install -m 644 data/exaile.appdata.xml \
$(DESTDIR)$(DATADIR)/appdata/
install -m 644 exaile.1.gz $(EXAILEMANDIR)/man1/
-install -m 644 exaile.bash-completion $(DESTDIR)$(BASHCOMPDIR)/exaile
install -m 644 data/config/settings.ini $(EXAILECONFDIR)
tools/generate-launcher "$(DESTDIR)" "$(PREFIX)" "$(EPREFIX)" "$(LIBINSTALLDIR)" \
"$(PYTHON2_CMD)" && \
Expand Down Expand Up @@ -166,11 +176,15 @@ manpage:
./exaile \
| gzip -9 > exaile.1.gz

completion:
$(PYTHON_CMD) tools/generate-completion.py > exaile.bash-completion

clean:
-find . -name "*.~[0-9]~" -exec rm -f {} \;
-find . -name "*.py[co]" -exec rm -f {} \;
find po/* -depth -type d -exec rm -r {} \;
rm -f exaile.1.gz
rm -f exaile.bash-completion
$(MAKE) -C plugins clean

# The "LC_ALL=C" disables any locale-dependent sort behavior.
Expand Down
105 changes: 105 additions & 0 deletions tools/generate-completion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env python

# Copyright (C) 2015, 2017 Johannes Sasongko <sasongko@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.


from __future__ import division, print_function, unicode_literals

import argparse


TEMPLATE = '''_%(prog)s() {
local cur="${COMP_WORDS[COMP_CWORD]}"
local prev="${COMP_WORDS[COMP_CWORD-1]}"
case "${prev}" in
%(prev_opts)s
esac
case "${cur}" in
%(cur_opts)s
esac
}
complete -F _%(prog)s %(prog)s'''

TEMPLATE_OPT = ''' %(opt)s)
%(reply)s
return 0
;;'''

TEMPLATE_REPLY_W = ''' COMPREPLY=( $(compgen -W "%(opts)s" -- ${cur}) )'''
TEMPLATE_REPLY_f = ''' COMPREPLY=( $(compgen -f ${cur}) )'''
TEMPLATE_REPLY_d = ''' COMPREPLY=( $(compgen -d ${cur}) )'''
TEMPLATE_REPLY_empty = ''' COMPREPLY=()'''


def bash_completion(parser):
"""
:type parser: argparse.ArgumentParser
"""
actions = parser._actions

opt_names = []
filearg_opt_names = []
dirarg_opt_names = []
arg_opt_names = []
for action in actions:
names = action.option_strings
if not names: # Positional args
continue
opt_names.extend(names)
if action.metavar == 'LOCATION':
filearg_opt_names.extend(names)
elif action.metavar == 'DIRECTORY':
dirarg_opt_names.extend(names)
elif action.metavar is not None:
arg_opt_names.extend(names)

return TEMPLATE % {
'prog': 'exaile',
'prev_opts': '\n'.join([
TEMPLATE_OPT % {
'opt': '|'.join(filearg_opt_names),
'reply': TEMPLATE_REPLY_f,
},
TEMPLATE_OPT % {
'opt': '|'.join(dirarg_opt_names),
'reply': TEMPLATE_REPLY_d,
},
TEMPLATE_OPT % {
'opt': '|'.join(arg_opt_names),
'reply': TEMPLATE_REPLY_empty,
},
]),
'cur_opts': '\n'.join([
TEMPLATE_OPT % {
'opt': '-*',
'reply': TEMPLATE_REPLY_W % {'opts': ' '.join(opt_names)},
},
TEMPLATE_OPT % {
'opt': '*',
'reply': TEMPLATE_REPLY_f,
},
]),
}

if __name__ == '__main__':
import os, sys
root = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
os.environ['LC_ALL'] = 'C' # Avoid getting translated metavars
os.environ['EXAILE_DIR'] = root
sys.path.append(root)
from xl import main
p = main.create_argument_parser()
print(bash_completion(p))

0 comments on commit 609db72

Please sign in to comment.