PageRenderTime 58ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/lib-python/2.7/idlelib/PyShell.py

https://bitbucket.org/varialus/jyjy
Python | 1447 lines | 1325 code | 55 blank | 67 comment | 89 complexity | 25df253b8a1071b6e7f3f4510f333ee3 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. #! /usr/bin/env python
  2. import os
  3. import os.path
  4. import sys
  5. import string
  6. import getopt
  7. import re
  8. import socket
  9. import time
  10. import threading
  11. import traceback
  12. import types
  13. import linecache
  14. from code import InteractiveInterpreter
  15. try:
  16. from Tkinter import *
  17. except ImportError:
  18. print>>sys.__stderr__, "** IDLE can't import Tkinter. " \
  19. "Your Python may not be configured for Tk. **"
  20. sys.exit(1)
  21. import tkMessageBox
  22. from idlelib.EditorWindow import EditorWindow, fixwordbreaks
  23. from idlelib.FileList import FileList
  24. from idlelib.ColorDelegator import ColorDelegator
  25. from idlelib.UndoDelegator import UndoDelegator
  26. from idlelib.OutputWindow import OutputWindow
  27. from idlelib.configHandler import idleConf
  28. from idlelib import idlever
  29. from idlelib import rpc
  30. from idlelib import Debugger
  31. from idlelib import RemoteDebugger
  32. from idlelib import macosxSupport
  33. IDENTCHARS = string.ascii_letters + string.digits + "_"
  34. HOST = '127.0.0.1' # python execution server on localhost loopback
  35. PORT = 0 # someday pass in host, port for remote debug capability
  36. try:
  37. from signal import SIGTERM
  38. except ImportError:
  39. SIGTERM = 15
  40. # Override warnings module to write to warning_stream. Initialize to send IDLE
  41. # internal warnings to the console. ScriptBinding.check_syntax() will
  42. # temporarily redirect the stream to the shell window to display warnings when
  43. # checking user's code.
  44. global warning_stream
  45. warning_stream = sys.__stderr__
  46. try:
  47. import warnings
  48. except ImportError:
  49. pass
  50. else:
  51. def idle_showwarning(message, category, filename, lineno,
  52. file=None, line=None):
  53. if file is None:
  54. file = warning_stream
  55. try:
  56. file.write(warnings.formatwarning(message, category, filename,
  57. lineno, file=file, line=line))
  58. except IOError:
  59. pass ## file (probably __stderr__) is invalid, warning dropped.
  60. warnings.showwarning = idle_showwarning
  61. def idle_formatwarning(message, category, filename, lineno, line=None):
  62. """Format warnings the IDLE way"""
  63. s = "\nWarning (from warnings module):\n"
  64. s += ' File \"%s\", line %s\n' % (filename, lineno)
  65. if line is None:
  66. line = linecache.getline(filename, lineno)
  67. line = line.strip()
  68. if line:
  69. s += " %s\n" % line
  70. s += "%s: %s\n>>> " % (category.__name__, message)
  71. return s
  72. warnings.formatwarning = idle_formatwarning
  73. def extended_linecache_checkcache(filename=None,
  74. orig_checkcache=linecache.checkcache):
  75. """Extend linecache.checkcache to preserve the <pyshell#...> entries
  76. Rather than repeating the linecache code, patch it to save the
  77. <pyshell#...> entries, call the original linecache.checkcache()
  78. (skipping them), and then restore the saved entries.
  79. orig_checkcache is bound at definition time to the original
  80. method, allowing it to be patched.
  81. """
  82. cache = linecache.cache
  83. save = {}
  84. for key in list(cache):
  85. if key[:1] + key[-1:] == '<>':
  86. save[key] = cache.pop(key)
  87. orig_checkcache(filename)
  88. cache.update(save)
  89. # Patch linecache.checkcache():
  90. linecache.checkcache = extended_linecache_checkcache
  91. class PyShellEditorWindow(EditorWindow):
  92. "Regular text edit window in IDLE, supports breakpoints"
  93. def __init__(self, *args):
  94. self.breakpoints = []
  95. EditorWindow.__init__(self, *args)
  96. self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
  97. self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
  98. self.text.bind("<<open-python-shell>>", self.flist.open_shell)
  99. self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
  100. 'breakpoints.lst')
  101. # whenever a file is changed, restore breakpoints
  102. if self.io.filename: self.restore_file_breaks()
  103. def filename_changed_hook(old_hook=self.io.filename_change_hook,
  104. self=self):
  105. self.restore_file_breaks()
  106. old_hook()
  107. self.io.set_filename_change_hook(filename_changed_hook)
  108. rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
  109. ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
  110. def set_breakpoint(self, lineno):
  111. text = self.text
  112. filename = self.io.filename
  113. text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
  114. try:
  115. i = self.breakpoints.index(lineno)
  116. except ValueError: # only add if missing, i.e. do once
  117. self.breakpoints.append(lineno)
  118. try: # update the subprocess debugger
  119. debug = self.flist.pyshell.interp.debugger
  120. debug.set_breakpoint_here(filename, lineno)
  121. except: # but debugger may not be active right now....
  122. pass
  123. def set_breakpoint_here(self, event=None):
  124. text = self.text
  125. filename = self.io.filename
  126. if not filename:
  127. text.bell()
  128. return
  129. lineno = int(float(text.index("insert")))
  130. self.set_breakpoint(lineno)
  131. def clear_breakpoint_here(self, event=None):
  132. text = self.text
  133. filename = self.io.filename
  134. if not filename:
  135. text.bell()
  136. return
  137. lineno = int(float(text.index("insert")))
  138. try:
  139. self.breakpoints.remove(lineno)
  140. except:
  141. pass
  142. text.tag_remove("BREAK", "insert linestart",\
  143. "insert lineend +1char")
  144. try:
  145. debug = self.flist.pyshell.interp.debugger
  146. debug.clear_breakpoint_here(filename, lineno)
  147. except:
  148. pass
  149. def clear_file_breaks(self):
  150. if self.breakpoints:
  151. text = self.text
  152. filename = self.io.filename
  153. if not filename:
  154. text.bell()
  155. return
  156. self.breakpoints = []
  157. text.tag_remove("BREAK", "1.0", END)
  158. try:
  159. debug = self.flist.pyshell.interp.debugger
  160. debug.clear_file_breaks(filename)
  161. except:
  162. pass
  163. def store_file_breaks(self):
  164. "Save breakpoints when file is saved"
  165. # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
  166. # be run. The breaks are saved at that time. If we introduce
  167. # a temporary file save feature the save breaks functionality
  168. # needs to be re-verified, since the breaks at the time the
  169. # temp file is created may differ from the breaks at the last
  170. # permanent save of the file. Currently, a break introduced
  171. # after a save will be effective, but not persistent.
  172. # This is necessary to keep the saved breaks synched with the
  173. # saved file.
  174. #
  175. # Breakpoints are set as tagged ranges in the text. Certain
  176. # kinds of edits cause these ranges to be deleted: Inserting
  177. # or deleting a line just before a breakpoint, and certain
  178. # deletions prior to a breakpoint. These issues need to be
  179. # investigated and understood. It's not clear if they are
  180. # Tk issues or IDLE issues, or whether they can actually
  181. # be fixed. Since a modified file has to be saved before it is
  182. # run, and since self.breakpoints (from which the subprocess
  183. # debugger is loaded) is updated during the save, the visible
  184. # breaks stay synched with the subprocess even if one of these
  185. # unexpected breakpoint deletions occurs.
  186. breaks = self.breakpoints
  187. filename = self.io.filename
  188. try:
  189. lines = open(self.breakpointPath,"r").readlines()
  190. except IOError:
  191. lines = []
  192. new_file = open(self.breakpointPath,"w")
  193. for line in lines:
  194. if not line.startswith(filename + '='):
  195. new_file.write(line)
  196. self.update_breakpoints()
  197. breaks = self.breakpoints
  198. if breaks:
  199. new_file.write(filename + '=' + str(breaks) + '\n')
  200. new_file.close()
  201. def restore_file_breaks(self):
  202. self.text.update() # this enables setting "BREAK" tags to be visible
  203. filename = self.io.filename
  204. if filename is None:
  205. return
  206. if os.path.isfile(self.breakpointPath):
  207. lines = open(self.breakpointPath,"r").readlines()
  208. for line in lines:
  209. if line.startswith(filename + '='):
  210. breakpoint_linenumbers = eval(line[len(filename)+1:])
  211. for breakpoint_linenumber in breakpoint_linenumbers:
  212. self.set_breakpoint(breakpoint_linenumber)
  213. def update_breakpoints(self):
  214. "Retrieves all the breakpoints in the current window"
  215. text = self.text
  216. ranges = text.tag_ranges("BREAK")
  217. linenumber_list = self.ranges_to_linenumbers(ranges)
  218. self.breakpoints = linenumber_list
  219. def ranges_to_linenumbers(self, ranges):
  220. lines = []
  221. for index in range(0, len(ranges), 2):
  222. lineno = int(float(ranges[index]))
  223. end = int(float(ranges[index+1]))
  224. while lineno < end:
  225. lines.append(lineno)
  226. lineno += 1
  227. return lines
  228. # XXX 13 Dec 2002 KBK Not used currently
  229. # def saved_change_hook(self):
  230. # "Extend base method - clear breaks if module is modified"
  231. # if not self.get_saved():
  232. # self.clear_file_breaks()
  233. # EditorWindow.saved_change_hook(self)
  234. def _close(self):
  235. "Extend base method - clear breaks when module is closed"
  236. self.clear_file_breaks()
  237. EditorWindow._close(self)
  238. class PyShellFileList(FileList):
  239. "Extend base class: IDLE supports a shell and breakpoints"
  240. # override FileList's class variable, instances return PyShellEditorWindow
  241. # instead of EditorWindow when new edit windows are created.
  242. EditorWindow = PyShellEditorWindow
  243. pyshell = None
  244. def open_shell(self, event=None):
  245. if self.pyshell:
  246. self.pyshell.top.wakeup()
  247. else:
  248. self.pyshell = PyShell(self)
  249. if self.pyshell:
  250. if not self.pyshell.begin():
  251. return None
  252. return self.pyshell
  253. class ModifiedColorDelegator(ColorDelegator):
  254. "Extend base class: colorizer for the shell window itself"
  255. def __init__(self):
  256. ColorDelegator.__init__(self)
  257. self.LoadTagDefs()
  258. def recolorize_main(self):
  259. self.tag_remove("TODO", "1.0", "iomark")
  260. self.tag_add("SYNC", "1.0", "iomark")
  261. ColorDelegator.recolorize_main(self)
  262. def LoadTagDefs(self):
  263. ColorDelegator.LoadTagDefs(self)
  264. theme = idleConf.GetOption('main','Theme','name')
  265. self.tagdefs.update({
  266. "stdin": {'background':None,'foreground':None},
  267. "stdout": idleConf.GetHighlight(theme, "stdout"),
  268. "stderr": idleConf.GetHighlight(theme, "stderr"),
  269. "console": idleConf.GetHighlight(theme, "console"),
  270. })
  271. class ModifiedUndoDelegator(UndoDelegator):
  272. "Extend base class: forbid insert/delete before the I/O mark"
  273. def insert(self, index, chars, tags=None):
  274. try:
  275. if self.delegate.compare(index, "<", "iomark"):
  276. self.delegate.bell()
  277. return
  278. except TclError:
  279. pass
  280. UndoDelegator.insert(self, index, chars, tags)
  281. def delete(self, index1, index2=None):
  282. try:
  283. if self.delegate.compare(index1, "<", "iomark"):
  284. self.delegate.bell()
  285. return
  286. except TclError:
  287. pass
  288. UndoDelegator.delete(self, index1, index2)
  289. class MyRPCClient(rpc.RPCClient):
  290. def handle_EOF(self):
  291. "Override the base class - just re-raise EOFError"
  292. raise EOFError
  293. class ModifiedInterpreter(InteractiveInterpreter):
  294. def __init__(self, tkconsole):
  295. self.tkconsole = tkconsole
  296. locals = sys.modules['__main__'].__dict__
  297. InteractiveInterpreter.__init__(self, locals=locals)
  298. self.save_warnings_filters = None
  299. self.restarting = False
  300. self.subprocess_arglist = None
  301. self.port = PORT
  302. rpcclt = None
  303. rpcpid = None
  304. def spawn_subprocess(self):
  305. if self.subprocess_arglist is None:
  306. self.subprocess_arglist = self.build_subprocess_arglist()
  307. args = self.subprocess_arglist
  308. self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
  309. def build_subprocess_arglist(self):
  310. assert (self.port!=0), (
  311. "Socket should have been assigned a port number.")
  312. w = ['-W' + s for s in sys.warnoptions]
  313. if 1/2 > 0: # account for new division
  314. w.append('-Qnew')
  315. # Maybe IDLE is installed and is being accessed via sys.path,
  316. # or maybe it's not installed and the idle.py script is being
  317. # run from the IDLE source directory.
  318. del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
  319. default=False, type='bool')
  320. if __name__ == 'idlelib.PyShell':
  321. command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
  322. else:
  323. command = "__import__('run').main(%r)" % (del_exitf,)
  324. if sys.platform[:3] == 'win' and ' ' in sys.executable:
  325. # handle embedded space in path by quoting the argument
  326. decorated_exec = '"%s"' % sys.executable
  327. else:
  328. decorated_exec = sys.executable
  329. return [decorated_exec] + w + ["-c", command, str(self.port)]
  330. def start_subprocess(self):
  331. addr = (HOST, self.port)
  332. # GUI makes several attempts to acquire socket, listens for connection
  333. for i in range(3):
  334. time.sleep(i)
  335. try:
  336. self.rpcclt = MyRPCClient(addr)
  337. break
  338. except socket.error, err:
  339. pass
  340. else:
  341. self.display_port_binding_error()
  342. return None
  343. # if PORT was 0, system will assign an 'ephemeral' port. Find it out:
  344. self.port = self.rpcclt.listening_sock.getsockname()[1]
  345. # if PORT was not 0, probably working with a remote execution server
  346. if PORT != 0:
  347. # To allow reconnection within the 2MSL wait (cf. Stevens TCP
  348. # V1, 18.6), set SO_REUSEADDR. Note that this can be problematic
  349. # on Windows since the implementation allows two active sockets on
  350. # the same address!
  351. self.rpcclt.listening_sock.setsockopt(socket.SOL_SOCKET,
  352. socket.SO_REUSEADDR, 1)
  353. self.spawn_subprocess()
  354. #time.sleep(20) # test to simulate GUI not accepting connection
  355. # Accept the connection from the Python execution server
  356. self.rpcclt.listening_sock.settimeout(10)
  357. try:
  358. self.rpcclt.accept()
  359. except socket.timeout, err:
  360. self.display_no_subprocess_error()
  361. return None
  362. self.rpcclt.register("stdin", self.tkconsole)
  363. self.rpcclt.register("stdout", self.tkconsole.stdout)
  364. self.rpcclt.register("stderr", self.tkconsole.stderr)
  365. self.rpcclt.register("flist", self.tkconsole.flist)
  366. self.rpcclt.register("linecache", linecache)
  367. self.rpcclt.register("interp", self)
  368. self.transfer_path()
  369. self.poll_subprocess()
  370. return self.rpcclt
  371. def restart_subprocess(self):
  372. if self.restarting:
  373. return self.rpcclt
  374. self.restarting = True
  375. # close only the subprocess debugger
  376. debug = self.getdebugger()
  377. if debug:
  378. try:
  379. # Only close subprocess debugger, don't unregister gui_adap!
  380. RemoteDebugger.close_subprocess_debugger(self.rpcclt)
  381. except:
  382. pass
  383. # Kill subprocess, spawn a new one, accept connection.
  384. self.rpcclt.close()
  385. self.unix_terminate()
  386. console = self.tkconsole
  387. was_executing = console.executing
  388. console.executing = False
  389. self.spawn_subprocess()
  390. try:
  391. self.rpcclt.accept()
  392. except socket.timeout, err:
  393. self.display_no_subprocess_error()
  394. return None
  395. self.transfer_path()
  396. # annotate restart in shell window and mark it
  397. console.text.delete("iomark", "end-1c")
  398. if was_executing:
  399. console.write('\n')
  400. console.showprompt()
  401. halfbar = ((int(console.width) - 16) // 2) * '='
  402. console.write(halfbar + ' RESTART ' + halfbar)
  403. console.text.mark_set("restart", "end-1c")
  404. console.text.mark_gravity("restart", "left")
  405. console.showprompt()
  406. # restart subprocess debugger
  407. if debug:
  408. # Restarted debugger connects to current instance of debug GUI
  409. gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
  410. # reload remote debugger breakpoints for all PyShellEditWindows
  411. debug.load_breakpoints()
  412. self.restarting = False
  413. return self.rpcclt
  414. def __request_interrupt(self):
  415. self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
  416. def interrupt_subprocess(self):
  417. threading.Thread(target=self.__request_interrupt).start()
  418. def kill_subprocess(self):
  419. try:
  420. self.rpcclt.close()
  421. except AttributeError: # no socket
  422. pass
  423. self.unix_terminate()
  424. self.tkconsole.executing = False
  425. self.rpcclt = None
  426. def unix_terminate(self):
  427. "UNIX: make sure subprocess is terminated and collect status"
  428. if hasattr(os, 'kill'):
  429. try:
  430. os.kill(self.rpcpid, SIGTERM)
  431. except OSError:
  432. # process already terminated:
  433. return
  434. else:
  435. try:
  436. os.waitpid(self.rpcpid, 0)
  437. except OSError:
  438. return
  439. def transfer_path(self):
  440. self.runcommand("""if 1:
  441. import sys as _sys
  442. _sys.path = %r
  443. del _sys
  444. \n""" % (sys.path,))
  445. active_seq = None
  446. def poll_subprocess(self):
  447. clt = self.rpcclt
  448. if clt is None:
  449. return
  450. try:
  451. response = clt.pollresponse(self.active_seq, wait=0.05)
  452. except (EOFError, IOError, KeyboardInterrupt):
  453. # lost connection or subprocess terminated itself, restart
  454. # [the KBI is from rpc.SocketIO.handle_EOF()]
  455. if self.tkconsole.closing:
  456. return
  457. response = None
  458. self.restart_subprocess()
  459. if response:
  460. self.tkconsole.resetoutput()
  461. self.active_seq = None
  462. how, what = response
  463. console = self.tkconsole.console
  464. if how == "OK":
  465. if what is not None:
  466. print >>console, repr(what)
  467. elif how == "EXCEPTION":
  468. if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
  469. self.remote_stack_viewer()
  470. elif how == "ERROR":
  471. errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
  472. print >>sys.__stderr__, errmsg, what
  473. print >>console, errmsg, what
  474. # we received a response to the currently active seq number:
  475. try:
  476. self.tkconsole.endexecuting()
  477. except AttributeError: # shell may have closed
  478. pass
  479. # Reschedule myself
  480. if not self.tkconsole.closing:
  481. self.tkconsole.text.after(self.tkconsole.pollinterval,
  482. self.poll_subprocess)
  483. debugger = None
  484. def setdebugger(self, debugger):
  485. self.debugger = debugger
  486. def getdebugger(self):
  487. return self.debugger
  488. def open_remote_stack_viewer(self):
  489. """Initiate the remote stack viewer from a separate thread.
  490. This method is called from the subprocess, and by returning from this
  491. method we allow the subprocess to unblock. After a bit the shell
  492. requests the subprocess to open the remote stack viewer which returns a
  493. static object looking at the last exception. It is queried through
  494. the RPC mechanism.
  495. """
  496. self.tkconsole.text.after(300, self.remote_stack_viewer)
  497. return
  498. def remote_stack_viewer(self):
  499. from idlelib import RemoteObjectBrowser
  500. oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
  501. if oid is None:
  502. self.tkconsole.root.bell()
  503. return
  504. item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
  505. from idlelib.TreeWidget import ScrolledCanvas, TreeNode
  506. top = Toplevel(self.tkconsole.root)
  507. theme = idleConf.GetOption('main','Theme','name')
  508. background = idleConf.GetHighlight(theme, 'normal')['background']
  509. sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
  510. sc.frame.pack(expand=1, fill="both")
  511. node = TreeNode(sc.canvas, None, item)
  512. node.expand()
  513. # XXX Should GC the remote tree when closing the window
  514. gid = 0
  515. def execsource(self, source):
  516. "Like runsource() but assumes complete exec source"
  517. filename = self.stuffsource(source)
  518. self.execfile(filename, source)
  519. def execfile(self, filename, source=None):
  520. "Execute an existing file"
  521. if source is None:
  522. source = open(filename, "r").read()
  523. try:
  524. code = compile(source, filename, "exec")
  525. except (OverflowError, SyntaxError):
  526. self.tkconsole.resetoutput()
  527. tkerr = self.tkconsole.stderr
  528. print>>tkerr, '*** Error in script or command!\n'
  529. print>>tkerr, 'Traceback (most recent call last):'
  530. InteractiveInterpreter.showsyntaxerror(self, filename)
  531. self.tkconsole.showprompt()
  532. else:
  533. self.runcode(code)
  534. def runsource(self, source):
  535. "Extend base class method: Stuff the source in the line cache first"
  536. filename = self.stuffsource(source)
  537. self.more = 0
  538. self.save_warnings_filters = warnings.filters[:]
  539. warnings.filterwarnings(action="error", category=SyntaxWarning)
  540. if isinstance(source, types.UnicodeType):
  541. from idlelib import IOBinding
  542. try:
  543. source = source.encode(IOBinding.encoding)
  544. except UnicodeError:
  545. self.tkconsole.resetoutput()
  546. self.write("Unsupported characters in input\n")
  547. return
  548. try:
  549. # InteractiveInterpreter.runsource() calls its runcode() method,
  550. # which is overridden (see below)
  551. return InteractiveInterpreter.runsource(self, source, filename)
  552. finally:
  553. if self.save_warnings_filters is not None:
  554. warnings.filters[:] = self.save_warnings_filters
  555. self.save_warnings_filters = None
  556. def stuffsource(self, source):
  557. "Stuff source in the filename cache"
  558. filename = "<pyshell#%d>" % self.gid
  559. self.gid = self.gid + 1
  560. lines = source.split("\n")
  561. linecache.cache[filename] = len(source)+1, 0, lines, filename
  562. return filename
  563. def prepend_syspath(self, filename):
  564. "Prepend sys.path with file's directory if not already included"
  565. self.runcommand("""if 1:
  566. _filename = %r
  567. import sys as _sys
  568. from os.path import dirname as _dirname
  569. _dir = _dirname(_filename)
  570. if not _dir in _sys.path:
  571. _sys.path.insert(0, _dir)
  572. del _filename, _sys, _dirname, _dir
  573. \n""" % (filename,))
  574. def showsyntaxerror(self, filename=None):
  575. """Extend base class method: Add Colorizing
  576. Color the offending position instead of printing it and pointing at it
  577. with a caret.
  578. """
  579. text = self.tkconsole.text
  580. stuff = self.unpackerror()
  581. if stuff:
  582. msg, lineno, offset, line = stuff
  583. if lineno == 1:
  584. pos = "iomark + %d chars" % (offset-1)
  585. else:
  586. pos = "iomark linestart + %d lines + %d chars" % \
  587. (lineno-1, offset-1)
  588. text.tag_add("ERROR", pos)
  589. text.see(pos)
  590. char = text.get(pos)
  591. if char and char in IDENTCHARS:
  592. text.tag_add("ERROR", pos + " wordstart", pos)
  593. self.tkconsole.resetoutput()
  594. self.write("SyntaxError: %s\n" % str(msg))
  595. else:
  596. self.tkconsole.resetoutput()
  597. InteractiveInterpreter.showsyntaxerror(self, filename)
  598. self.tkconsole.showprompt()
  599. def unpackerror(self):
  600. type, value, tb = sys.exc_info()
  601. ok = type is SyntaxError
  602. if ok:
  603. try:
  604. msg, (dummy_filename, lineno, offset, line) = value
  605. if not offset:
  606. offset = 0
  607. except:
  608. ok = 0
  609. if ok:
  610. return msg, lineno, offset, line
  611. else:
  612. return None
  613. def showtraceback(self):
  614. "Extend base class method to reset output properly"
  615. self.tkconsole.resetoutput()
  616. self.checklinecache()
  617. InteractiveInterpreter.showtraceback(self)
  618. if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
  619. self.tkconsole.open_stack_viewer()
  620. def checklinecache(self):
  621. c = linecache.cache
  622. for key in c.keys():
  623. if key[:1] + key[-1:] != "<>":
  624. del c[key]
  625. def runcommand(self, code):
  626. "Run the code without invoking the debugger"
  627. # The code better not raise an exception!
  628. if self.tkconsole.executing:
  629. self.display_executing_dialog()
  630. return 0
  631. if self.rpcclt:
  632. self.rpcclt.remotequeue("exec", "runcode", (code,), {})
  633. else:
  634. exec code in self.locals
  635. return 1
  636. def runcode(self, code):
  637. "Override base class method"
  638. if self.tkconsole.executing:
  639. self.interp.restart_subprocess()
  640. self.checklinecache()
  641. if self.save_warnings_filters is not None:
  642. warnings.filters[:] = self.save_warnings_filters
  643. self.save_warnings_filters = None
  644. debugger = self.debugger
  645. try:
  646. self.tkconsole.beginexecuting()
  647. if not debugger and self.rpcclt is not None:
  648. self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
  649. (code,), {})
  650. elif debugger:
  651. debugger.run(code, self.locals)
  652. else:
  653. exec code in self.locals
  654. except SystemExit:
  655. if not self.tkconsole.closing:
  656. if tkMessageBox.askyesno(
  657. "Exit?",
  658. "Do you want to exit altogether?",
  659. default="yes",
  660. master=self.tkconsole.text):
  661. raise
  662. else:
  663. self.showtraceback()
  664. else:
  665. raise
  666. except:
  667. if use_subprocess:
  668. print >>self.tkconsole.stderr, \
  669. "IDLE internal error in runcode()"
  670. self.showtraceback()
  671. self.tkconsole.endexecuting()
  672. else:
  673. if self.tkconsole.canceled:
  674. self.tkconsole.canceled = False
  675. print >>self.tkconsole.stderr, "KeyboardInterrupt"
  676. else:
  677. self.showtraceback()
  678. finally:
  679. if not use_subprocess:
  680. try:
  681. self.tkconsole.endexecuting()
  682. except AttributeError: # shell may have closed
  683. pass
  684. def write(self, s):
  685. "Override base class method"
  686. self.tkconsole.stderr.write(s)
  687. def display_port_binding_error(self):
  688. tkMessageBox.showerror(
  689. "Port Binding Error",
  690. "IDLE can't bind to a TCP/IP port, which is necessary to "
  691. "communicate with its Python execution server. This might be "
  692. "because no networking is installed on this computer. "
  693. "Run IDLE with the -n command line switch to start without a "
  694. "subprocess and refer to Help/IDLE Help 'Running without a "
  695. "subprocess' for further details.",
  696. master=self.tkconsole.text)
  697. def display_no_subprocess_error(self):
  698. tkMessageBox.showerror(
  699. "Subprocess Startup Error",
  700. "IDLE's subprocess didn't make connection. Either IDLE can't "
  701. "start a subprocess or personal firewall software is blocking "
  702. "the connection.",
  703. master=self.tkconsole.text)
  704. def display_executing_dialog(self):
  705. tkMessageBox.showerror(
  706. "Already executing",
  707. "The Python Shell window is already executing a command; "
  708. "please wait until it is finished.",
  709. master=self.tkconsole.text)
  710. class PyShell(OutputWindow):
  711. shell_title = "Python Shell"
  712. # Override classes
  713. ColorDelegator = ModifiedColorDelegator
  714. UndoDelegator = ModifiedUndoDelegator
  715. # Override menus
  716. menu_specs = [
  717. ("file", "_File"),
  718. ("edit", "_Edit"),
  719. ("debug", "_Debug"),
  720. ("options", "_Options"),
  721. ("windows", "_Windows"),
  722. ("help", "_Help"),
  723. ]
  724. if macosxSupport.runningAsOSXApp():
  725. del menu_specs[-3]
  726. menu_specs[-2] = ("windows", "_Window")
  727. # New classes
  728. from idlelib.IdleHistory import History
  729. def __init__(self, flist=None):
  730. if use_subprocess:
  731. ms = self.menu_specs
  732. if ms[2][0] != "shell":
  733. ms.insert(2, ("shell", "She_ll"))
  734. self.interp = ModifiedInterpreter(self)
  735. if flist is None:
  736. root = Tk()
  737. fixwordbreaks(root)
  738. root.withdraw()
  739. flist = PyShellFileList(root)
  740. #
  741. OutputWindow.__init__(self, flist, None, None)
  742. #
  743. ## self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
  744. self.usetabs = True
  745. # indentwidth must be 8 when using tabs. See note in EditorWindow:
  746. self.indentwidth = 8
  747. self.context_use_ps1 = True
  748. #
  749. text = self.text
  750. text.configure(wrap="char")
  751. text.bind("<<newline-and-indent>>", self.enter_callback)
  752. text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
  753. text.bind("<<interrupt-execution>>", self.cancel_callback)
  754. text.bind("<<end-of-file>>", self.eof_callback)
  755. text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
  756. text.bind("<<toggle-debugger>>", self.toggle_debugger)
  757. text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
  758. if use_subprocess:
  759. text.bind("<<view-restart>>", self.view_restart_mark)
  760. text.bind("<<restart-shell>>", self.restart_shell)
  761. #
  762. self.save_stdout = sys.stdout
  763. self.save_stderr = sys.stderr
  764. self.save_stdin = sys.stdin
  765. from idlelib import IOBinding
  766. self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
  767. self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
  768. self.console = PseudoFile(self, "console", IOBinding.encoding)
  769. if not use_subprocess:
  770. sys.stdout = self.stdout
  771. sys.stderr = self.stderr
  772. sys.stdin = self
  773. #
  774. self.history = self.History(self.text)
  775. #
  776. self.pollinterval = 50 # millisec
  777. def get_standard_extension_names(self):
  778. return idleConf.GetExtensions(shell_only=True)
  779. reading = False
  780. executing = False
  781. canceled = False
  782. endoffile = False
  783. closing = False
  784. def set_warning_stream(self, stream):
  785. global warning_stream
  786. warning_stream = stream
  787. def get_warning_stream(self):
  788. return warning_stream
  789. def toggle_debugger(self, event=None):
  790. if self.executing:
  791. tkMessageBox.showerror("Don't debug now",
  792. "You can only toggle the debugger when idle",
  793. master=self.text)
  794. self.set_debugger_indicator()
  795. return "break"
  796. else:
  797. db = self.interp.getdebugger()
  798. if db:
  799. self.close_debugger()
  800. else:
  801. self.open_debugger()
  802. def set_debugger_indicator(self):
  803. db = self.interp.getdebugger()
  804. self.setvar("<<toggle-debugger>>", not not db)
  805. def toggle_jit_stack_viewer(self, event=None):
  806. pass # All we need is the variable
  807. def close_debugger(self):
  808. db = self.interp.getdebugger()
  809. if db:
  810. self.interp.setdebugger(None)
  811. db.close()
  812. if self.interp.rpcclt:
  813. RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
  814. self.resetoutput()
  815. self.console.write("[DEBUG OFF]\n")
  816. sys.ps1 = ">>> "
  817. self.showprompt()
  818. self.set_debugger_indicator()
  819. def open_debugger(self):
  820. if self.interp.rpcclt:
  821. dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
  822. self)
  823. else:
  824. dbg_gui = Debugger.Debugger(self)
  825. self.interp.setdebugger(dbg_gui)
  826. dbg_gui.load_breakpoints()
  827. sys.ps1 = "[DEBUG ON]\n>>> "
  828. self.showprompt()
  829. self.set_debugger_indicator()
  830. def beginexecuting(self):
  831. "Helper for ModifiedInterpreter"
  832. self.resetoutput()
  833. self.executing = 1
  834. def endexecuting(self):
  835. "Helper for ModifiedInterpreter"
  836. self.executing = 0
  837. self.canceled = 0
  838. self.showprompt()
  839. def close(self):
  840. "Extend EditorWindow.close()"
  841. if self.executing:
  842. response = tkMessageBox.askokcancel(
  843. "Kill?",
  844. "The program is still running!\n Do you want to kill it?",
  845. default="ok",
  846. parent=self.text)
  847. if response is False:
  848. return "cancel"
  849. if self.reading:
  850. self.top.quit()
  851. self.canceled = True
  852. self.closing = True
  853. # Wait for poll_subprocess() rescheduling to stop
  854. self.text.after(2 * self.pollinterval, self.close2)
  855. def close2(self):
  856. return EditorWindow.close(self)
  857. def _close(self):
  858. "Extend EditorWindow._close(), shut down debugger and execution server"
  859. self.close_debugger()
  860. if use_subprocess:
  861. self.interp.kill_subprocess()
  862. # Restore std streams
  863. sys.stdout = self.save_stdout
  864. sys.stderr = self.save_stderr
  865. sys.stdin = self.save_stdin
  866. # Break cycles
  867. self.interp = None
  868. self.console = None
  869. self.flist.pyshell = None
  870. self.history = None
  871. EditorWindow._close(self)
  872. def ispythonsource(self, filename):
  873. "Override EditorWindow method: never remove the colorizer"
  874. return True
  875. def short_title(self):
  876. return self.shell_title
  877. COPYRIGHT = \
  878. 'Type "copyright", "credits" or "license()" for more information.'
  879. def begin(self):
  880. self.resetoutput()
  881. if use_subprocess:
  882. nosub = ''
  883. client = self.interp.start_subprocess()
  884. if not client:
  885. self.close()
  886. return False
  887. else:
  888. nosub = "==== No Subprocess ===="
  889. self.write("Python %s on %s\n%s\n%s" %
  890. (sys.version, sys.platform, self.COPYRIGHT, nosub))
  891. self.showprompt()
  892. import Tkinter
  893. Tkinter._default_root = None # 03Jan04 KBK What's this?
  894. return True
  895. def readline(self):
  896. save = self.reading
  897. try:
  898. self.reading = 1
  899. self.top.mainloop() # nested mainloop()
  900. finally:
  901. self.reading = save
  902. line = self.text.get("iomark", "end-1c")
  903. if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
  904. line = "\n"
  905. if isinstance(line, unicode):
  906. from idlelib import IOBinding
  907. try:
  908. line = line.encode(IOBinding.encoding)
  909. except UnicodeError:
  910. pass
  911. self.resetoutput()
  912. if self.canceled:
  913. self.canceled = 0
  914. if not use_subprocess:
  915. raise KeyboardInterrupt
  916. if self.endoffile:
  917. self.endoffile = 0
  918. line = ""
  919. return line
  920. def isatty(self):
  921. return True
  922. def cancel_callback(self, event=None):
  923. try:
  924. if self.text.compare("sel.first", "!=", "sel.last"):
  925. return # Active selection -- always use default binding
  926. except:
  927. pass
  928. if not (self.executing or self.reading):
  929. self.resetoutput()
  930. self.interp.write("KeyboardInterrupt\n")
  931. self.showprompt()
  932. return "break"
  933. self.endoffile = 0
  934. self.canceled = 1
  935. if (self.executing and self.interp.rpcclt):
  936. if self.interp.getdebugger():
  937. self.interp.restart_subprocess()
  938. else:
  939. self.interp.interrupt_subprocess()
  940. if self.reading:
  941. self.top.quit() # exit the nested mainloop() in readline()
  942. return "break"
  943. def eof_callback(self, event):
  944. if self.executing and not self.reading:
  945. return # Let the default binding (delete next char) take over
  946. if not (self.text.compare("iomark", "==", "insert") and
  947. self.text.compare("insert", "==", "end-1c")):
  948. return # Let the default binding (delete next char) take over
  949. if not self.executing:
  950. self.resetoutput()
  951. self.close()
  952. else:
  953. self.canceled = 0
  954. self.endoffile = 1
  955. self.top.quit()
  956. return "break"
  957. def linefeed_callback(self, event):
  958. # Insert a linefeed without entering anything (still autoindented)
  959. if self.reading:
  960. self.text.insert("insert", "\n")
  961. self.text.see("insert")
  962. else:
  963. self.newline_and_indent_event(event)
  964. return "break"
  965. def enter_callback(self, event):
  966. if self.executing and not self.reading:
  967. return # Let the default binding (insert '\n') take over
  968. # If some text is selected, recall the selection
  969. # (but only if this before the I/O mark)
  970. try:
  971. sel = self.text.get("sel.first", "sel.last")
  972. if sel:
  973. if self.text.compare("sel.last", "<=", "iomark"):
  974. self.recall(sel, event)
  975. return "break"
  976. except:
  977. pass
  978. # If we're strictly before the line containing iomark, recall
  979. # the current line, less a leading prompt, less leading or
  980. # trailing whitespace
  981. if self.text.compare("insert", "<", "iomark linestart"):
  982. # Check if there's a relevant stdin range -- if so, use it
  983. prev = self.text.tag_prevrange("stdin", "insert")
  984. if prev and self.text.compare("insert", "<", prev[1]):
  985. self.recall(self.text.get(prev[0], prev[1]), event)
  986. return "break"
  987. next = self.text.tag_nextrange("stdin", "insert")
  988. if next and self.text.compare("insert lineend", ">=", next[0]):
  989. self.recall(self.text.get(next[0], next[1]), event)
  990. return "break"
  991. # No stdin mark -- just get the current line, less any prompt
  992. indices = self.text.tag_nextrange("console", "insert linestart")
  993. if indices and \
  994. self.text.compare(indices[0], "<=", "insert linestart"):
  995. self.recall(self.text.get(indices[1], "insert lineend"), event)
  996. else:
  997. self.recall(self.text.get("insert linestart", "insert lineend"), event)
  998. return "break"
  999. # If we're between the beginning of the line and the iomark, i.e.
  1000. # in the prompt area, move to the end of the prompt
  1001. if self.text.compare("insert", "<", "iomark"):
  1002. self.text.mark_set("insert", "iomark")
  1003. # If we're in the current input and there's only whitespace
  1004. # beyond the cursor, erase that whitespace first
  1005. s = self.text.get("insert", "end-1c")
  1006. if s and not s.strip():
  1007. self.text.delete("insert", "end-1c")
  1008. # If we're in the current input before its last line,
  1009. # insert a newline right at the insert point
  1010. if self.text.compare("insert", "<", "end-1c linestart"):
  1011. self.newline_and_indent_event(event)
  1012. return "break"
  1013. # We're in the last line; append a newline and submit it
  1014. self.text.mark_set("insert", "end-1c")
  1015. if self.reading:
  1016. self.text.insert("insert", "\n")
  1017. self.text.see("insert")
  1018. else:
  1019. self.newline_and_indent_event(event)
  1020. self.text.tag_add("stdin", "iomark", "end-1c")
  1021. self.text.update_idletasks()
  1022. if self.reading:
  1023. self.top.quit() # Break out of recursive mainloop() in raw_input()
  1024. else:
  1025. self.runit()
  1026. return "break"
  1027. def recall(self, s, event):
  1028. # remove leading and trailing empty or whitespace lines
  1029. s = re.sub(r'^\s*\n', '' , s)
  1030. s = re.sub(r'\n\s*$', '', s)
  1031. lines = s.split('\n')
  1032. self.text.undo_block_start()
  1033. try:
  1034. self.text.tag_remove("sel", "1.0", "end")
  1035. self.text.mark_set("insert", "end-1c")
  1036. prefix = self.text.get("insert linestart", "insert")
  1037. if prefix.rstrip().endswith(':'):
  1038. self.newline_and_indent_event(event)
  1039. prefix = self.text.get("insert linestart", "insert")
  1040. self.text.insert("insert", lines[0].strip())
  1041. if len(lines) > 1:
  1042. orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
  1043. new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)
  1044. for line in lines[1:]:
  1045. if line.startswith(orig_base_indent):
  1046. # replace orig base indentation with new indentation
  1047. line = new_base_indent + line[len(orig_base_indent):]
  1048. self.text.insert('insert', '\n'+line.rstrip())
  1049. finally:
  1050. self.text.see("insert")
  1051. self.text.undo_block_stop()
  1052. def runit(self):
  1053. line = self.text.get("iomark", "end-1c")
  1054. # Strip off last newline and surrounding whitespace.
  1055. # (To allow you to hit return twice to end a statement.)
  1056. i = len(line)
  1057. while i > 0 and line[i-1] in " \t":
  1058. i = i-1
  1059. if i > 0 and line[i-1] == "\n":
  1060. i = i-1
  1061. while i > 0 and line[i-1] in " \t":
  1062. i = i-1
  1063. line = line[:i]
  1064. more = self.interp.runsource(line)
  1065. def open_stack_viewer(self, event=None):
  1066. if self.interp.rpcclt:
  1067. return self.interp.remote_stack_viewer()
  1068. try:
  1069. sys.last_traceback
  1070. except:
  1071. tkMessageBox.showerror("No stack trace",
  1072. "There is no stack trace yet.\n"
  1073. "(sys.last_traceback is not defined)",
  1074. master=self.text)
  1075. return
  1076. from idlelib.StackViewer import StackBrowser
  1077. sv = StackBrowser(self.root, self.flist)
  1078. def view_restart_mark(self, event=None):
  1079. self.text.see("iomark")
  1080. self.text.see("restart")
  1081. def restart_shell(self, event=None):
  1082. self.interp.restart_subprocess()
  1083. def showprompt(self):
  1084. self.resetoutput()
  1085. try:
  1086. s = str(sys.ps1)
  1087. except:
  1088. s = ""
  1089. self.console.write(s)
  1090. self.text.mark_set("insert", "end-1c")
  1091. self.set_line_and_column()
  1092. self.io.reset_undo()
  1093. def resetoutput(self):
  1094. source = self.text.get("iomark", "end-1c")
  1095. if self.history:
  1096. self.history.history_store(source)
  1097. if self.text.get("end-2c") != "\n":
  1098. self.text.insert("end-1c", "\n")
  1099. self.text.mark_set("iomark", "end-1c")
  1100. self.set_line_and_column()
  1101. sys.stdout.softspace = 0
  1102. def write(self, s, tags=()):
  1103. try:
  1104. self.text.mark_gravity("iomark", "right")
  1105. OutputWindow.write(self, s, tags, "iomark")
  1106. self.text.mark_gravity("iomark", "left")
  1107. except:
  1108. pass
  1109. if self.canceled:
  1110. self.canceled = 0
  1111. if not use_subprocess:
  1112. raise KeyboardInterrupt
  1113. class PseudoFile(object):
  1114. def __init__(self, shell, tags, encoding=None):
  1115. self.shell = shell
  1116. self.tags = tags
  1117. self.softspace = 0
  1118. self.encoding = encoding
  1119. def write(self, s):
  1120. self.shell.write(s, self.tags)
  1121. def writelines(self, lines):
  1122. for line in lines:
  1123. self.write(line)
  1124. def flush(self):
  1125. pass
  1126. def isatty(self):
  1127. return True
  1128. usage_msg = """\
  1129. USAGE: idle [-deins] [-t title] [file]*
  1130. idle [-dns] [-t title] (-c cmd | -r file) [arg]*
  1131. idle [-dns] [-t title] - [arg]*
  1132. -h print this help message and exit
  1133. -n run IDLE without a subprocess (see Help/IDLE Help for details)
  1134. The following options will override the IDLE 'settings' configuration:
  1135. -e open an edit window
  1136. -i open a shell window
  1137. The following options imply -i and will open a shell:
  1138. -c cmd run the command in a shell, or
  1139. -r file run script from file
  1140. -d enable the debugger
  1141. -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
  1142. -t title set title of shell window
  1143. A default edit window will be bypassed when -c, -r, or - are used.
  1144. [arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
  1145. Examples:
  1146. idle
  1147. Open an edit window or shell depending on IDLE's configuration.
  1148. idle foo.py foobar.py
  1149. Edit the files, also open a shell if configured to start with shell.
  1150. idle -est "Baz" foo.py
  1151. Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
  1152. window with the title "Baz".
  1153. idle -c "import sys; print sys.argv" "foo"
  1154. Open a shell window and run the command, passing "-c" in sys.argv[0]
  1155. and "foo" in sys.argv[1].
  1156. idle -d -s -r foo.py "Hello World"
  1157. Open a shell window, run a startup script, enable the debugger, and
  1158. run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
  1159. sys.argv[1].
  1160. echo "import sys; print sys.argv" | idle - "foobar"
  1161. Open a shell window, run the script piped in, passing '' in sys.argv[0]
  1162. and "foobar" in sys.argv[1].
  1163. """
  1164. def main():
  1165. global flist, root, use_subprocess
  1166. use_subprocess = True
  1167. enable_shell = True
  1168. enable_edit = False
  1169. debug = False
  1170. cmd = None
  1171. script = None
  1172. startup = False
  1173. try:
  1174. opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
  1175. except getopt.error, msg:
  1176. sys.stderr.write("Error: %s\n" % str(msg))
  1177. sys.stderr.write(usage_msg)
  1178. sys.exit(2)
  1179. for o, a in opts:
  1180. if o == '-c':
  1181. cmd = a
  1182. enable_shell = True
  1183. if o == '-d':
  1184. debug = True
  1185. enable_shell = True
  1186. if o == '-e':
  1187. enable_edit = True
  1188. enable_shell = False
  1189. if o == '-h':
  1190. sys.stdout.write(usage_msg)
  1191. sys.exit()
  1192. if o == '-i':
  1193. enable_shell = True
  1194. if o == '-n':
  1195. use_subprocess = False
  1196. if o == '-r':
  1197. script = a
  1198. if os.path.isfile(script):
  1199. pass
  1200. else:
  1201. print "No script file: ", script
  1202. sys.exit()
  1203. enable_shell = True
  1204. if o == '-s':
  1205. startup = True
  1206. enable_shell = True
  1207. if o == '-t':
  1208. PyShell.shell_title = a
  1209. enable_shell = True
  1210. if args and args[0] == '-':
  1211. cmd = sys.stdin.read()
  1212. enable_shell = True
  1213. # process sys.argv and sys.path:
  1214. for i in range(len(sys.path)):
  1215. sys.path[i] = os.path.abspath(sys.path[i])
  1216. if args and args[0] == '-':
  1217. sys.argv = [''] + args[1:]
  1218. elif cmd:
  1219. sys.argv = ['-c'] + args
  1220. elif script:
  1221. sys.argv = [script] + args
  1222. elif args:
  1223. enable_edit = True
  1224. pathx = []
  1225. for filename in args:
  1226. pathx.append(os.path.dirname(filename))
  1227. for dir in pathx:
  1228. dir = os.path.abspath(dir)
  1229. if dir not in sys.path:
  1230. sys.path.insert(0, dir)
  1231. else:
  1232. dir = os.getcwd()
  1233. if not dir in sys.path:
  1234. sys.path.insert(0, dir)
  1235. # check the IDLE settings configuration (but command line overrides)
  1236. edit_start = idleConf.GetOption('main', 'General',
  1237. 'editor-on-startup', type='bool')
  1238. enable_edit = enable_edit or edit_start
  1239. # start editor and/or shell windows:
  1240. root = Tk(className="Idle")
  1241. fixwordbreaks(root)
  1242. root.withdraw()
  1243. flist = PyShellFileList(root)
  1244. macosxSupport.setupApp(root, flist)
  1245. if enable_edit:
  1246. if not (cmd or script):
  1247. fo

Large files files are truncated, but you can click here to view the full file