Guido van Rossum | 63f4cdc | 1992-12-14 14:10:53 +0000 | [diff] [blame] | 1 | #! /usr/local/bin/python |
| 2 | |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 3 | # A STDWIN-based front end for the Python interpreter. |
| 4 | # |
| 5 | # This is useful if you want to avoid console I/O and instead |
| 6 | # use text windows to issue commands to the interpreter. |
| 7 | # |
| 8 | # It supports multiple interpreter windows, each with its own context. |
| 9 | # |
| 10 | # BUGS AND CAVEATS: |
| 11 | # |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 12 | # This was written long ago as a demonstration, and slightly hacked to |
| 13 | # keep it up-to-date, but never as an industry-strength alternative |
| 14 | # interface to Python. It should be rewritten using more classes, and |
| 15 | # merged with something like wdb. |
Guido van Rossum | 63f4cdc | 1992-12-14 14:10:53 +0000 | [diff] [blame] | 16 | # |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 17 | # Although this supports multiple windows, the whole application |
| 18 | # is deaf and dumb when a command is running in one window. |
| 19 | # |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 20 | # Interrupt is (ab)used to signal EOF on input requests. |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 21 | # |
| 22 | # On UNIX (using X11), interrupts typed in the window will not be |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 23 | # seen until the next input or output operation. When you are stuck |
| 24 | # in an infinite loop, try typing ^C in the shell window where you |
| 25 | # started this interpreter. (On the Mac, interrupts work normally.) |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 26 | |
| 27 | |
| 28 | import sys |
| 29 | import builtin |
| 30 | import stdwin |
| 31 | from stdwinevents import * |
| 32 | import rand |
| 33 | import mainloop |
Guido van Rossum | 4ea570d | 1992-03-30 11:01:26 +0000 | [diff] [blame] | 34 | import os |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 35 | |
| 36 | |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 37 | # Stack of windows waiting for [raw_]input(). |
| 38 | # Element [0] is the top. |
| 39 | # If there are multiple windows waiting for input, only the |
| 40 | # one on top of the stack can accept input, because the way |
| 41 | # raw_input() is implemented (using recursive mainloop() calls). |
| 42 | # |
| 43 | inputwindows = [] |
| 44 | |
| 45 | |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 46 | # Exception raised when input is available |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 47 | # |
| 48 | InputAvailable = 'input available for raw_input (not an error)' |
| 49 | |
| 50 | |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 51 | # Main program -- create the window and call the mainloop |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 52 | # |
| 53 | def main(): |
| 54 | # Hack so 'import python' won't load another copy |
| 55 | # of this if we were loaded though 'python python.py'. |
| 56 | # (Should really look at sys.argv[0]...) |
| 57 | if 'inputwindows' in dir(sys.modules['__main__']) and \ |
| 58 | sys.modules['__main__'].inputwindows is inputwindows: |
| 59 | sys.modules['python'] = sys.modules['__main__'] |
| 60 | # |
| 61 | win = makewindow() |
| 62 | mainloop.mainloop() |
| 63 | |
| 64 | |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 65 | # Create a new window |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 66 | # |
| 67 | def makewindow(): |
| 68 | # stdwin.setdefscrollbars(0, 1) # Not in Python 0.9.1 |
| 69 | # stdwin.setfont('monaco') # Not on UNIX! and not Python 0.9.1 |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 70 | # width, height = stdwin.textwidth('in')*40, stdwin.lineheight()*24 |
| 71 | # stdwin.setdefwinsize(width, height) |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 72 | win = stdwin.open('Python interpreter ready') |
| 73 | win.editor = win.textcreate((0,0), win.getwinsize()) |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 74 | win.globals = {} # Dictionary for user's globals |
| 75 | win.command = '' # Partially read command |
| 76 | win.busy = 0 # Ready to accept a command |
| 77 | win.auto = 1 # [CR] executes command |
| 78 | win.insertOutput = 1 # Insert output at focus |
| 79 | win.insertError = 1 # Insert error output at focus |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 80 | win.setwincursor('ibeam') |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 81 | win.filename = '' # Empty if no file for this window |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 82 | makefilemenu(win) |
| 83 | makeeditmenu(win) |
| 84 | win.dispatch = pdispatch # Event dispatch function |
| 85 | mainloop.register(win) |
| 86 | return win |
| 87 | |
| 88 | |
| 89 | # Make a 'File' menu |
| 90 | # |
| 91 | def makefilemenu(win): |
| 92 | win.filemenu = mp = win.menucreate('File') |
| 93 | mp.callback = [] |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 94 | additem(mp, 'New', 'N', do_new) |
| 95 | additem(mp, 'Open...', 'O', do_open) |
| 96 | additem(mp, '', '', None) |
| 97 | additem(mp, 'Close', 'W', do_close) |
| 98 | additem(mp, 'Save', 'S', do_save) |
| 99 | additem(mp, 'Save as...', '', do_saveas) |
| 100 | additem(mp, '', '', None) |
| 101 | additem(mp, 'Quit', 'Q', do_quit) |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 102 | |
| 103 | |
| 104 | # Make an 'Edit' menu |
| 105 | # |
| 106 | def makeeditmenu(win): |
| 107 | win.editmenu = mp = win.menucreate('Edit') |
| 108 | mp.callback = [] |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 109 | additem(mp, 'Cut', 'X', do_cut) |
| 110 | additem(mp, 'Copy', 'C', do_copy) |
| 111 | additem(mp, 'Paste', 'V', do_paste) |
| 112 | additem(mp, 'Clear', '', do_clear) |
| 113 | additem(mp, '', '', None) |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 114 | win.iauto = len(mp.callback) |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 115 | additem(mp, 'Autoexecute', '', do_auto) |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 116 | mp.check(win.iauto, win.auto) |
| 117 | win.insertOutputNum = len(mp.callback) |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 118 | additem(mp, 'Insert Output', '', do_insertOutputOption) |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 119 | win.insertErrorNum = len(mp.callback) |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 120 | additem(mp, 'Insert Error', '', do_insertErrorOption) |
| 121 | additem(mp, 'Exec', '\r', do_exec) |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 122 | |
| 123 | |
| 124 | # Helper to add a menu item and callback function |
| 125 | # |
| 126 | def additem(mp, text, shortcut, handler): |
| 127 | if shortcut: |
| 128 | mp.additem(text, shortcut) |
| 129 | else: |
| 130 | mp.additem(text) |
| 131 | mp.callback.append(handler) |
| 132 | |
| 133 | |
| 134 | # Dispatch a single event to the interpreter. |
| 135 | # Resize events cause a resize of the editor. |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 136 | # Some events are treated specially. |
| 137 | # Most other events are passed directly to the editor. |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 138 | # |
| 139 | def pdispatch(event): |
| 140 | type, win, detail = event |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 141 | if not win: |
| 142 | win = stdwin.getactive() |
| 143 | if not win: return |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 144 | if type == WE_CLOSE: |
| 145 | do_close(win) |
Guido van Rossum | 63f4cdc | 1992-12-14 14:10:53 +0000 | [diff] [blame] | 146 | return |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 147 | elif type == WE_SIZE: |
| 148 | win.editor.move((0, 0), win.getwinsize()) |
| 149 | elif type == WE_COMMAND and detail == WC_RETURN: |
| 150 | if win.auto: |
| 151 | do_exec(win) |
| 152 | else: |
| 153 | void = win.editor.event(event) |
| 154 | elif type == WE_COMMAND and detail == WC_CANCEL: |
| 155 | if win.busy: |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 156 | raise KeyboardInterrupt |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 157 | else: |
| 158 | win.command = '' |
| 159 | settitle(win) |
| 160 | elif type == WE_MENU: |
| 161 | mp, item = detail |
| 162 | mp.callback[item](win) |
| 163 | else: |
| 164 | void = win.editor.event(event) |
Guido van Rossum | 63f4cdc | 1992-12-14 14:10:53 +0000 | [diff] [blame] | 165 | if win in mainloop.windows: |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 166 | # May have been deleted by close... |
| 167 | win.setdocsize(0, win.editor.getrect()[1][1]) |
| 168 | if type in (WE_CHAR, WE_COMMAND): |
| 169 | win.editor.setfocus(win.editor.getfocus()) |
| 170 | |
| 171 | |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 172 | # Helper to set the title of the window |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 173 | # |
| 174 | def settitle(win): |
| 175 | if win.filename == '': |
| 176 | win.settitle('Python interpreter ready') |
| 177 | else: |
| 178 | win.settitle(win.filename) |
| 179 | |
| 180 | |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 181 | # Helper to replace the text of the focus |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 182 | # |
| 183 | def replace(win, text): |
| 184 | win.editor.replace(text) |
| 185 | # Resize the window to display the text |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 186 | win.setdocsize(0, win.editor.getrect()[1][1]) # update the size before |
| 187 | win.editor.setfocus(win.editor.getfocus()) # move focus to the change |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 188 | |
| 189 | |
| 190 | # File menu handlers |
| 191 | # |
| 192 | def do_new(win): |
| 193 | win = makewindow() |
| 194 | # |
| 195 | def do_open(win): |
| 196 | try: |
| 197 | filename = stdwin.askfile('Open file', '', 0) |
| 198 | win = makewindow() |
| 199 | win.filename = filename |
Guido van Rossum | 4ea570d | 1992-03-30 11:01:26 +0000 | [diff] [blame] | 200 | win.editor.replace(open(filename, 'r').read()) |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 201 | win.editor.setfocus(0, 0) |
| 202 | win.settitle(win.filename) |
| 203 | # |
| 204 | except KeyboardInterrupt: |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 205 | pass # Don't give an error on cancel |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 206 | # |
| 207 | def do_save(win): |
| 208 | try: |
| 209 | if win.filename == '': |
| 210 | win.filename = stdwin.askfile('Open file', '', 1) |
| 211 | f = open(win.filename, 'w') |
| 212 | f.write(win.editor.gettext()) |
| 213 | # |
| 214 | except KeyboardInterrupt: |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 215 | pass # Don't give an error on cancel |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 216 | |
| 217 | def do_saveas(win): |
| 218 | currentFilename = win.filename |
| 219 | win.filename = '' |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 220 | do_save(win) # Use do_save with empty filename |
| 221 | if win.filename == '': # Restore the name if do_save did not set it |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 222 | win.filename = currentFilename |
| 223 | # |
| 224 | def do_close(win): |
| 225 | if win.busy: |
| 226 | stdwin.message('Can\'t close busy window') |
| 227 | return # need to fail if quitting?? |
| 228 | win.editor = None # Break circular reference |
| 229 | #del win.editmenu # What about the filemenu?? |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 230 | mainloop.unregister(win) |
Guido van Rossum | 63f4cdc | 1992-12-14 14:10:53 +0000 | [diff] [blame] | 231 | win.close() |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 232 | # |
| 233 | def do_quit(win): |
| 234 | # Call win.dispatch instead of do_close because there |
| 235 | # may be 'alien' windows in the list. |
Guido van Rossum | 63f4cdc | 1992-12-14 14:10:53 +0000 | [diff] [blame] | 236 | for win in mainloop.windows[:]: |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 237 | mainloop.dispatch((WE_CLOSE, win, None)) |
| 238 | # need to catch failed close |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 239 | |
| 240 | |
| 241 | # Edit menu handlers |
| 242 | # |
| 243 | def do_cut(win): |
| 244 | text = win.editor.getfocustext() |
| 245 | if not text: |
| 246 | stdwin.fleep() |
| 247 | return |
| 248 | stdwin.setcutbuffer(0, text) |
| 249 | replace(win, '') |
| 250 | # |
| 251 | def do_copy(win): |
| 252 | text = win.editor.getfocustext() |
| 253 | if not text: |
| 254 | stdwin.fleep() |
| 255 | return |
| 256 | stdwin.setcutbuffer(0, text) |
| 257 | # |
| 258 | def do_paste(win): |
| 259 | text = stdwin.getcutbuffer(0) |
| 260 | if not text: |
| 261 | stdwin.fleep() |
| 262 | return |
| 263 | replace(win, text) |
| 264 | # |
| 265 | def do_clear(win): |
| 266 | replace(win, '') |
| 267 | |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 268 | |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 269 | # These would be better in a preferences dialog: |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 270 | # |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 271 | def do_auto(win): |
| 272 | win.auto = (not win.auto) |
| 273 | win.editmenu.check(win.iauto, win.auto) |
| 274 | # |
| 275 | def do_insertOutputOption(win): |
| 276 | win.insertOutput = (not win.insertOutput) |
| 277 | title = ['Append Output', 'Insert Output'][win.insertOutput] |
| 278 | win.editmenu.setitem(win.insertOutputNum, title) |
| 279 | # |
| 280 | def do_insertErrorOption(win): |
| 281 | win.insertError = (not win.insertError) |
| 282 | title = ['Error Dialog', 'Insert Error'][win.insertError] |
| 283 | win.editmenu.setitem(win.insertErrorNum, title) |
| 284 | |
| 285 | |
| 286 | # Extract a command from the editor and execute it, or pass input to |
| 287 | # an interpreter waiting for it. |
| 288 | # Incomplete commands are merely placed in the window's command buffer. |
| 289 | # All exceptions occurring during the execution are caught and reported. |
| 290 | # (Tracebacks are currently not possible, as the interpreter does not |
| 291 | # save the traceback pointer until it reaches its outermost level.) |
| 292 | # |
| 293 | def do_exec(win): |
| 294 | if win.busy: |
| 295 | if win not in inputwindows: |
| 296 | stdwin.message('Can\'t run recursive commands') |
| 297 | return |
| 298 | if win <> inputwindows[0]: |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 299 | stdwin.message('Please complete recursive input first') |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 300 | return |
| 301 | # |
| 302 | # Set text to the string to execute. |
| 303 | a, b = win.editor.getfocus() |
| 304 | alltext = win.editor.gettext() |
| 305 | n = len(alltext) |
| 306 | if a == b: |
| 307 | # There is no selected text, just an insert point; |
| 308 | # so execute the current line. |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 309 | while 0 < a and alltext[a-1] <> '\n': # Find beginning of line |
| 310 | a = a-1 |
| 311 | while b < n and alltext[b] <> '\n': # Find end of line after b |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 312 | b = b+1 |
| 313 | text = alltext[a:b] + '\n' |
| 314 | else: |
| 315 | # Execute exactly the selected text. |
| 316 | text = win.editor.getfocustext() |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 317 | if text[-1:] <> '\n': # Make sure text ends with \n |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 318 | text = text + '\n' |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 319 | while b < n and alltext[b] <> '\n': # Find end of line after b |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 320 | b = b+1 |
| 321 | # |
| 322 | # Set the focus to expect the output, since there is always something. |
| 323 | # Output will be inserted at end of line after current focus, |
| 324 | # or appended to the end of the text. |
| 325 | b = [n, b][win.insertOutput] |
| 326 | win.editor.setfocus(b, b) |
| 327 | # |
| 328 | # Make sure there is a preceeding newline. |
| 329 | if alltext[b-1:b] <> '\n': |
| 330 | win.editor.replace('\n') |
| 331 | # |
| 332 | # |
| 333 | if win.busy: |
| 334 | # Send it to raw_input() below |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 335 | raise InputAvailable, text |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 336 | # |
| 337 | # Like the real Python interpreter, we want to execute |
| 338 | # single-line commands immediately, but save multi-line |
| 339 | # commands until they are terminated by a blank line. |
| 340 | # Unlike the real Python interpreter, we don't do any syntax |
| 341 | # checking while saving up parts of a multi-line command. |
| 342 | # |
| 343 | # The current heuristic to determine whether a command is |
| 344 | # the first line of a multi-line command simply checks whether |
| 345 | # the command ends in a colon (followed by a newline). |
| 346 | # This is not very robust (comments and continuations will |
| 347 | # confuse it), but it is usable, and simple to implement. |
| 348 | # (It even has the advantage that single-line loops etc. |
| 349 | # don't need te be terminated by a blank line.) |
| 350 | # |
| 351 | if win.command: |
| 352 | # Already continuing |
| 353 | win.command = win.command + text |
| 354 | if win.command[-2:] <> '\n\n': |
| 355 | win.settitle('Unfinished command...') |
| 356 | return # Need more... |
| 357 | else: |
| 358 | # New command |
| 359 | win.command = text |
| 360 | if text[-2:] == ':\n': |
| 361 | win.settitle('Unfinished command...') |
| 362 | return |
| 363 | command = win.command |
| 364 | win.command = '' |
| 365 | win.settitle('Executing command...') |
| 366 | # |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 367 | # Some hacks: |
| 368 | # - The standard files are replaced by an IOWindow instance. |
| 369 | # - A 2nd argument to exec() is used to specify the directory |
| 370 | # holding the user's global variables. (If this wasn't done, |
| 371 | # the exec would be executed in the current local environment, |
| 372 | # and the user's assignments to globals would be lost...) |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 373 | # |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 374 | save_stdin = sys.stdin |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 375 | save_stdout = sys.stdout |
| 376 | save_stderr = sys.stderr |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 377 | try: |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 378 | sys.stdin = sys.stdout = sys.stderr = IOWindow().init(win) |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 379 | win.busy = 1 |
| 380 | try: |
| 381 | exec(command, win.globals) |
| 382 | except KeyboardInterrupt: |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 383 | print '[Interrupt]' |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 384 | except: |
| 385 | msg = sys.exc_type |
| 386 | if sys.exc_value <> None: |
| 387 | msg = msg + ': ' + `sys.exc_value` |
| 388 | if win.insertError: |
| 389 | stdwin.fleep() |
| 390 | replace(win, msg + '\n') |
| 391 | else: |
| 392 | win.settitle('Unhandled exception') |
| 393 | stdwin.message(msg) |
| 394 | finally: |
| 395 | # Restore redirected I/O in *all* cases |
| 396 | win.busy = 0 |
| 397 | sys.stderr = save_stderr |
| 398 | sys.stdout = save_stdout |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 399 | sys.stdin = save_stdin |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 400 | settitle(win) |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 401 | |
| 402 | |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 403 | # Class emulating file I/O from/to a window |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 404 | # |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 405 | class IOWindow: |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 406 | # |
| 407 | def init(self, win): |
| 408 | self.win = win |
| 409 | return self |
| 410 | # |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 411 | def readline(self, *unused_args): |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 412 | n = len(inputwindows) |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 413 | save_title = self.win.gettitle() |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 414 | title = n*'(' + 'Requesting input...' + ')'*n |
| 415 | self.win.settitle(title) |
| 416 | inputwindows.insert(0, self.win) |
| 417 | try: |
Guido van Rossum | cb4b295 | 1992-05-15 15:40:30 +0000 | [diff] [blame] | 418 | try: |
| 419 | mainloop.mainloop() |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 420 | finally: |
| 421 | del inputwindows[0] |
| 422 | self.win.settitle(save_title) |
| 423 | except InputAvailable, val: # See do_exec above |
| 424 | return val |
| 425 | except KeyboardInterrupt: |
| 426 | raise EOFError # Until we have a "send EOF" key |
| 427 | # If we didn't catch InputAvailable, something's wrong... |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 428 | raise EOFError |
| 429 | # |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 430 | def write(self, text): |
| 431 | mainloop.check() |
| 432 | replace(self.win, text) |
| 433 | mainloop.check() |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 434 | |
| 435 | |
| 436 | # Currently unused function to test a command's syntax without executing it |
| 437 | # |
| 438 | def testsyntax(s): |
| 439 | import string |
| 440 | lines = string.splitfields(s, '\n') |
| 441 | for i in range(len(lines)): lines[i] = '\t' + lines[i] |
| 442 | lines.insert(0, 'if 0:') |
| 443 | lines.append('') |
| 444 | exec(string.joinfields(lines, '\n')) |
| 445 | |
| 446 | |
Guido van Rossum | 5dd997c | 1992-12-22 14:34:43 +0000 | [diff] [blame^] | 447 | # Call the main program |
Guido van Rossum | 9cf8f33 | 1992-03-30 10:54:51 +0000 | [diff] [blame] | 448 | # |
| 449 | main() |