0
|
1 |
# Copyright 2000-2004 Michael Hudson mwh@python.net
|
|
2 |
#
|
|
3 |
# All Rights Reserved
|
|
4 |
#
|
|
5 |
# Portions Copyright (c) 2005 Nokia Corporation
|
|
6 |
#
|
|
7 |
# Permission to use, copy, modify, and distribute this software and
|
|
8 |
# its documentation for any purpose is hereby granted without fee,
|
|
9 |
# provided that the above copyright notice appear in all copies and
|
|
10 |
# that both that copyright notice and this permission notice appear in
|
|
11 |
# supporting documentation.
|
|
12 |
#
|
|
13 |
# THE AUTHOR MICHAEL HUDSON DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
|
14 |
# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
15 |
# AND FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
|
|
16 |
# INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
|
17 |
# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
|
18 |
# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
19 |
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
20 |
|
|
21 |
# one impressive collections of imports:
|
|
22 |
from pyrepl.completing_reader import CompletingReader
|
|
23 |
from pyrepl.historical_reader import HistoricalReader
|
|
24 |
from pyrepl import completing_reader, reader
|
|
25 |
from pyrepl import commands, completer
|
|
26 |
from pyrepl import module_lister
|
|
27 |
import sys, os, re, code, atexit
|
|
28 |
import warnings
|
|
29 |
|
|
30 |
HISTORYFILE=u"c:\\pythonhistory.txt"
|
|
31 |
|
|
32 |
try:
|
|
33 |
import cPickle as pickle
|
|
34 |
except ImportError:
|
|
35 |
try:
|
|
36 |
import pickle
|
|
37 |
except ImportError:
|
|
38 |
try:
|
|
39 |
import dumbpickle as pickle
|
|
40 |
except ImportError:
|
|
41 |
print "No pickle module -> command history will not be saved."
|
|
42 |
pickle=None
|
|
43 |
|
|
44 |
CommandCompiler = code.CommandCompiler
|
|
45 |
|
|
46 |
def eat_it(*args):
|
|
47 |
"""this function eats warnings, if you were wondering"""
|
|
48 |
pass
|
|
49 |
|
|
50 |
class maybe_accept(commands.Command):
|
|
51 |
def do(self):
|
|
52 |
r = self.reader
|
|
53 |
text = r.get_unicode()
|
|
54 |
try:
|
|
55 |
# ooh, look at the hack:
|
|
56 |
code = r.compiler("#coding:utf-8\n"+text.encode('utf-8'))
|
|
57 |
except (OverflowError, SyntaxError, ValueError):
|
|
58 |
self.finish = 1
|
|
59 |
else:
|
|
60 |
if code is None:
|
|
61 |
r.insert("\n")
|
|
62 |
else:
|
|
63 |
self.finish = 1
|
|
64 |
|
|
65 |
from_line_prog = re.compile(
|
|
66 |
"^from\s+(?P<mod>[A-Za-z_.0-9]*)\s+import\s+(?P<name>[A-Za-z_.0-9]*)")
|
|
67 |
import_line_prog = re.compile(
|
|
68 |
"^(?:import|from)\s+(?P<mod>[A-Za-z_.0-9]*)\s*$")
|
|
69 |
|
|
70 |
def mk_saver(reader):
|
|
71 |
def saver(reader=reader):
|
|
72 |
try:
|
|
73 |
file = open(HISTORYFILE, "w")
|
|
74 |
except IOError:
|
|
75 |
pass
|
|
76 |
else:
|
|
77 |
pickle.dump(reader.history, file)
|
|
78 |
file.close()
|
|
79 |
return saver
|
|
80 |
|
|
81 |
def prhelp():
|
|
82 |
print '''
|
|
83 |
This is pyrepl, a simple multiline editor with command history, tab
|
|
84 |
completion and emacs-like key bindings.
|
|
85 |
|
|
86 |
Most useful commands:
|
|
87 |
(C-x means Control-x, M-x means Alt-x or Esc x)
|
|
88 |
|
|
89 |
C-p, C-n previous/next history item
|
|
90 |
C-o accept line and take next line from history
|
|
91 |
(handy for repeating sequences of commands)
|
|
92 |
M-r restore line to what it was when retrieved
|
|
93 |
from history
|
|
94 |
C-r, C-s incremental search back/forward
|
|
95 |
C-a, C-e beginning/end of line
|
|
96 |
M-f, M-b next/previous word
|
|
97 |
C-k cut to end of line
|
|
98 |
C-w, M-d cut word to left/right of cursor
|
|
99 |
C-y paste
|
|
100 |
M-y paste older (use after C-y)
|
|
101 |
M-return insert literal Return
|
|
102 |
C-d delete character/quit interpreter
|
|
103 |
C-xC-s save history to file (also saved on graceful exit)
|
|
104 |
tab complete item (attribute, method, variable...)
|
|
105 |
'''
|
|
106 |
|
|
107 |
class PythonicReader(CompletingReader, HistoricalReader):
|
|
108 |
def collect_keymap(self):
|
|
109 |
return super(PythonicReader, self).collect_keymap() + (
|
|
110 |
(r'\r', 'maybe-accept'),
|
|
111 |
(r'\M-\r', 'insert-nl'),
|
|
112 |
(r'\n', 'maybe-accept'),
|
|
113 |
(r'\M-\n', 'insert-nl'))
|
|
114 |
|
|
115 |
def __init__(self, console, locals,
|
|
116 |
compiler=None):
|
|
117 |
super(PythonicReader, self).__init__(console)
|
|
118 |
self.completer = completer.Completer(locals)
|
|
119 |
st = self.syntax_table
|
|
120 |
for c in "._0123456789":
|
|
121 |
st[c] = reader.SYNTAX_WORD
|
|
122 |
self.locals = locals
|
|
123 |
self.locals['prhelp']=prhelp
|
|
124 |
if compiler is None:
|
|
125 |
self.compiler = CommandCompiler()
|
|
126 |
else:
|
|
127 |
self.compiler = compiler
|
|
128 |
try:
|
|
129 |
file = open(HISTORYFILE)
|
|
130 |
except IOError:
|
|
131 |
pass
|
|
132 |
else:
|
|
133 |
try:
|
|
134 |
self.history = pickle.load(file)
|
|
135 |
except:
|
|
136 |
self.history = []
|
|
137 |
self.historyi = len(self.history)
|
|
138 |
file.close()
|
|
139 |
self.save_history=mk_saver(self)
|
|
140 |
atexit.register(self.save_history)
|
|
141 |
for c in [maybe_accept]:
|
|
142 |
self.commands[c.__name__] = c
|
|
143 |
self.commands[c.__name__.replace('_', '-')] = c
|
|
144 |
|
|
145 |
def get_completions(self, stem):
|
|
146 |
b = self.get_unicode()
|
|
147 |
m = import_line_prog.match(b)
|
|
148 |
if m:
|
|
149 |
mod = m.group("mod")
|
|
150 |
try:
|
|
151 |
return module_lister.find_modules(mod)
|
|
152 |
except ImportError:
|
|
153 |
pass
|
|
154 |
m = from_line_prog.match(b)
|
|
155 |
if m:
|
|
156 |
mod, name = m.group("mod", "name")
|
|
157 |
try:
|
|
158 |
l = module_lister._packages[mod]
|
|
159 |
except KeyError:
|
|
160 |
try:
|
|
161 |
mod = __import__(mod, self.locals, self.locals, [''])
|
|
162 |
return [x for x in dir(mod) if x.startswith(name)]
|
|
163 |
except ImportError:
|
|
164 |
pass
|
|
165 |
else:
|
|
166 |
return [x[len(mod) + 1:]
|
|
167 |
for x in l if x.startswith(mod + '.' + name)]
|
|
168 |
try:
|
|
169 |
l = completing_reader.uniqify(self.completer.complete(stem))
|
|
170 |
return l
|
|
171 |
except (NameError, AttributeError):
|
|
172 |
return []
|
|
173 |
|
|
174 |
class ReaderConsole(code.InteractiveInterpreter):
|
|
175 |
II_init = code.InteractiveInterpreter.__init__
|
|
176 |
def __init__(self, console, locals=None):
|
|
177 |
self.II_init(locals)
|
|
178 |
self.compiler = CommandCompiler()
|
|
179 |
self.compile = self.compiler.compiler
|
|
180 |
self.reader = PythonicReader(console, locals, self.compiler)
|
|
181 |
self.locals['Reader'] = self.reader
|
|
182 |
|
|
183 |
def run_user_init_file(self):
|
|
184 |
for key in "PYREPLSTARTUP", "PYTHONSTARTUP":
|
|
185 |
initfile = os.environ.get(key)
|
|
186 |
if initfile is not None and os.path.exists(initfile):
|
|
187 |
break
|
|
188 |
else:
|
|
189 |
return
|
|
190 |
try:
|
|
191 |
execfile(initfile, self.locals, self.locals)
|
|
192 |
except:
|
|
193 |
etype, value, tb = sys.exc_info()
|
|
194 |
import traceback
|
|
195 |
traceback.print_exception(etype, value, tb.tb_next)
|
|
196 |
|
|
197 |
def execute(self, text):
|
|
198 |
try:
|
|
199 |
# ooh, look at the hack:
|
|
200 |
code = self.compile("# coding:utf8\n"+text.encode('utf-8'),
|
|
201 |
'<input>', 'single')
|
|
202 |
except (OverflowError, SyntaxError, ValueError):
|
|
203 |
self.showsyntaxerror("<input>")
|
|
204 |
else:
|
|
205 |
self.runcode(code)
|
|
206 |
sys.stdout.flush()
|
|
207 |
|
|
208 |
def interact(self):
|
|
209 |
while 1:
|
|
210 |
try:
|
|
211 |
try: # catches EOFError's and KeyboardInterrupts during execution
|
|
212 |
try: # catches KeyboardInterrupts during editing
|
|
213 |
try: # warning saver
|
|
214 |
# can't have warnings spewed onto terminal
|
|
215 |
sv = warnings.showwarning
|
|
216 |
warnings.showwarning = eat_it
|
|
217 |
l = unicode(self.reader.readline(), 'utf-8')
|
|
218 |
finally:
|
|
219 |
warnings.showwarning = sv
|
|
220 |
except KeyboardInterrupt:
|
|
221 |
print "KeyboardInterrupt"
|
|
222 |
else:
|
|
223 |
if l:
|
|
224 |
self.execute(l)
|
|
225 |
except EOFError:
|
|
226 |
break
|
|
227 |
except KeyboardInterrupt:
|
|
228 |
continue
|
|
229 |
finally:
|
|
230 |
self.reader.save_history()
|
|
231 |
|
|
232 |
def prepare(self):
|
|
233 |
self.sv_sw = warnings.showwarning
|
|
234 |
warnings.showwarning = eat_it
|
|
235 |
self.reader.prepare()
|
|
236 |
self.reader.refresh() # we want :after methods...
|
|
237 |
|
|
238 |
def restore(self):
|
|
239 |
self.reader.restore()
|
|
240 |
warnings.showwarning = self.sv_sw
|
|
241 |
|
|
242 |
def handle1(self, block=1):
|
|
243 |
try:
|
|
244 |
r = 1
|
|
245 |
r = self.reader.handle1(block)
|
|
246 |
except KeyboardInterrupt:
|
|
247 |
self.restore()
|
|
248 |
print "KeyboardInterrupt"
|
|
249 |
self.prepare()
|
|
250 |
else:
|
|
251 |
if self.reader.finished:
|
|
252 |
text = self.reader.get_unicode()
|
|
253 |
self.restore()
|
|
254 |
if text:
|
|
255 |
self.execute(text)
|
|
256 |
self.prepare()
|
|
257 |
return r
|
|
258 |
|
|
259 |
|