# Copyright 2000-2007 Michael Hudson-Doyle # Maciek Fijalkowski # # All Rights Reserved # # # Permission to use, copy, modify, and distribute this software and # its documentation for any purpose is hereby granted without fee, # provided that the above copyright notice appear in all copies and # that both that copyright notice and this permission notice appear in # supporting documentation. # # THE AUTHOR MICHAEL HUDSON DISCLAIMS ALL WARRANTIES WITH REGARD TO # THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, # INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER # RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF # CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """Wedge pyrepl behaviour into cmd.Cmd-derived classes. replize, when given a subclass of cmd.Cmd, returns a class that behaves almost identically to the supplied class, except that it uses pyrepl instead if raw_input. It was designed to let you do this: >>> import pdb >>> from pyrepl import replize >>> pdb.Pdb = replize(pdb.Pdb) which is in fact done by the `pythoni' script that comes with pyrepl.""" from __future__ import nested_scopes from pyrepl import completing_reader as cr, reader, completer from pyrepl.completing_reader import CompletingReader as CR import cmd class CmdReader(CR): def collect_keymap(self): return super(CmdReader, self).collect_keymap() + ( ("\\M-\\n", "invalid-key"), ("\\n", "accept")) CR_init = CR.__init__ def __init__(self, completions): self.CR_init(self) self.completions = completions def get_completions(self, stem): if len(stem) != self.pos: return [] return cr.uniqify([s for s in self.completions if s.startswith(stem)]) def replize(klass, history_across_invocations=1): """Return a subclass of the cmd.Cmd-derived klass that uses pyrepl instead of readline. Raises a ValueError if klass does not derive from cmd.Cmd. The optional history_across_invocations parameter (default 1) controls whether instances of the returned class share histories.""" completions = [s[3:] for s in completer.get_class_members(klass) if s.startswith("do_")] if not issubclass(klass, cmd.Cmd): raise Exception # if klass.cmdloop.im_class is not cmd.Cmd: # print "this may not work" class CmdRepl(klass): k_init = klass.__init__ if history_across_invocations: _CmdRepl__history = [] def __init__(self, *args, **kw): self.k_init(*args, **kw) self.__reader = CmdReader(completions) self.__reader.history = CmdRepl._CmdRepl__history self.__reader.historyi = len(CmdRepl._CmdRepl__history) else: def __init__(self, *args, **kw): self.k_init(*args, **kw) self.__reader = CmdReader(completions) def cmdloop(self, intro=None): self.preloop() if intro is not None: self.intro = intro if self.intro: print self.intro stop = None while not stop: if self.cmdqueue: line = self.cmdqueue[0] del self.cmdqueue[0] else: try: self.__reader.ps1 = self.prompt line = self.__reader.readline() except EOFError: line = "EOF" line = self.precmd(line) stop = self.onecmd(line) stop = self.postcmd(stop, line) self.postloop() CmdRepl.__name__ = "replize(%s.%s)"%(klass.__module__, klass.__name__) return CmdRepl