Last active
August 29, 2015 14:01
-
-
Save fredrikhl/eb7934613d1acfc94db9 to your computer and use it in GitHub Desktop.
pyrc-autocomplete
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# | |
"""Python startup script.""" | |
class IndentOrCompleteMixin(object): | |
u""" Mixin to add tab completion for inserting indents. | |
The idea is that a (base10) natural number (e.g. 3, 45) has no sensible | |
auto-complete value. This mixin, intended for use with rlcompleter, adds | |
completion for numbers. When suggesting number completions, however, this | |
mixin only returns one suggestion - which is a string containing that | |
number of indents. | |
""" | |
bind_backend = {'libedit': u'bind ^I rl_complete', | |
'readline': u'tab: complete', } | |
u""" The command used to bind tab to completion with different | |
python readline implementations. """ | |
def __init__(self, indent=' '): | |
u""" Initialize completer. | |
:param str indent: The intent string we want (default=' ') | |
""" | |
self.__tab = indent | |
super(IndentOrCompleteMixin, self).__init__() | |
@classmethod | |
def get_bind_command(cls, readline_module): | |
u""" Get keybind command suggestion for `readline_module'. | |
Parses the docstring of `readline_module', to decide which | |
implementation it is. | |
:param readline_module: The imported readline module. | |
:return str: | |
Returns a command string that can be passed to | |
`readline_module.parse_and_bind()' | |
""" | |
if 'GNU readline' in getattr(readline_module, '__doc__', ''): | |
return cls.bind_backend['readline'] | |
elif 'libedit' in getattr(readline_module, '__doc__', ''): | |
return cls.bind_backend['libedit'] | |
# No match, gamble that it will work with readline command | |
return cls.bind_backend['readline'] | |
def complete(self, text, state): | |
u""" Fetch next suggestion. | |
:param str text: The actual text we're completing. | |
:param int state: The suggestion number | |
:ref: `readline documentation <python:readline>` | |
:rtype: NoneType, basestring | |
:return: Suggestion string, or None if no more suggestions exist. | |
""" | |
if text.isdigit(): | |
if state == 0: | |
num = int(text) | |
return self.__tab * num | |
return None | |
else: | |
return super(IndentOrCompleteMixin, self).complete(text, state) | |
@classmethod | |
def get_completer(cls, completer=type): | |
u""" Prepare a completer class with this mixin. | |
:type completer: type | |
:param completer: | |
Use `completer' as base class. If `completer' already have `cls' in | |
its bases, we do nothing (just return `completer' as is). | |
If `completer' is `type' or `cls', we try to use | |
`rlcompleter.Completer' as base class (this is the default). | |
:return type: Returns a completer class with this mixin. | |
""" | |
if type(completer) is not type: | |
raise TypeError( | |
"`completer' must be of type 'type' (not %s)" % | |
type(completer)) | |
if completer is type or completer == cls: | |
from rlcompleter import Completer as completer | |
if not issubclass(completer, cls): | |
completer = type('_IndentOrComplete', | |
(cls, completer, object), | |
{}) | |
return completer | |
@classmethod | |
def register(cls, *args, **kwargs): | |
u""" Register with readline. | |
Performs the neccessay readline magic to enable this completer in | |
an interactive session. | |
""" | |
import readline | |
completer_cls = cls.get_completer() | |
readline.parse_and_bind(cls.get_bind_command(readline)) | |
readline.set_completer(completer_cls(*args, **kwargs).complete) | |
if __name__ == '__main__': | |
try: | |
IndentOrCompleteMixin.register() | |
except ImportError: | |
print(u"NOTE: Unable to set up tab completion") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To use from scripts that invoke an interactive session (e.g. with
code.interact()
), just doexecfile('/path/to/thisfile')
before the interactive session is set up.