ipy_stock_completers.py
248 lines
| 7.8 KiB
| text/x-python
|
PythonLexer
vivainio
|
r503 | """ Tab completion support for a couple of linux package managers | ||
This is also an example of how to write custom completer plugins | ||||
or hooks. | ||||
Practical use: | ||||
[ipython]|1> import ipy_linux_package_managers | ||||
[ipython]|2> apt-get u<<< press tab here >>> | ||||
update upgrade | ||||
[ipython]|2> apt-get up | ||||
""" | ||||
import IPython.ipapi | ||||
import glob,os,shlex,sys | ||||
ip = IPython.ipapi.get() | ||||
def vcs_completer(commands, event): | ||||
""" utility to make writing typical version control app completers easier | ||||
VCS command line apps typically have the format: | ||||
[sudo ]PROGNAME [help] [command] file file... | ||||
""" | ||||
cmd_param = event.line.split() | ||||
if event.line.endswith(' '): | ||||
cmd_param.append('') | ||||
if cmd_param[0] == 'sudo': | ||||
cmd_param = cmd_param[1:] | ||||
if len(cmd_param) == 2 or 'help' in cmd_param: | ||||
return commands.split() | ||||
return ip.IP.Completer.file_matches(event.symbol) | ||||
def apt_completers(self, event): | ||||
""" This should return a list of strings with possible completions. | ||||
Note that all the included strings that don't start with event.symbol | ||||
are removed, in order to not confuse readline. | ||||
""" | ||||
# print event # dbg | ||||
# commands are only suggested for the 'command' part of package manager | ||||
# invocation | ||||
cmd = (event.line + "<placeholder>").rsplit(None,1)[0] | ||||
# print cmd | ||||
if cmd.endswith('apt-get') or cmd.endswith('yum'): | ||||
return ['update', 'upgrade', 'install', 'remove'] | ||||
# later on, add dpkg -l / whatever to get list of possible | ||||
# packages, add switches etc. for the rest of command line | ||||
# filling | ||||
raise IPython.ipapi.TryNext | ||||
# re_key specifies the regexp that triggers the specified completer | ||||
ip.set_hook('complete_command', apt_completers, re_key = '.*apt-get') | ||||
ip.set_hook('complete_command', apt_completers, re_key = '.*yum') | ||||
pkg_cache = None | ||||
def module_completer(self,event): | ||||
""" Give completions after user has typed 'import' """ | ||||
# only a local version for py 2.4, pkgutil has no walk_packages() there | ||||
if sys.version_info < (2,5): | ||||
for el in [f[:-3] for f in glob.glob("*.py")]: | ||||
yield el | ||||
return | ||||
global pkg_cache | ||||
import pkgutil,imp,time | ||||
#current = | ||||
if pkg_cache is None: | ||||
print "\n\n[Standby while scanning modules, this can take a while]\n\n" | ||||
pkg_cache = list(pkgutil.walk_packages()) | ||||
already = set() | ||||
for ld, name, ispkg in pkg_cache: | ||||
if name.count('.') < event.symbol.count('.') + 1: | ||||
if name not in already: | ||||
already.add(name) | ||||
yield name + (ispkg and '.' or '') | ||||
return | ||||
ip.set_hook('complete_command', module_completer, str_key = 'import') | ||||
ip.set_hook('complete_command', module_completer, str_key = 'from') | ||||
svn_commands = """\ | ||||
add blame praise annotate ann cat checkout co cleanup commit ci copy | ||||
cp delete del remove rm diff di export help ? h import info list ls | ||||
lock log merge mkdir move mv rename ren propdel pdel pd propedit pedit | ||||
pe propget pget pg proplist plist pl propset pset ps resolved revert | ||||
status stat st switch sw unlock update | ||||
""" | ||||
def svn_completer(self,event): | ||||
return vcs_completer(svn_commands, event) | ||||
ip.set_hook('complete_command', svn_completer, str_key = 'svn') | ||||
hg_commands = """ | ||||
add addremove annotate archive backout branch branches bundle cat | ||||
clone commit copy diff export grep heads help identify import incoming | ||||
init locate log manifest merge outgoing parents paths pull push | ||||
qapplied qclone qcommit qdelete qdiff qfold qguard qheader qimport | ||||
qinit qnew qnext qpop qprev qpush qrefresh qrename qrestore qsave | ||||
qselect qseries qtop qunapplied recover remove rename revert rollback | ||||
root serve showconfig status strip tag tags tip unbundle update verify | ||||
version | ||||
""" | ||||
def hg_completer(self,event): | ||||
""" Completer for mercurial commands """ | ||||
return vcs_completer(hg_commands, event) | ||||
ip.set_hook('complete_command', hg_completer, str_key = 'hg') | ||||
bzr_commands = """ | ||||
add annotate bind branch break-lock bundle-revisions cat check | ||||
checkout commit conflicts deleted diff export gannotate gbranch | ||||
gcommit gdiff help ignore ignored info init init-repository inventory | ||||
log merge missing mkdir mv nick pull push reconcile register-branch | ||||
remerge remove renames resolve revert revno root serve sign-my-commits | ||||
status testament unbind uncommit unknowns update upgrade version | ||||
version-info visualise whoami | ||||
""" | ||||
def bzr_completer(self,event): | ||||
""" Completer for bazaar commands """ | ||||
cmd_param = event.line.split() | ||||
if event.line.endswith(' '): | ||||
cmd_param.append('') | ||||
if len(cmd_param) > 2: | ||||
cmd = cmd_param[1] | ||||
param = cmd_param[-1] | ||||
output_file = (param == '--output=') | ||||
if cmd == 'help': | ||||
return bzr_commands.split() | ||||
elif cmd in ['bundle-revisions','conflicts', | ||||
'deleted','nick','register-branch', | ||||
'serve','unbind','upgrade','version', | ||||
'whoami'] and not output_file: | ||||
return [] | ||||
else: | ||||
# the rest are probably file names | ||||
return ip.IP.Completer.file_matches(event.symbol) | ||||
return bzr_commands.split() | ||||
ip.set_hook('complete_command', bzr_completer, str_key = 'bzr') | ||||
vivainio
|
r544 | |||
def shlex_split(x): | ||||
"""Helper function to split lines into segments.""" | ||||
#shlex.split raise exception if syntax error in sh syntax | ||||
#for example if no closing " is found. This function keeps dropping | ||||
#the last character of the line until shlex.split does not raise | ||||
#exception. Adds end of the line to the result of shlex.split | ||||
#example: %run "c:/python -> ['%run','"c:/python'] | ||||
endofline=[] | ||||
while x!="": | ||||
try: | ||||
comps=shlex.split(x) | ||||
if endofline>=1: | ||||
comps.append("".join(endofline)) | ||||
return comps | ||||
except ValueError: | ||||
endofline=[x[-1:]]+endofline | ||||
x=x[:-1] | ||||
return ["".join(endofline)] | ||||
vivainio
|
r503 | |||
def runlistpy(self, event): | ||||
vivainio
|
r544 | comps = shlex_split(event.line) | ||
relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"") | ||||
fperez
|
r516 | #print "\nev=",event # dbg | ||
#print "rp=",relpath # dbg | ||||
#print 'comps=',comps # dbg | ||||
vivainio
|
r503 | lglob = glob.glob | ||
isdir = os.path.isdir | ||||
if relpath.startswith('~'): | ||||
relpath = os.path.expanduser(relpath) | ||||
dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') | ||||
if isdir(f)] | ||||
fperez
|
r516 | |||
# Find if the user has already typed the first filename, after which we | ||||
# should complete on all files, since after the first one other files may | ||||
# be arguments to the input script. | ||||
#filter( | ||||
if filter(lambda f: f.endswith('.py') or f.endswith('.ipy'),comps): | ||||
pys = [f.replace('\\','/') for f in lglob('*')] | ||||
else: | ||||
pys = [f.replace('\\','/') | ||||
for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy')] | ||||
vivainio
|
r503 | return dirs + pys | ||
ip.set_hook('complete_command', runlistpy, str_key = '%run') | ||||
def cd_completer(self, event): | ||||
relpath = event.symbol | ||||
#print event # dbg | ||||
if '-b' in event.line: | ||||
# return only bookmark completions | ||||
bkms = self.db.get('bookmarks',{}) | ||||
return bkms.keys() | ||||
if event.symbol == '-': | ||||
# jump in directory history by number | ||||
ents = ['-%d [%s]' % (i,s) for i,s in enumerate(ip.user_ns['_dh'])] | ||||
if len(ents) > 1: | ||||
return ents | ||||
return [] | ||||
if relpath.startswith('~'): | ||||
relpath = os.path.expanduser(relpath).replace('\\','/') | ||||
found = [] | ||||
for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*') | ||||
if os.path.isdir(f)]: | ||||
if ' ' in d: | ||||
# we don't want to deal with any of that, complex code | ||||
# for this is elsewhere | ||||
raise IPython.ipapi.TryNext | ||||
found.append( d ) | ||||
if not found: | ||||
if os.path.isdir(relpath): | ||||
return [relpath] | ||||
raise IPython.ipapi.TryNext | ||||
return found | ||||
ip.set_hook('complete_command', cd_completer, str_key = '%cd') | ||||