diff -r 000000000000 -r ca70ae20a155 src/extras/pyrepl/python_reader.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/extras/pyrepl/python_reader.py Tue Feb 16 10:07:05 2010 +0530 @@ -0,0 +1,259 @@ +# Copyright 2000-2004 Michael Hudson mwh@python.net +# +# All Rights Reserved +# +# Portions Copyright (c) 2005 Nokia Corporation +# +# 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. + +# one impressive collections of imports: +from pyrepl.completing_reader import CompletingReader +from pyrepl.historical_reader import HistoricalReader +from pyrepl import completing_reader, reader +from pyrepl import commands, completer +from pyrepl import module_lister +import sys, os, re, code, atexit +import warnings + +HISTORYFILE=u"c:\\pythonhistory.txt" + +try: + import cPickle as pickle +except ImportError: + try: + import pickle + except ImportError: + try: + import dumbpickle as pickle + except ImportError: + print "No pickle module -> command history will not be saved." + pickle=None + +CommandCompiler = code.CommandCompiler + +def eat_it(*args): + """this function eats warnings, if you were wondering""" + pass + +class maybe_accept(commands.Command): + def do(self): + r = self.reader + text = r.get_unicode() + try: + # ooh, look at the hack: + code = r.compiler("#coding:utf-8\n"+text.encode('utf-8')) + except (OverflowError, SyntaxError, ValueError): + self.finish = 1 + else: + if code is None: + r.insert("\n") + else: + self.finish = 1 + +from_line_prog = re.compile( + "^from\s+(?P[A-Za-z_.0-9]*)\s+import\s+(?P[A-Za-z_.0-9]*)") +import_line_prog = re.compile( + "^(?:import|from)\s+(?P[A-Za-z_.0-9]*)\s*$") + +def mk_saver(reader): + def saver(reader=reader): + try: + file = open(HISTORYFILE, "w") + except IOError: + pass + else: + pickle.dump(reader.history, file) + file.close() + return saver + +def prhelp(): + print ''' +This is pyrepl, a simple multiline editor with command history, tab +completion and emacs-like key bindings. + +Most useful commands: +(C-x means Control-x, M-x means Alt-x or Esc x) + + C-p, C-n previous/next history item + C-o accept line and take next line from history + (handy for repeating sequences of commands) + M-r restore line to what it was when retrieved + from history + C-r, C-s incremental search back/forward + C-a, C-e beginning/end of line + M-f, M-b next/previous word + C-k cut to end of line + C-w, M-d cut word to left/right of cursor + C-y paste + M-y paste older (use after C-y) + M-return insert literal Return + C-d delete character/quit interpreter + C-xC-s save history to file (also saved on graceful exit) + tab complete item (attribute, method, variable...) +''' + +class PythonicReader(CompletingReader, HistoricalReader): + def collect_keymap(self): + return super(PythonicReader, self).collect_keymap() + ( + (r'\r', 'maybe-accept'), + (r'\M-\r', 'insert-nl'), + (r'\n', 'maybe-accept'), + (r'\M-\n', 'insert-nl')) + + def __init__(self, console, locals, + compiler=None): + super(PythonicReader, self).__init__(console) + self.completer = completer.Completer(locals) + st = self.syntax_table + for c in "._0123456789": + st[c] = reader.SYNTAX_WORD + self.locals = locals + self.locals['prhelp']=prhelp + if compiler is None: + self.compiler = CommandCompiler() + else: + self.compiler = compiler + try: + file = open(HISTORYFILE) + except IOError: + pass + else: + try: + self.history = pickle.load(file) + except: + self.history = [] + self.historyi = len(self.history) + file.close() + self.save_history=mk_saver(self) + atexit.register(self.save_history) + for c in [maybe_accept]: + self.commands[c.__name__] = c + self.commands[c.__name__.replace('_', '-')] = c + + def get_completions(self, stem): + b = self.get_unicode() + m = import_line_prog.match(b) + if m: + mod = m.group("mod") + try: + return module_lister.find_modules(mod) + except ImportError: + pass + m = from_line_prog.match(b) + if m: + mod, name = m.group("mod", "name") + try: + l = module_lister._packages[mod] + except KeyError: + try: + mod = __import__(mod, self.locals, self.locals, ['']) + return [x for x in dir(mod) if x.startswith(name)] + except ImportError: + pass + else: + return [x[len(mod) + 1:] + for x in l if x.startswith(mod + '.' + name)] + try: + l = completing_reader.uniqify(self.completer.complete(stem)) + return l + except (NameError, AttributeError): + return [] + +class ReaderConsole(code.InteractiveInterpreter): + II_init = code.InteractiveInterpreter.__init__ + def __init__(self, console, locals=None): + self.II_init(locals) + self.compiler = CommandCompiler() + self.compile = self.compiler.compiler + self.reader = PythonicReader(console, locals, self.compiler) + self.locals['Reader'] = self.reader + + def run_user_init_file(self): + for key in "PYREPLSTARTUP", "PYTHONSTARTUP": + initfile = os.environ.get(key) + if initfile is not None and os.path.exists(initfile): + break + else: + return + try: + execfile(initfile, self.locals, self.locals) + except: + etype, value, tb = sys.exc_info() + import traceback + traceback.print_exception(etype, value, tb.tb_next) + + def execute(self, text): + try: + # ooh, look at the hack: + code = self.compile("# coding:utf8\n"+text.encode('utf-8'), + '', 'single') + except (OverflowError, SyntaxError, ValueError): + self.showsyntaxerror("") + else: + self.runcode(code) + sys.stdout.flush() + + def interact(self): + while 1: + try: + try: # catches EOFError's and KeyboardInterrupts during execution + try: # catches KeyboardInterrupts during editing + try: # warning saver + # can't have warnings spewed onto terminal + sv = warnings.showwarning + warnings.showwarning = eat_it + l = unicode(self.reader.readline(), 'utf-8') + finally: + warnings.showwarning = sv + except KeyboardInterrupt: + print "KeyboardInterrupt" + else: + if l: + self.execute(l) + except EOFError: + break + except KeyboardInterrupt: + continue + finally: + self.reader.save_history() + + def prepare(self): + self.sv_sw = warnings.showwarning + warnings.showwarning = eat_it + self.reader.prepare() + self.reader.refresh() # we want :after methods... + + def restore(self): + self.reader.restore() + warnings.showwarning = self.sv_sw + + def handle1(self, block=1): + try: + r = 1 + r = self.reader.handle1(block) + except KeyboardInterrupt: + self.restore() + print "KeyboardInterrupt" + self.prepare() + else: + if self.reader.finished: + text = self.reader.get_unicode() + self.restore() + if text: + self.execute(text) + self.prepare() + return r + +