diff options
Diffstat (limited to 'powerline/bindings/pdb/__init__.py')
-rw-r--r-- | powerline/bindings/pdb/__init__.py | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/powerline/bindings/pdb/__init__.py b/powerline/bindings/pdb/__init__.py new file mode 100644 index 0000000..4033e61 --- /dev/null +++ b/powerline/bindings/pdb/__init__.py @@ -0,0 +1,183 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import pdb + +from powerline.pdb import PDBPowerline +from powerline.lib.encoding import get_preferred_output_encoding +from powerline.lib.unicode import unicode + + +if sys.version_info < (3,): + # XXX The below classes make code compatible with PDBpp which uses pyrepl + # which does not expect unicode or something above ASCII. They are + # completely not needed if pdbpp is not used, but that’s not always the + # case. + class PowerlineRenderBytesResult(bytes): + def __new__(cls, s, encoding=None): + encoding = encoding or s.encoding + if isinstance(s, PowerlineRenderResult): + return s.encode(encoding) + self = bytes.__new__(cls, s.encode(encoding) if isinstance(s, unicode) else s) + self.encoding = encoding + return self + + for meth in ( + '__contains__', + 'partition', 'rpartition', + 'split', 'rsplit', + 'count', 'join', + ): + exec(( + 'def {0}(self, *args):\n' + ' if any((isinstance(arg, unicode) for arg in args)):\n' + ' return self.__unicode__().{0}(*args)\n' + ' else:\n' + ' return bytes.{0}(self, *args)' + ).format(meth)) + + for meth in ( + 'find', 'rfind', + 'index', 'rindex', + ): + exec(( + 'def {0}(self, *args):\n' + ' if any((isinstance(arg, unicode) for arg in args)):\n' + ' args = [arg.encode(self.encoding) if isinstance(arg, unicode) else arg for arg in args]\n' + ' return bytes.{0}(self, *args)' + ).format(meth)) + + def __len__(self): + return len(self.decode(self.encoding)) + + def __getitem__(self, *args): + return PowerlineRenderBytesResult(bytes.__getitem__(self, *args), encoding=self.encoding) + + def __getslice__(self, *args): + return PowerlineRenderBytesResult(bytes.__getslice__(self, *args), encoding=self.encoding) + + @staticmethod + def add(encoding, *args): + if any((isinstance(arg, unicode) for arg in args)): + return PowerlineRenderResult(''.join(( + arg + if isinstance(arg, unicode) + else arg.decode(encoding) + for arg in args + )), encoding) + else: + return PowerlineRenderBytesResult(b''.join(args), encoding=encoding) + + def __add__(self, other): + return self.add(self.encoding, self, other) + + def __radd__(self, other): + return self.add(self.encoding, other, self) + + def __unicode__(self): + return PowerlineRenderResult(self) + + class PowerlineRenderResult(unicode): + def __new__(cls, s, encoding=None): + encoding = ( + encoding + or getattr(s, 'encoding', None) + or get_preferred_output_encoding() + ) + if isinstance(s, unicode): + self = unicode.__new__(cls, s) + else: + self = unicode.__new__(cls, s, encoding, 'replace') + self.encoding = encoding + return self + + def __str__(self): + return PowerlineRenderBytesResult(self) + + def __getitem__(self, *args): + return PowerlineRenderResult(unicode.__getitem__(self, *args)) + + def __getslice__(self, *args): + return PowerlineRenderResult(unicode.__getslice__(self, *args)) + + @staticmethod + def add(encoding, *args): + return PowerlineRenderResult(''.join(( + arg + if isinstance(arg, unicode) + else arg.decode(encoding) + for arg in args + )), encoding) + + def __add__(self, other): + return self.add(self.encoding, self, other) + + def __radd__(self, other): + return self.add(self.encoding, other, self) + + def encode(self, *args, **kwargs): + return PowerlineRenderBytesResult(unicode.encode(self, *args, **kwargs), args[0]) +else: + PowerlineRenderResult = str + + +def use_powerline_prompt(cls): + '''Decorator that installs powerline prompt to the class + + :param pdb.Pdb cls: + Class that should be decorated. + + :return: + ``cls`` argument or a class derived from it. Latter is used to turn + old-style classes into new-style classes. + ''' + @property + def prompt(self): + try: + powerline = self.powerline + except AttributeError: + powerline = PDBPowerline() + powerline.setup(self) + self.powerline = powerline + return PowerlineRenderResult(powerline.render(side='left')) + + @prompt.setter + def prompt(self, _): + pass + + @prompt.deleter + def prompt(self): + pass + + if not hasattr(cls, '__class__'): + # Old-style class: make it new-style or @property will not work. + old_cls = cls + + class cls(cls, object): + __module__ = cls.__module__ + __doc__ = cls.__doc__ + + cls.__name__ = old_cls.__name__ + + cls.prompt = prompt + + return cls + + +def main(): + '''Run module as a script + + Uses :py:func:`pdb.main` function directly, but prior to that it mocks + :py:class:`pdb.Pdb` class with powerline-specific class instance. + ''' + orig_pdb = pdb.Pdb + + @use_powerline_prompt + class Pdb(pdb.Pdb, object): + def __init__(self): + orig_pdb.__init__(self) + + pdb.Pdb = Pdb + + return pdb.main() |