From kbk@users.sourceforge.net Wed Jul 3 04:55:45 2002 From: kbk@users.sourceforge.net (Kurt B. Kaiser) Date: Tue, 02 Jul 2002 20:55:45 -0700 Subject: [Idle-dev] CVS: idle RemoteDebugger.py,1.5,1.6 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv27426 Modified Files: RemoteDebugger.py Log Message: Debugger Exception Info and GUI Stack Exception Traceback: finish implementation. Index: RemoteDebugger.py =================================================================== RCS file: /cvsroot/idlefork/idle/RemoteDebugger.py,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -r1.5 -r1.6 *** RemoteDebugger.py 26 Jun 2002 02:32:09 -0000 1.5 --- RemoteDebugger.py 3 Jul 2002 03:55:43 -0000 1.6 *************** *** 22,25 **** --- 22,26 ---- import sys + import types import rpc import Debugger *************** *** 34,37 **** --- 35,39 ---- dicttable = {} codetable = {} + tracebacktable = {} def wrap_frame(frame): *************** *** 41,48 **** def wrap_info(info): if info is None: return None else: ! return None # XXX for now class GUIProxy: --- 43,56 ---- def wrap_info(info): + "replace info[2], a traceback instance, by its ID" if info is None: return None else: ! traceback = info[2] ! assert isinstance(traceback, types.TracebackType) ! traceback_id = id(traceback) ! tracebacktable[traceback_id] = traceback ! modified_info = (info[0], info[1], traceback_id) ! return modified_info class GUIProxy: *************** *** 54,57 **** --- 62,66 ---- def interaction(self, message, frame, info=None): # calls rpc.SocketIO.remotecall() via run.MyHandler instance + # pass frame and traceback object IDs instead of the objects themselves self.conn.remotecall(self.oid, "interaction", (message, wrap_frame(frame), wrap_info(info)), *************** *** 85,89 **** ##print >>sys.__stderr__, "get_stack(%s, %s)" % (`fid`, `tbid`) frame = frametable[fid] ! tb = None # XXX for now stack, i = self.idb.get_stack(frame, tb) ##print >>sys.__stderr__, "get_stack() ->", stack --- 94,101 ---- ##print >>sys.__stderr__, "get_stack(%s, %s)" % (`fid`, `tbid`) frame = frametable[fid] ! if tbid is None: ! tb = None ! else: ! tb = tracebacktable[tbid] stack, i = self.idb.get_stack(frame, tb) ##print >>sys.__stderr__, "get_stack() ->", stack *************** *** 105,109 **** def clear_all_file_breaks(self, filename): msg = self.idb.clear_all_file_breaks(filename) ! #----------called by a FrameProxy---------- --- 117,122 ---- def clear_all_file_breaks(self, filename): msg = self.idb.clear_all_file_breaks(filename) ! return msg ! #----------called by a FrameProxy---------- *************** *** 264,272 **** self.gui = gui ! def interaction(self, message, fid, iid): ! ##print "interaction: (%s, %s, %s)" % (`message`,`fid`, `iid`) frame = FrameProxy(self.conn, fid) ! info = None # XXX for now ! self.gui.interaction(message, frame, info) --- 277,284 ---- self.gui = gui ! def interaction(self, message, fid, modified_info): ! ##print "interaction: (%s, %s, %s)" % (message, fid, modified_info) frame = FrameProxy(self.conn, fid) ! self.gui.interaction(message, frame, modified_info) *************** *** 287,292 **** self.call("run", cmd) ! def get_stack(self, frame, tb): ! stack, i = self.call("get_stack", frame._fid, None) stack = [(FrameProxy(self.conn, fid), k) for fid, k in stack] return stack, i --- 299,305 ---- self.call("run", cmd) ! def get_stack(self, frame, tbid): ! # passing frame and traceback IDs, not the objects themselves ! stack, i = self.call("get_stack", frame._fid, tbid) stack = [(FrameProxy(self.conn, fid), k) for fid, k in stack] return stack, i *************** *** 316,320 **** def clear_all_file_breaks(self, filename): msg = self.call("clear_all_file_breaks", filename) ! def start_remote_debugger(rpcclt, pyshell): --- 329,333 ---- def clear_all_file_breaks(self, filename): msg = self.call("clear_all_file_breaks", filename) ! return msg def start_remote_debugger(rpcclt, pyshell): From kbk@users.sourceforge.net Sat Jul 6 01:51:36 2002 From: kbk@users.sourceforge.net (Kurt B. Kaiser) Date: Fri, 05 Jul 2002 17:51:36 -0700 Subject: [Idle-dev] CVS: idle Debugger.py,1.10,1.11 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv1304 Modified Files: Debugger.py Log Message: 1. Test Sourceforge checkin, idle-dev posting 2. Remove extraneous comment Index: Debugger.py =================================================================== RCS file: /cvsroot/idlefork/idle/Debugger.py,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -r1.10 -r1.11 *** Debugger.py 5 Jul 2002 22:05:24 -0000 1.10 --- Debugger.py 6 Jul 2002 00:51:33 -0000 1.11 *************** *** 307,311 **** if lv and gv and ldict is gdict: ldict = None - # Calls OldStackviewer.NamespaceViewer.load_dict(): if lv: lv.load_dict(ldict, force, self.pyshell.interp.rpcclt) --- 307,310 ---- From kbk@shore.net Sat Jul 6 01:53:52 2002 From: kbk@shore.net (Kurt B. Kaiser) Date: 05 Jul 2002 20:53:52 -0400 Subject: [Idle-dev] Combine OldStackViewer.py with Debugger.py Message-ID: Hm, I checked in this change M Debugger.py : Incorporate StackViewer, NamespaceViewer classes M StackViewer.py : remove import OldStackViewer U OldStackViewer.py : remove file Sourceforge updated the CVS but apparently flubbed accessing my username. Also did not post to Idle-dev. Hopefully a transient. I have no problem logging into the shell acct. Just did a small change, no problem, may be singleton event. KBK ============================ Checking in Debugger.py; /cvsroot/idlefork/idle/Debugger.py,v <-- Debugger.py new revision: 1.10; previous revision: 1.9 done Checking in StackViewer.py; /cvsroot/idlefork/idle/StackViewer.py,v <-- StackViewer.py new revision: 1.5; previous revision: 1.4 done Removing OldStackViewer.py; /cvsroot/idlefork/idle/OldStackViewer.py,v <-- OldStackViewer.py new revision: delete; previous revision: 1.3 done Mailing idlefork@users.sourceforge.net... Generating notification message... Generating notification message... done. 2002-07-05 15:05:37 Failed to get user name for uid 56795 ============================= From kbk@users.sourceforge.net Sat Jul 6 02:07:20 2002 From: kbk@users.sourceforge.net (Kurt B. Kaiser) Date: Fri, 05 Jul 2002 18:07:20 -0700 Subject: [Idle-dev] CVS: idle FrameViewer.py,1.2,NONE Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv4345 Removed Files: FrameViewer.py Log Message: Remove dead code. --- FrameViewer.py DELETED --- From kbk@users.sourceforge.net Sat Jul 6 02:20:53 2002 From: kbk@users.sourceforge.net (Kurt B. Kaiser) Date: Fri, 05 Jul 2002 18:20:53 -0700 Subject: [Idle-dev] CVS: idle RemoteInterp.py,1.3,NONE Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv6587 Removed Files: RemoteInterp.py Log Message: Decent burial for venerated ancestor (urn in attic) --- RemoteInterp.py DELETED --- From kbk@users.sourceforge.net Sat Jul 6 05:22:27 2002 From: kbk@users.sourceforge.net (Kurt B. Kaiser) Date: Fri, 05 Jul 2002 21:22:27 -0700 Subject: [Idle-dev] CVS: idle Debugger.py,1.11,1.12 EditorWindow.py,1.25,1.26 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv11580 Modified Files: Debugger.py EditorWindow.py Log Message: Modifying EditorWindow causes breakpoints in that module to be removed from both sides of the split debugger. M Debugger.py M EditorWindow.py Index: Debugger.py =================================================================== RCS file: /cvsroot/idlefork/idle/Debugger.py,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -r1.11 -r1.12 *** Debugger.py 6 Jul 2002 00:51:33 -0000 1.11 --- Debugger.py 6 Jul 2002 04:22:25 -0000 1.12 *************** *** 83,86 **** --- 83,87 ---- for window in edit_windows: window.text.tag_remove("BREAK", 1.0, END) + window.break_set = False # Clean up pyshell if user clicked debugger control close widget. # (Causes a harmless extra cycle through close_debugger() if user *************** *** 324,327 **** --- 325,329 ---- return text.tag_add("BREAK", "insert linestart", "insert lineend +1char") + edit.break_set = True def clear_breakpoint_here(self, edit): *************** *** 338,341 **** --- 340,344 ---- text.tag_remove("BREAK", "insert linestart",\ "insert lineend +1char") + # Don't bother to track break_set status def clear_file_breaks(self, edit): *************** *** 349,353 **** text.bell() return ! text.tag_delete("BREAK") --- 352,357 ---- text.bell() return ! text.tag_remove("BREAK", "1.0", END) ! edit.break_set = False Index: EditorWindow.py =================================================================== RCS file: /cvsroot/idlefork/idle/EditorWindow.py,v retrieving revision 1.25 retrieving revision 1.26 diff -C2 -r1.25 -r1.26 *** EditorWindow.py 24 Jun 2002 17:03:37 -0000 1.25 --- EditorWindow.py 6 Jul 2002 04:22:25 -0000 1.26 *************** *** 102,105 **** --- 102,106 ---- self.recentFilesPath=os.path.join(idleConf.GetUserCfgDir(), 'recent-files.lst') + self.break_set = False self.vbar = vbar = Scrollbar(top, name='vbar') self.text_frame = text_frame = Frame(top) *************** *** 632,635 **** --- 633,639 ---- title = "*%s*" % title icon = "*%s" % icon + if self.break_set: + shell = self.flist.pyshell + shell.interp.debugger.clear_file_breaks(self) self.top.wm_title(title) self.top.wm_iconname(icon) *************** *** 700,705 **** if self.io.filename: self.UpdateRecentFilesList(newFile=self.io.filename) ! shell = self.flist.pyshell ! if shell and shell.interp.debugger: shell.interp.debugger.clear_file_breaks(self) WindowList.unregister_callback(self.postwindowsmenu) --- 704,709 ---- if self.io.filename: self.UpdateRecentFilesList(newFile=self.io.filename) ! if self.break_set: ! shell = self.flist.pyshell shell.interp.debugger.clear_file_breaks(self) WindowList.unregister_callback(self.postwindowsmenu) From kbk@users.sourceforge.net Thu Jul 11 05:33:43 2002 From: kbk@users.sourceforge.net (Kurt B. Kaiser) Date: Wed, 10 Jul 2002 21:33:43 -0700 Subject: [Idle-dev] CVS: idle EditorWindow.py,1.26,1.27 PyShell.py,1.19,1.20 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv6088 Modified Files: EditorWindow.py PyShell.py Log Message: 1. Prevent Undo before IOmark in PyShell.PyShell 2. Consolidate Undo code in EditorWindow.EditorWindow 3. Remove Formatting and Run menus from PyShell Index: EditorWindow.py =================================================================== RCS file: /cvsroot/idlefork/idle/EditorWindow.py,v retrieving revision 1.26 retrieving revision 1.27 diff -C2 -r1.26 -r1.27 *** EditorWindow.py 6 Jul 2002 04:22:25 -0000 1.26 --- EditorWindow.py 11 Jul 2002 04:33:41 -0000 1.27 *************** *** 152,159 **** self.set_status_bar() - vbar['command'] = text.yview vbar.pack(side=RIGHT, fill=Y) - text['yscrollcommand'] = vbar.set fontWeight='normal' --- 152,157 ---- *************** *** 169,179 **** self.per = per = self.Percolator(text) if self.ispythonsource(filename): ! self.color = color = self.ColorDelegator(); per.insertfilter(color) ##print "Initial colorizer" else: ##print "No initial colorizer" self.color = None ! self.undo = undo = self.UndoDelegator(); per.insertfilter(undo) self.io = io = self.IOBinding(self) #create the Recent Files submenu self.menuRecentFiles=Menu(self.menubar) --- 167,187 ---- self.per = per = self.Percolator(text) if self.ispythonsource(filename): ! self.color = color = self.ColorDelegator() ! per.insertfilter(color) ##print "Initial colorizer" else: ##print "No initial colorizer" self.color = None ! ! self.undo = undo = self.UndoDelegator() ! per.insertfilter(undo) ! text.undo_block_start = undo.undo_block_start ! text.undo_block_stop = undo.undo_block_stop ! undo.set_saved_change_hook(self.saved_change_hook) ! ! # IOBinding implements file I/O and printing functionality self.io = io = self.IOBinding(self) + io.set_filename_change_hook(self.filename_change_hook) + #create the Recent Files submenu self.menuRecentFiles=Menu(self.menubar) *************** *** 182,190 **** self.UpdateRecentFilesList() - text.undo_block_start = undo.undo_block_start - text.undo_block_stop = undo.undo_block_stop - undo.set_saved_change_hook(self.saved_change_hook) - io.set_filename_change_hook(self.filename_change_hook) - if filename: if os.path.exists(filename): --- 190,193 ---- *************** *** 192,196 **** else: io.set_filename(filename) - self.saved_change_hook() --- 195,198 ---- Index: PyShell.py =================================================================== RCS file: /cvsroot/idlefork/idle/PyShell.py,v retrieving revision 1.19 retrieving revision 1.20 diff -C2 -r1.19 -r1.20 *** PyShell.py 26 Jun 2002 02:32:08 -0000 1.19 --- PyShell.py 11 Jul 2002 04:33:41 -0000 1.20 *************** *** 451,457 **** UndoDelegator = ModifiedUndoDelegator ! # Override menu bar specs ! menu_specs = PyShellEditorWindow.menu_specs[:] ! menu_specs.insert(len(menu_specs)-3, ("debug", "_Debug")) # New classes --- 451,463 ---- UndoDelegator = ModifiedUndoDelegator ! # Override menus: Run and Format not desired in shell; add Debug ! menu_specs = [ ! ("file", "_File"), ! ("edit", "_Edit"), ! ("debug", "_Debug"), ! ("settings", "_Settings"), ! ("windows", "_Windows"), ! ("help", "_Help"), ! ] # New classes *************** *** 826,829 **** --- 832,836 ---- self.text.mark_set("insert", "end-1c") self.set_line_and_column() + self.io.reset_undo() def resetoutput(self): From guido@python.org Wed Jul 17 21:35:50 2002 From: guido@python.org (Guido van Rossum) Date: Wed, 17 Jul 2002 16:35:50 -0400 Subject: [Idle-dev] leo.py 3.0 outlining editor Message-ID: <200207172035.g6HKZow13690@odiug.zope.com> It's pretty quiet here. The following announcement may be of interest because it's an app with some similar features as IDLE (e.g. configuration). It also imports IDLE and uses the Python shell, if it can, I believe. Worth looking into? Worth suggesting cooperation or at least exchange of ideas? --Guido van Rossum (home page: http://www.python.org/~guido/) ------- Forwarded Message Date: Tue, 16 Jul 2002 22:30:49 -0000 From: "Edward K. Ream" To: python-announce-list@python.org Subject: ANN: leo.py 3.0 outliing editor leo.py 3.0 is now available at: http://sourceforge.net/projects/leo/ The highlights of 3.0: - ---------------------- - - Support for many user options stored in leoConfig.txt, including options for fonts in all panes and colors for syntax coloring. - - Support for .leo files with XML types like "ISO-8859-1". By default, Leo writes files compatible with all previous versions. - - New Color and Font pickers, fully connected to user options. - - New Toggle Split Direction command, under control of user options. - - Autoscrolling in the outline pane. - - Windows open at the position in which they were saved. - - The size and position of new windows can be controlled with user options. - - Eliminated drawing problems while opening files. - - Improved syntax coloring for @comment plain. - - The Convert All Blanks and Convert All Tabs commands are now undoable. - - Leo warns and aborts if Python 2.2 or above is not running. - - The usual bug fixes and minor improvements. leo.py requires Python 2.2 and tcl/tk 8.3 or above. What is Leo? - ------------ - A programmer's editor, an outlining editor and a flexible browser. - A literate programming tool, compatible with noweb and CWEB. - A data organizer and project manager. Leo provides multiple views of projects within a single outline. - Fully scriptable using Python. Leo saves its files in XML format. - Portable. leo.py is 100% pure Python. - Open Software, distributed under the Python License. Links: - ------ Leo: http://personalpages.tds.net/~edream/front.html Home: http://sourceforge.net/projects/leo/ Download: http://sourceforge.net/project/showfiles.php?group_id=3458 CVS: http://sourceforge.net/cvs/?group_id=3458 Edward K. Ream - -------------------------------------------------------------------- Edward K. Ream email: edream@tds.net Leo: Literate Editor with Outlines Leo: http://personalpages.tds.net/~edream/front.html - -------------------------------------------------------------------- - -- http://mail.python.org/mailman/listinfo/python-announce-list ------- End of Forwarded Message From kbk@shore.net Wed Jul 17 22:49:34 2002 From: kbk@shore.net (Kurt B. Kaiser) Date: 17 Jul 2002 17:49:34 -0400 Subject: [Idle-dev] leo.py 3.0 outlining editor In-Reply-To: <200207172035.g6HKZow13690@odiug.zope.com> References: <200207172035.g6HKZow13690@odiug.zope.com> Message-ID: Guido van Rossum writes: > It's pretty quiet here. The following announcement may be of interest > because it's an app with some similar features as IDLE > (e.g. configuration). It also imports IDLE and uses the Python shell, > if it can, I believe. Worth looking into? Worth suggesting > cooperation or at least exchange of ideas? Leo is an outlining editor with special features tailored for Literate Programming. The latter is an old favorite of mine. It's especially good for C when the algorithms are subtle. Knuth's Stanford Graphbase is an example of extended programming in C, at book length. It's eminently readable, and there's a gem on almost every page. I have yet to see anyone solve the problem of how to do object oriented programming in the Literate style. Maybe Ed's got some ideas or pointers to relevant work. The Leo license is compatible. Regards, KBK From kbk@shore.net Thu Jul 18 00:10:13 2002 From: kbk@shore.net (Kurt B. Kaiser) Date: 17 Jul 2002 19:10:13 -0400 Subject: [Idle-dev] leo.py 3.0 outlining editor In-Reply-To: <200207172035.g6HKZow13690@odiug.zope.com> References: <200207172035.g6HKZow13690@odiug.zope.com> Message-ID: Guido van Rossum writes: > It's pretty quiet here. I'm in the process of reversing the connection between Idle and the Python subprocess. I guess the sound of brains frying doesn't carry well over the net. Regards, KBK From elguavas@python.net Thu Jul 18 00:51:52 2002 From: elguavas@python.net (Stephen M. Gava) Date: 18 Jul 2002 09:51:52 +1000 Subject: [Idle-dev] leo.py 3.0 outlining editor In-Reply-To: <200207172035.g6HKZow13690@odiug.zope.com> References: <200207172035.g6HKZow13690@odiug.zope.com> Message-ID: <1026949912.507.22.camel@oberon> Guido van Rossum wrote: > It's pretty quiet here. Welcome back from your break. For my part I'm in the last few days of some work commitments that I will be oh so glad to finally kiss goodbye, after which I'm gonna take a break which will hopefully include some idleforking time. Also, Raymond did the right thing a couple of weeks back and emailed to let me know that he was going to be 'out of the country' (sic) for a while, but then I didn't do the right thing in notifying you others that we'd be without him for a while. I have been keeping a delighted eye on the recent SPE checkins by Kurt though. :) > The following announcement may be of interest > because it's an app with some similar features as IDLE > (e.g. configuration). It also imports IDLE and uses the Python shell, > if it can, I believe. I've looked at several leo releases and it seems to be very nifty indeed, with some interesting features. > Worth looking into? Worth suggesting > cooperation or at least exchange of ideas? IMO it would be worthwhile if someone took the time to look realistically at the possibility of at least some of the great editing features from leo making it somehow in to idlefork. Edward Ream, the leo author has provided idle patches before, and also read(s) (hopefully still) this list. Edward, if you're listening, how would you feel about some level of cooperation with idlefork, at least for seeing if any cross-pollination between the projects is worthwhile or feasible? Stephen. -- Stephen M. Gava http://python.net/crew/elguavas IDLEfork http://idlefork.sourceforge.net "just like IDLE, only crunchy" From kbk@shore.net Thu Jul 18 17:41:49 2002 From: kbk@shore.net (Kurt B. Kaiser) Date: 18 Jul 2002 12:41:49 -0400 Subject: [Idle-dev] leo.py 3.0 outlining editor In-Reply-To: <200207181151.g6IBpMY26322@pcp02138704pcs.reston01.va.comcast.net> References: <200207172035.g6HKZow13690@odiug.zope.com> <200207181151.g6IBpMY26322@pcp02138704pcs.reston01.va.comcast.net> Message-ID: Guido van Rossum writes: > > > It's pretty quiet here. > > > > I'm in the process of reversing the connection between Idle and the > > Python subprocess. I guess the sound of brains frying doesn't carry > > well over the net. > > I didn't mean it as criticism, sorry! Not at all...it _is_ pretty quiet! > Hope it's going well -- if you need help, let me know. I've got the socket reversed, now PyShell.Modified_Interpreter.spawn_subprocess's poll_subprocess call is flubbing. So now I have to figure out how _that_ works. Let's see...poll_subprocess -> pollresponse -> pollmessage -> pollpacket which is compaining because it's getting zero length data. Hmm. It's mostly grok 100 lines of code, change 1, grok 100.... :) :) Regards, KBK From kbk@users.sourceforge.net Sun Jul 21 02:24:30 2002 From: kbk@users.sourceforge.net (Kurt B. Kaiser) Date: Sat, 20 Jul 2002 18:24:30 -0700 Subject: [Idle-dev] CVS: idle IOBinding.py,1.6,1.7 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv17263 Modified Files: IOBinding.py Log Message: Bug: clearing the shell undo list after a prompt was allowing files to be opened on top of the shell instead of in a new window. Index: IOBinding.py =================================================================== RCS file: /cvsroot/idlefork/idle/IOBinding.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -r1.6 -r1.7 *** IOBinding.py 11 Jun 2002 04:43:58 -0000 1.6 --- IOBinding.py 21 Jul 2002 01:24:28 -0000 1.7 *************** *** 88,95 **** filename=editFile if filename: ! # if the current window has no filename and hasn't been ! # modified, we replace it's contents (no loss). Otherwise ! # we open a new window. ! if not self.filename and self.get_saved(): self.editwin.flist.open(filename, self.loadfile) else: --- 88,101 ---- filename=editFile if filename: ! # If the current window has no filename and hasn't been ! # modified, we replace its contents (no loss). Otherwise ! # we open a new window. But we won't replace the ! # shell window (which has an interp(reter) attribute), which ! # gets set to "not modified" at every new prompt. ! try: ! interp = self.editwin.interp ! except: ! interp = None ! if not self.filename and self.get_saved() and not interp: self.editwin.flist.open(filename, self.loadfile) else: *************** *** 97,102 **** else: self.text.focus_set() - return "break" # Code for use outside IDLE: if self.get_saved(): --- 103,108 ---- else: self.text.focus_set() return "break" + # # Code for use outside IDLE: if self.get_saved(): From elguavas@users.sourceforge.net Mon Jul 22 03:21:11 2002 From: elguavas@users.sourceforge.net (Stephen M. Gava) Date: Sun, 21 Jul 2002 19:21:11 -0700 Subject: [Idle-dev] CVS: idle EditorWindow.py,1.23,1.23.2.1 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv17242 Modified Files: Tag: DS_RPC_BRANCH EditorWindow.py Log Message: Merge autoindent functions into EditorWindow proper, as discussed with GvR. Modify autoindent and new config system indent handling to make user prompting consistent. Index: EditorWindow.py =================================================================== RCS file: /cvsroot/idlefork/idle/EditorWindow.py,v retrieving revision 1.23 retrieving revision 1.23.2.1 diff -C2 -r1.23 -r1.23.2.1 *** EditorWindow.py 22 Apr 2002 00:38:26 -0000 1.23 --- EditorWindow.py 22 Jul 2002 02:21:09 -0000 1.23.2.1 *************** *** 20,23 **** --- 20,24 ---- import GrepDialog import ReplaceDialog + import PyParse #from IdleConf import idleconf from configHandler import idleConf *************** *** 147,150 **** --- 148,163 ---- text.bind("<>", self.goto_line_event) text.bind("<3>", self.right_menu_event) + text.bind("<>",self.smart_backspace_event) + text.bind("<>",self.newline_and_indent_event) + text.bind("<>",self.smart_indent_event) + text.bind("<>",self.indent_region_event) + text.bind("<>",self.dedent_region_event) + text.bind("<>",self.comment_region_event) + text.bind("<>",self.uncomment_region_event) + text.bind("<>",self.tabify_region_event) + text.bind("<>",self.untabify_region_event) + text.bind("<>",self.toggle_tabs_event) + text.bind("<>",self.change_indentwidth_event) + if flist: flist.inversedict[self] = key *************** *** 872,875 **** --- 885,1355 ---- "n" * newtabwidth) text.configure(tabs=pixels) + + ### begin autoindent code ### + + # usetabs true -> literal tab characters are used by indent and + # dedent cmds, possibly mixed with spaces if + # indentwidth is not a multiple of tabwidth + # false -> tab characters are converted to spaces by indent + # and dedent cmds, and ditto TAB keystrokes + # indentwidth is the number of characters per logical indent level. + # tabwidth is the display width of a literal tab character. + # CAUTION: telling Tk to use anything other than its default + # tab setting causes it to use an entirely different tabbing algorithm, + # treating tab stops as fixed distances from the left margin. + # Nobody expects this, so for now tabwidth should never be changed. + usetabs = 0 + indentwidth = 4 + tabwidth = 8 # for IDLE use, must remain 8 until Tk is fixed + + # If context_use_ps1 is true, parsing searches back for a ps1 line; + # else searches for a popular (if, def, ...) Python stmt. + context_use_ps1 = 0 + + # When searching backwards for a reliable place to begin parsing, + # first start num_context_lines[0] lines back, then + # num_context_lines[1] lines back if that didn't work, and so on. + # The last value should be huge (larger than the # of lines in a + # conceivable file). + # Making the initial values larger slows things down more often. + num_context_lines = 50, 500, 5000000 + + def config(self, **options): + for key, value in options.items(): + if key == 'usetabs': + self.usetabs = value + elif key == 'indentwidth': + self.indentwidth = value + elif key == 'tabwidth': + self.tabwidth = value + elif key == 'context_use_ps1': + self.context_use_ps1 = value + else: + raise KeyError, "bad option name: %s" % `key` + + # If ispythonsource and guess are true, guess a good value for + # indentwidth based on file content (if possible), and if + # indentwidth != tabwidth set usetabs false. + # In any case, adjust the Text widget's view of what a tab + # character means. + + def set_indentation_params(self, ispythonsource, guess=1): + if guess and ispythonsource: + i = self.guess_indent() + if 2 <= i <= 8: + self.indentwidth = i + if self.indentwidth != self.tabwidth: + self.usetabs = 0 + + self.set_tabwidth(self.tabwidth) + + def smart_backspace_event(self, event): + text = self.text + first, last = self.get_selection_indices() + if first and last: + text.delete(first, last) + text.mark_set("insert", first) + return "break" + # Delete whitespace left, until hitting a real char or closest + # preceding virtual tab stop. + chars = text.get("insert linestart", "insert") + if chars == '': + if text.compare("insert", ">", "1.0"): + # easy: delete preceding newline + text.delete("insert-1c") + else: + text.bell() # at start of buffer + return "break" + if chars[-1] not in " \t": + # easy: delete preceding real char + text.delete("insert-1c") + return "break" + # Ick. It may require *inserting* spaces if we back up over a + # tab character! This is written to be clear, not fast. + expand, tabwidth = string.expandtabs, self.tabwidth + have = len(expand(chars, tabwidth)) + assert have > 0 + want = ((have - 1) // self.indentwidth) * self.indentwidth + ncharsdeleted = 0 + while 1: + chars = chars[:-1] + ncharsdeleted = ncharsdeleted + 1 + have = len(expand(chars, tabwidth)) + if have <= want or chars[-1] not in " \t": + break + text.undo_block_start() + text.delete("insert-%dc" % ncharsdeleted, "insert") + if have < want: + text.insert("insert", ' ' * (want - have)) + text.undo_block_stop() + return "break" + + def smart_indent_event(self, event): + # if intraline selection: + # delete it + # elif multiline selection: + # do indent-region & return + # indent one level + text = self.text + first, last = self.get_selection_indices() + text.undo_block_start() + try: + if first and last: + if index2line(first) != index2line(last): + return self.indent_region_event(event) + text.delete(first, last) + text.mark_set("insert", first) + prefix = text.get("insert linestart", "insert") + raw, effective = classifyws(prefix, self.tabwidth) + if raw == len(prefix): + # only whitespace to the left + self.reindent_to(effective + self.indentwidth) + else: + if self.usetabs: + pad = '\t' + else: + effective = len(string.expandtabs(prefix, + self.tabwidth)) + n = self.indentwidth + pad = ' ' * (n - effective % n) + text.insert("insert", pad) + text.see("insert") + return "break" + finally: + text.undo_block_stop() + + def newline_and_indent_event(self, event): + text = self.text + first, last = self.get_selection_indices() + text.undo_block_start() + try: + if first and last: + text.delete(first, last) + text.mark_set("insert", first) + line = text.get("insert linestart", "insert") + i, n = 0, len(line) + while i < n and line[i] in " \t": + i = i+1 + if i == n: + # the cursor is in or at leading indentation; just inject + # an empty line at the start + text.insert("insert linestart", '\n') + return "break" + indent = line[:i] + # strip whitespace before insert point + i = 0 + while line and line[-1] in " \t": + line = line[:-1] + i = i+1 + if i: + text.delete("insert - %d chars" % i, "insert") + # strip whitespace after insert point + while text.get("insert") in " \t": + text.delete("insert") + # start new line + text.insert("insert", '\n') + + # adjust indentation for continuations and block + # open/close first need to find the last stmt + lno = index2line(text.index('insert')) + y = PyParse.Parser(self.indentwidth, self.tabwidth) + for context in self.num_context_lines: + startat = max(lno - context, 1) + startatindex = `startat` + ".0" + rawtext = text.get(startatindex, "insert") + y.set_str(rawtext) + bod = y.find_good_parse_start( + self.context_use_ps1, + self._build_char_in_string_func(startatindex)) + if bod is not None or startat == 1: + break + y.set_lo(bod or 0) + c = y.get_continuation_type() + if c != PyParse.C_NONE: + # The current stmt hasn't ended yet. + if c == PyParse.C_STRING: + # inside a string; just mimic the current indent + text.insert("insert", indent) + elif c == PyParse.C_BRACKET: + # line up with the first (if any) element of the + # last open bracket structure; else indent one + # level beyond the indent of the line with the + # last open bracket + self.reindent_to(y.compute_bracket_indent()) + elif c == PyParse.C_BACKSLASH: + # if more than one line in this stmt already, just + # mimic the current indent; else if initial line + # has a start on an assignment stmt, indent to + # beyond leftmost =; else to beyond first chunk of + # non-whitespace on initial line + if y.get_num_lines_in_stmt() > 1: + text.insert("insert", indent) + else: + self.reindent_to(y.compute_backslash_indent()) + else: + assert 0, "bogus continuation type " + `c` + return "break" + + # This line starts a brand new stmt; indent relative to + # indentation of initial line of closest preceding + # interesting stmt. + indent = y.get_base_indent_string() + text.insert("insert", indent) + if y.is_block_opener(): + self.smart_indent_event(event) + elif indent and y.is_block_closer(): + self.smart_backspace_event(event) + return "break" + finally: + text.see("insert") + text.undo_block_stop() + + auto_indent = newline_and_indent_event + + # Our editwin provides a is_char_in_string function that works + # with a Tk text index, but PyParse only knows about offsets into + # a string. This builds a function for PyParse that accepts an + # offset. + + def _build_char_in_string_func(self, startindex): + def inner(offset, _startindex=startindex, + _icis=self.is_char_in_string): + return _icis(_startindex + "+%dc" % offset) + return inner + + def indent_region_event(self, event): + head, tail, chars, lines = self.get_region() + for pos in range(len(lines)): + line = lines[pos] + if line: + raw, effective = classifyws(line, self.tabwidth) + effective = effective + self.indentwidth + lines[pos] = self._make_blanks(effective) + line[raw:] + self.set_region(head, tail, chars, lines) + return "break" + + def dedent_region_event(self, event): + head, tail, chars, lines = self.get_region() + for pos in range(len(lines)): + line = lines[pos] + if line: + raw, effective = classifyws(line, self.tabwidth) + effective = max(effective - self.indentwidth, 0) + lines[pos] = self._make_blanks(effective) + line[raw:] + self.set_region(head, tail, chars, lines) + return "break" + + def comment_region_event(self, event): + head, tail, chars, lines = self.get_region() + for pos in range(len(lines) - 1): + line = lines[pos] + lines[pos] = '##' + line + self.set_region(head, tail, chars, lines) + + def uncomment_region_event(self, event): + head, tail, chars, lines = self.get_region() + for pos in range(len(lines)): + line = lines[pos] + if not line: + continue + if line[:2] == '##': + line = line[2:] + elif line[:1] == '#': + line = line[1:] + lines[pos] = line + self.set_region(head, tail, chars, lines) + + def tabify_region_event(self, event): + head, tail, chars, lines = self.get_region() + tabwidth = self._asktabwidth() + for pos in range(len(lines)): + line = lines[pos] + if line: + raw, effective = classifyws(line, tabwidth) + ntabs, nspaces = divmod(effective, tabwidth) + lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:] + self.set_region(head, tail, chars, lines) + + def untabify_region_event(self, event): + head, tail, chars, lines = self.get_region() + tabwidth = self._asktabwidth() + for pos in range(len(lines)): + lines[pos] = string.expandtabs(lines[pos], tabwidth) + self.set_region(head, tail, chars, lines) + + def toggle_tabs_event(self, event): + if self.askyesno( + "Toggle tabs", + "Turn tabs " + ("on", "off")[self.usetabs] + "?", + parent=self.text): + self.usetabs = not self.usetabs + return "break" + + # XXX this isn't bound to anything -- see class tabwidth comments + def change_tabwidth_event(self, event): + new = self._asktabwidth() + if new != self.tabwidth: + self.tabwidth = new + self.set_indentation_params(0, guess=0) + return "break" + + def change_indentwidth_event(self, event): + new = self.askinteger( + "Indent width", + "New indent width (2-16)", + parent=self.text, + initialvalue=self.indentwidth, + minvalue=2, + maxvalue=16) + if new and new != self.indentwidth: + self.indentwidth = new + return "break" + + def get_region(self): + text = self.text + first, last = self.get_selection_indices() + if first and last: + head = text.index(first + " linestart") + tail = text.index(last + "-1c lineend +1c") + else: + head = text.index("insert linestart") + tail = text.index("insert lineend +1c") + chars = text.get(head, tail) + lines = string.split(chars, "\n") + return head, tail, chars, lines + + def set_region(self, head, tail, chars, lines): + text = self.text + newchars = string.join(lines, "\n") + if newchars == chars: + text.bell() + return + text.tag_remove("sel", "1.0", "end") + text.mark_set("insert", head) + text.undo_block_start() + text.delete(head, tail) + text.insert(head, newchars) + text.undo_block_stop() + text.tag_add("sel", head, "insert") + + # Make string that displays as n leading blanks. + + def _make_blanks(self, n): + if self.usetabs: + ntabs, nspaces = divmod(n, self.tabwidth) + return '\t' * ntabs + ' ' * nspaces + else: + return ' ' * n + + # Delete from beginning of line to insert point, then reinsert + # column logical (meaning use tabs if appropriate) spaces. + + def reindent_to(self, column): + text = self.text + text.undo_block_start() + if text.compare("insert linestart", "!=", "insert"): + text.delete("insert linestart", "insert") + if column: + text.insert("insert", self._make_blanks(column)) + text.undo_block_stop() + + def _asktabwidth(self): + return self.askinteger( + "Tab width", + "Spaces per tab? (2-16)", + parent=self.text, + initialvalue=self.indentwidth, + minvalue=2, + maxvalue=16) or self.tabwidth + + # Guess indentwidth from text content. + # Return guessed indentwidth. This should not be believed unless + # it's in a reasonable range (e.g., it will be 0 if no indented + # blocks are found). + + def guess_indent(self): + opener, indented = IndentSearcher(self.text, self.tabwidth).run() + if opener and indented: + raw, indentsmall = classifyws(opener, self.tabwidth) + raw, indentlarge = classifyws(indented, self.tabwidth) + else: + indentsmall = indentlarge = 0 + return indentlarge - indentsmall + + # "line.col" -> line, as an int + def index2line(index): + return int(float(index)) + + # Look at the leading whitespace in s. + # Return pair (# of leading ws characters, + # effective # of leading blanks after expanding + # tabs to width tabwidth) + + def classifyws(s, tabwidth): + raw = effective = 0 + for ch in s: + if ch == ' ': + raw = raw + 1 + effective = effective + 1 + elif ch == '\t': + raw = raw + 1 + effective = (effective // tabwidth + 1) * tabwidth + else: + break + return raw, effective + + import tokenize + _tokenize = tokenize + del tokenize + + class IndentSearcher: + + # .run() chews over the Text widget, looking for a block opener + # and the stmt following it. Returns a pair, + # (line containing block opener, line containing stmt) + # Either or both may be None. + + def __init__(self, text, tabwidth): + self.text = text + self.tabwidth = tabwidth + self.i = self.finished = 0 + self.blkopenline = self.indentedline = None + + def readline(self): + if self.finished: + return "" + i = self.i = self.i + 1 + mark = `i` + ".0" + if self.text.compare(mark, ">=", "end"): + return "" + return self.text.get(mark, mark + " lineend+1c") + + def tokeneater(self, type, token, start, end, line, + INDENT=_tokenize.INDENT, + NAME=_tokenize.NAME, + OPENERS=('class', 'def', 'for', 'if', 'try', 'while')): + if self.finished: + pass + elif type == NAME and token in OPENERS: + self.blkopenline = line + elif type == INDENT and self.blkopenline: + self.indentedline = line + self.finished = 1 + + def run(self): + save_tabsize = _tokenize.tabsize + _tokenize.tabsize = self.tabwidth + try: + try: + _tokenize.tokenize(self.readline, self.tokeneater) + except _tokenize.TokenError: + # since we cut off the tokenizer early, we can trigger + # spurious errors + pass + finally: + _tokenize.tabsize = save_tabsize + return self.blkopenline, self.indentedline + + ### end autoindent code ### def prepstr(s): From elguavas@users.sourceforge.net Mon Jul 22 03:23:04 2002 From: elguavas@users.sourceforge.net (Stephen M. Gava) Date: Sun, 21 Jul 2002 19:23:04 -0700 Subject: [Idle-dev] CVS: idle configHandler.py,1.22,1.22.2.1 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv17720 Modified Files: Tag: DS_RPC_BRANCH configHandler.py Log Message: Modify autoindent and new config system indent handling to make user prompting consistent. Index: configHandler.py =================================================================== RCS file: /cvsroot/idlefork/idle/configHandler.py,v retrieving revision 1.22 retrieving revision 1.22.2.1 diff -C2 -r1.22 -r1.22.2.1 *** configHandler.py 2 Mar 2002 07:12:54 -0000 1.22 --- configHandler.py 22 Jul 2002 02:23:01 -0000 1.22.2.1 *************** *** 521,525 **** '<>': [''], '<>': [''], ! '<>': [''] } if keySetName: for event in keyBindings.keys(): --- 521,537 ---- '<>': [''], '<>': [''], ! '<>': [''], ! '<>': [''], ! '<>': [' '], ! '<>': [''], ! '<>': [''], ! '<>': [''], ! '<>': [''], ! '<>': [''], ! '<>': [''], ! '<>': [''], ! '<>': [''], ! '<>': [''] ! } if keySetName: for event in keyBindings.keys(): From elguavas@users.sourceforge.net Mon Jul 22 03:24:36 2002 From: elguavas@users.sourceforge.net (Stephen M. Gava) Date: Sun, 21 Jul 2002 19:24:36 -0700 Subject: [Idle-dev] CVS: idle configDialog.py,1.46,1.46.2.1 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv18102 Modified Files: Tag: DS_RPC_BRANCH configDialog.py Log Message: Modify autoindent and new config system indent handling to make user prompting consistent. Index: configDialog.py =================================================================== RCS file: /cvsroot/idlefork/idle/configDialog.py,v retrieving revision 1.46 retrieving revision 1.46.2.1 diff -C2 -r1.46 -r1.46.2.1 *** configDialog.py 27 Mar 2002 08:40:46 -0000 1.46 --- configDialog.py 22 Jul 2002 02:24:34 -0000 1.46.2.1 *************** *** 126,132 **** text='Choose indentation size :') labelSpaceNumTitle=Label(frameIndentSize,justify=LEFT, ! text='when tab key inserts spaces,\nspaces per indent') self.scaleSpaceNum=Scale(frameIndentSize,variable=self.spaceNum, ! orient='horizontal',tickinterval=2,from_=2,to=10) #labeltabColsTitle=Label(frameIndentSize,justify=LEFT, # text='when tab key inserts tabs,\ncolumns per tab') --- 126,132 ---- text='Choose indentation size :') labelSpaceNumTitle=Label(frameIndentSize,justify=LEFT, ! text='indent width') self.scaleSpaceNum=Scale(frameIndentSize,variable=self.spaceNum, ! orient='horizontal',tickinterval=2,from_=2,to=16) #labeltabColsTitle=Label(frameIndentSize,justify=LEFT, # text='when tab key inserts tabs,\ncolumns per tab') From elguavas@users.sourceforge.net Mon Jul 22 03:26:06 2002 From: elguavas@users.sourceforge.net (Stephen M. Gava) Date: Sun, 21 Jul 2002 19:26:06 -0700 Subject: [Idle-dev] CVS: idle Bindings.py,1.9,1.9.2.1 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv18519 Modified Files: Tag: DS_RPC_BRANCH Bindings.py Log Message: Changes to support autoindent to core idlefork merge. Index: Bindings.py =================================================================== RCS file: /cvsroot/idlefork/idle/Bindings.py,v retrieving revision 1.9 retrieving revision 1.9.2.1 diff -C2 -r1.9 -r1.9.2.1 *** Bindings.py 18 Feb 2002 01:45:43 -0000 1.9 --- Bindings.py 22 Jul 2002 02:26:04 -0000 1.9.2.1 *************** *** 50,53 **** --- 50,63 ---- ('Go to _line', '<>'), ]), + ('format', [ + ('_Indent region', '<>'), + ('_Dedent region', '<>'), + ('Comment _out region', '<>'), + ('U_ncomment region', '<>'), + ('Tabify region', '<>'), + ('Untabify region', '<>'), + ('Toggle tabs', '<>'), + ('New indent width', '<>'), + ]), ('run',[ ('Python shell', '<>'), From elguavas@users.sourceforge.net Mon Jul 22 03:27:05 2002 From: elguavas@users.sourceforge.net (Stephen M. Gava) Date: Sun, 21 Jul 2002 19:27:05 -0700 Subject: [Idle-dev] CVS: idle config-extensions.def,1.5,1.5.2.1 config-keys.def,1.9,1.9.2.1 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv18772 Modified Files: Tag: DS_RPC_BRANCH config-extensions.def config-keys.def Log Message: Changes to support autoindent to core idlefork merge. Index: config-extensions.def =================================================================== RCS file: /cvsroot/idlefork/idle/config-extensions.def,v retrieving revision 1.5 retrieving revision 1.5.2.1 diff -C2 -r1.5 -r1.5.2.1 *** config-extensions.def 11 Feb 2002 03:45:22 -0000 1.5 --- config-extensions.def 22 Jul 2002 02:27:03 -0000 1.5.2.1 *************** *** 18,36 **** format-paragraph= - [AutoIndent] - enable=1 - [AutoIndent_cfgBindings] - smart-backspace= - newline-and-indent= - smart-indent= - indent-region= - dedent-region= - comment-region= - uncomment-region= - tabify-region= - untabify-region= - toggle-tabs= - change-indentwidth= - [AutoExpand] enable=1 --- 18,21 ---- *************** *** 48,58 **** run-complete-script= stop-execution= - - #[ScriptBinding] #currently ExecBinding has replaced ScriptBinding - #enable=0 - #[ScriptBinding_cfgBindings] - #run-script= - #check-module= - #import-module= [CallTips] --- 33,36 ---- Index: config-keys.def =================================================================== RCS file: /cvsroot/idlefork/idle/config-keys.def,v retrieving revision 1.9 retrieving revision 1.9.2.1 diff -C2 -r1.9 -r1.9.2.1 *** config-keys.def 27 Mar 2002 02:25:44 -0000 1.9 --- config-keys.def 22 Jul 2002 02:27:03 -0000 1.9.2.1 *************** *** 41,44 **** --- 41,55 ---- replace= goto-line= + smart-backspace= + newline-and-indent= + smart-indent= + indent-region= + dedent-region= + comment-region= + uncomment-region= + tabify-region= + untabify-region= + toggle-tabs= + change-indentwidth= [IDLE Classic Unix] *************** *** 76,77 **** --- 87,99 ---- replace= goto-line= + smart-backspace= + newline-and-indent= + smart-indent= + indent-region= + dedent-region= + comment-region= + uncomment-region= + tabify-region= + untabify-region= + toggle-tabs= + change-indentwidth= From elguavas@users.sourceforge.net Mon Jul 22 04:05:16 2002 From: elguavas@users.sourceforge.net (Stephen M. Gava) Date: Sun, 21 Jul 2002 20:05:16 -0700 Subject: [Idle-dev] CVS: idle AutoIndent.py,1.5,NONE Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv26541 Removed Files: Tag: DS_RPC_BRANCH AutoIndent.py Log Message: move this into the attic now --- AutoIndent.py DELETED --- From elguavas@users.sourceforge.net Mon Jul 22 04:06:03 2002 From: elguavas@users.sourceforge.net (Stephen M. Gava) Date: Sun, 21 Jul 2002 20:06:03 -0700 Subject: [Idle-dev] CVS: idle EditorWindow.py,1.23.2.1,1.23.2.2 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv26644 Modified Files: Tag: DS_RPC_BRANCH EditorWindow.py Log Message: disable some debug messages Index: EditorWindow.py =================================================================== RCS file: /cvsroot/idlefork/idle/EditorWindow.py,v retrieving revision 1.23.2.1 retrieving revision 1.23.2.2 diff -C2 -r1.23.2.1 -r1.23.2.2 *** EditorWindow.py 22 Jul 2002 02:21:09 -0000 1.23.2.1 --- EditorWindow.py 22 Jul 2002 03:06:01 -0000 1.23.2.2 *************** *** 598,603 **** rfList.insert(0,newFile) rfList=self.__CleanRecentFiles(rfList) ! print self.top.instanceDict ! print self if rfList: for instance in self.top.instanceDict.keys(): --- 598,603 ---- rfList.insert(0,newFile) rfList=self.__CleanRecentFiles(rfList) ! #print self.top.instanceDict ! #print self if rfList: for instance in self.top.instanceDict.keys(): *************** *** 715,719 **** def _close(self): ! print self.io.filename if self.io.filename: self.UpdateRecentFilesList(newFile=self.io.filename) --- 715,719 ---- def _close(self): ! #print self.io.filename if self.io.filename: self.UpdateRecentFilesList(newFile=self.io.filename) From elguavas@users.sourceforge.net Mon Jul 22 04:09:52 2002 From: elguavas@users.sourceforge.net (Stephen M. Gava) Date: Sun, 21 Jul 2002 20:09:52 -0700 Subject: [Idle-dev] CVS: idle idlever.py,1.5,1.5.2.1 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv27394 Modified Files: Tag: DS_RPC_BRANCH idlever.py Log Message: bump this an amount suitable for reflecting the _major_ changes and improvements coming in the next release Index: idlever.py =================================================================== RCS file: /cvsroot/idlefork/idle/idlever.py,v retrieving revision 1.5 retrieving revision 1.5.2.1 diff -C2 -r1.5 -r1.5.2.1 *** idlever.py 31 Jul 2001 07:00:39 -0000 1.5 --- idlever.py 22 Jul 2002 03:09:50 -0000 1.5.2.1 *************** *** 1 **** ! IDLE_VERSION = "0.8.2" --- 1 ---- ! IDLE_VERSION = "0.9.1" From elguavas@users.sourceforge.net Thu Jul 25 00:34:29 2002 From: elguavas@users.sourceforge.net (Stephen M. Gava) Date: Wed, 24 Jul 2002 16:34:29 -0700 Subject: [Idle-dev] CVS: idle ReplaceDialog.py,1.3,1.3.2.1 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv9310 Modified Files: Tag: DS_RPC_BRANCH ReplaceDialog.py Log Message: tracking python idle: merge guido's changes to search/replace Index: ReplaceDialog.py =================================================================== RCS file: /cvsroot/idlefork/idle/ReplaceDialog.py,v retrieving revision 1.3 retrieving revision 1.3.2.1 diff -C2 -r1.3 -r1.3.2.1 *** ReplaceDialog.py 12 Jul 2001 06:54:16 -0000 1.3 --- ReplaceDialog.py 24 Jul 2002 23:34:27 -0000 1.3.2.1 *************** *** 91,95 **** chars = text.get("%d.0" % line, "%d.0" % (line+1)) orig = m.group() ! new = self._expand(m, repl) i, j = m.span() first = "%d.%d" % (line, i) --- 91,95 ---- chars = text.get("%d.0" % line, "%d.0" % (line+1)) orig = m.group() ! new = m.expand(repl) i, j = m.span() first = "%d.%d" % (line, i) *************** *** 143,147 **** if not prog: return 0 ! new = self._expand(m, self.replvar.get()) text.mark_set("insert", first) text.undo_block_start() --- 143,147 ---- if not prog: return 0 ! new = m.expand(self.replvar.get()) text.mark_set("insert", first) text.undo_block_start() *************** *** 154,173 **** self.ok = 0 return 1 - - def _expand(self, m, template): - # XXX This code depends on internals of the regular expression - # engine! There's no standard API to do a substitution when you - # have already found the match. One should be added. - # The solution here is designed to be backwards compatible - # with previous Python versions, e.g. 1.5.2. - # XXX This dynamic test should be done only once. - if getattr(re, "engine", "pre") == "pre": - return re.pcre_expand(m, template) - else: # sre - # XXX This import should be avoidable... - import sre_parse - # XXX This parses the template over and over... - ptemplate = sre_parse.parse_template(template, m.re) - return sre_parse.expand_template(ptemplate, m) def show_hit(self, first, last): --- 154,157 ---- From elguavas@users.sourceforge.net Thu Jul 25 00:44:05 2002 From: elguavas@users.sourceforge.net (Stephen M. Gava) Date: Wed, 24 Jul 2002 16:44:05 -0700 Subject: [Idle-dev] CVS: idle EditorWindow.py,1.23.2.2,1.23.2.3 PyShell.py,1.13.2.1,1.13.2.2 ScriptBinding.py,1.4,1.4.2.1 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv13689 Modified Files: Tag: DS_RPC_BRANCH EditorWindow.py PyShell.py ScriptBinding.py Log Message: tracking python idle: merge changes for python idle patch 543222 - disable script bindings in shell window Index: EditorWindow.py =================================================================== RCS file: /cvsroot/idlefork/idle/EditorWindow.py,v retrieving revision 1.23.2.2 retrieving revision 1.23.2.3 diff -C2 -r1.23.2.2 -r1.23.2.3 *** EditorWindow.py 22 Jul 2002 03:06:01 -0000 1.23.2.2 --- EditorWindow.py 24 Jul 2002 23:44:02 -0000 1.23.2.3 *************** *** 94,97 **** --- 94,98 ---- vars = {} + runnable = False # Shell window cannot Import Module or Run Script def __init__(self, flist=None, filename=None, key=None, root=None): Index: PyShell.py =================================================================== RCS file: /cvsroot/idlefork/idle/PyShell.py,v retrieving revision 1.13.2.1 retrieving revision 1.13.2.2 diff -C2 -r1.13.2.1 -r1.13.2.2 *** PyShell.py 6 Jun 2002 03:15:53 -0000 1.13.2.1 --- PyShell.py 24 Jul 2002 23:44:02 -0000 1.13.2.2 *************** *** 98,102 **** # Regular text edit window when a shell is present # XXX ought to merge with regular editor window ! def __init__(self, *args): apply(EditorWindow.__init__, (self,) + args) --- 98,103 ---- # Regular text edit window when a shell is present # XXX ought to merge with regular editor window ! runnable = True # Shell not present, enable Import Module and Run Script ! def __init__(self, *args): apply(EditorWindow.__init__, (self,) + args) Index: ScriptBinding.py =================================================================== RCS file: /cvsroot/idlefork/idle/ScriptBinding.py,v retrieving revision 1.4 retrieving revision 1.4.2.1 diff -C2 -r1.4 -r1.4.2.1 *** ScriptBinding.py 19 Jan 2002 10:41:51 -0000 1.4 --- ScriptBinding.py 24 Jul 2002 23:44:02 -0000 1.4.2.1 *************** *** 46,49 **** --- 46,52 ---- def __init__(self, editwin): + if not editwin.runnable: + self.menudefs = [] + self.keydefs = {} self.editwin = editwin # Provide instance variables referenced by Debugger From elguavas@python.net Thu Jul 25 01:51:26 2002 From: elguavas@python.net (Stephen M. Gava) Date: 25 Jul 2002 10:51:26 +1000 Subject: [Idle-dev] massive cruftectomy Message-ID: <1027558287.10870.24.camel@oberon> Greetings idleforkers everywhere. As part of belting the idlefork code into shape for the upcoming series of testing releases, I'm currently carrying out some refactoring with one major aim being the removal of a lot of the no longer used modules that idlefork has accumulated during the course of it's existence (in fact, a certain amount of this dead wood seems to have been inherited directly from idle). This has left me with three categories of 'modules under suspicion'. The first category comprises those modules that I know for a fact serve no useful purpose in idlefork today and that I am about to excise with glee (like eventparse.py and all its hundreds of crufty "binding comments" that I can't wait to clean out of the source). The second category comprises a few modules relating to the old configuration backend that I need to remove the final dependencies on from the current code so that the old config backend can be finally fully retired. The third category is the biggest one, and the one I'd like to request comments on from you, dear readers. This last group of modules seem to all no longer fulfill any useful role in idlefork (if indeed some of them ever did). I can't find any part of idlefork as it currently stands that imports or uses any of these modules in any way, but before I move them into the cvs attic I'd like to list them here in case anyone with perhaps a better historical perspective on the codebase can suggest why they need to be retained; or in case I'm simply mistaken about any of these modules being dead wood. The modules in question are: FrameViewer.py, loader.py, MultiScrolledLists.py, Remote.py, RemoteInterp.py, Separator.py, and ToolTip.py . If you've had any connection with idlefork or idle in the past please cast an eye over that list and let me know if you think any of those modules still need to be in idlefork. Thanks, Stephen. -- Stephen M. Gava IDLEfork http://idlefork.sourceforge.net "just like IDLE, only crunchy" From kbk@users.sourceforge.net Fri Jul 26 01:06:45 2002 From: kbk@users.sourceforge.net (Kurt B. Kaiser) Date: Thu, 25 Jul 2002 17:06:45 -0700 Subject: [Idle-dev] CVS: idle PyShell.py,1.20,1.21 rpc.py,1.3,1.4 run.py,1.3,1.4 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv13932 Modified Files: PyShell.py rpc.py run.py Log Message: Reverse the RPC socket connection: Python execution server connects to Idle client and localhost origin of connection is verified by client. M PyShell.py M rpc.py M run.py Index: PyShell.py =================================================================== RCS file: /cvsroot/idlefork/idle/PyShell.py,v retrieving revision 1.20 retrieving revision 1.21 diff -C2 -r1.20 -r1.21 *** PyShell.py 11 Jul 2002 04:33:41 -0000 1.20 --- PyShell.py 26 Jul 2002 00:06:41 -0000 1.21 *************** *** 194,202 **** port = 8833 addr = ("localhost", port) w = ['-W' + s for s in sys.warnoptions] args = [sys.executable] + w + ["-c", "__import__('run').main()", str(port)] self.rpcpid = os.spawnv(os.P_NOWAIT, args[0], args) ! for i in range(5): time.sleep(i) try: --- 194,206 ---- port = 8833 addr = ("localhost", port) + # Spawn the Python execution "server" w = ['-W' + s for s in sys.warnoptions] args = [sys.executable] + w + ["-c", "__import__('run').main()", str(port)] self.rpcpid = os.spawnv(os.P_NOWAIT, args[0], args) ! # Idle starts listening for connection on localhost, retry since ! # Idle may be restarted before port is available for rebinding ! # XXX 25 July 2002 KBK Find out what is causing the delayed release! ! for i in range(12): time.sleep(i) try: *************** *** 204,215 **** break except socket.error, err: ! if i > 3: ! print >>sys.__stderr__, "Socket error:", err, "; retry..." else: - # XXX Make this a dialog? #GvR - print >>sys.__stderr__, "Can't spawn subprocess!" - # XXX Add Stephen's error msg, resolve the two later... KBK 09Jun02 display_port_binding_error() return self.rpcclt.register("stdin", self.tkconsole) self.rpcclt.register("stdout", self.tkconsole.stdout) --- 208,221 ---- break except socket.error, err: ! if i < 5: ! print>>sys.__stderr__, ". ", ! else: ! print>>sys.__stderr__,"\nIdle socket error: " + err[1]\ ! + ", retrying..." else: display_port_binding_error() return + # Accept the connection from the Python execution server + self.rpcclt.accept() self.rpcclt.register("stdin", self.tkconsole) self.rpcclt.register("stdout", self.tkconsole.stdout) Index: rpc.py =================================================================== RCS file: /cvsroot/idlefork/idle/rpc.py,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -r1.3 -r1.4 *** rpc.py 26 Jun 2002 02:32:09 -0000 1.3 --- rpc.py 26 Jul 2002 00:06:41 -0000 1.4 *************** *** 1,21 **** ! # ASCII-art documentation ! # ! # +---------------------------------+ +----------+ ! # | SocketServer.BaseRequestHandler | | SocketIO | ! # +---------------------------------+ +----------+ ! # ^ ^ ^ ! # | | | ! # | + -------------------+ | ! # | | | ! # +-------------------------+ +-----------------+ ! # | RPCHandler | | RPCClient | ! # |-------------------------| |-----------------| ! # | register() | | remotecall() | ! # | unregister() | | register() | ! # | | | unregister() | ! # | | | get_remote_proxy| ! # +-------------------------+ +-----------------+ ! # ! import sys import socket import select --- 1,32 ---- ! """RPC Implemention, originally written for the Python Idle IDE ! ! For security reasons, GvR requested that Idle's Python execution server process ! connect to the Idle process, which listens for the connection. Since Idle has ! has only one client per server, this was not a limitation. ! ! +---------------------------------+ +-------------+ ! | SocketServer.BaseRequestHandler | | SocketIO | ! +---------------------------------+ +-------------+ ! ^ | register() | ! | | unregister()| ! | +-------------+ ! | ^ ^ ! | | | ! | + -------------------+ | ! | | | ! +-------------------------+ +-----------------+ ! | RPCHandler | | RPCClient | ! | [attribute of RPCServer]| | | ! +-------------------------+ +-----------------+ ! ! The RPCServer handler class is expected to provide register/unregister methods. ! RPCHandler inherits the mix-in class SocketIO, which provides these methods. ! ! See the Idle run.main() docstring for further information on how this was ! accomplished in Idle. ! ! """ ! ! import sys import socket import select *************** *** 56,93 **** if handlerclass is None: handlerclass = RPCHandler ! # XXX KBK 25Jun02 Not used in Idlefork, see register/unregister note below. # self.objtable = objecttable SocketServer.TCPServer.__init__(self, addr, handlerclass) ! # XXX KBK 25Jun02 Following method is not used (yet) ! # def verify_request(self, request, client_address): ! # host, port = client_address ! # if host != "127.0.0.1": ! # print "Disallowed host:", host ! # return 0 ! # else: ! # return 1 ! ! # XXX KBK 25Jun02 The handlerclass is expected to provide register/unregister ! # methods. In Idle, RPCServer is instantiated with ! # handlerclass MyHandler, which in turn inherits the ! # register/unregister methods from the mix-in class SocketIO. ! # It is true that this is asymmetric with the RPCClient's use ! # of register/unregister, but I guess that's how a SocketServer ! # is supposed to work. ! ! # Exactly how this gets set up is convoluted. When the ! # TCPServer is instantiated, it creates an instance of ! # run.MyHandler and calls its handle() method. handle() ! # instantiates a run.Executive, passing it a reference to the ! # MyHandler object. That reference is saved as an attribute of ! # the Executive instance. The Executive methods have access to ! # the reference and can pass it on to entities that they ! # command (e.g. RemoteDebugger.Debugger.start_debugger()). The ! # latter, in turn, can call MyHandler(SocketIO) ! # register/unregister methods via the reference to register and ! # unregister themselves. Whew. ! # The following two methods are not currently used in Idlefork. # def register(self, oid, object): # self.objtable[oid] = object --- 67,93 ---- if handlerclass is None: handlerclass = RPCHandler ! # XXX KBK 25Jun02 Not used in Idlefork. # self.objtable = objecttable SocketServer.TCPServer.__init__(self, addr, handlerclass) ! def server_bind(self): ! "Override TCPServer method, no bind() phase for connecting entity" ! pass ! ! def server_activate(self): ! """Override TCPServer method, connect() instead of listen() ! ! Due to the reversed connection, self.server_address is actually the ! address of the Idle Client to which we are connecting. ! ! """ ! self.socket.connect(self.server_address) ! ! def get_request(self): ! "Override TCPServer method, return already connected socket" ! return self.socket, self.server_address ! ! # XXX The following two methods are not currently used in Idlefork. # def register(self, oid, object): # self.objtable[oid] = object *************** *** 365,368 **** --- 365,370 ---- self.statelock.release() continue + + #----------------- end class SocketIO -------------------- class RemoteObject: *************** *** 389,401 **** SocketServer.BaseRequestHandler.__init__(self, sock, addr, svr) - def setup(self): - SocketServer.BaseRequestHandler.setup(self) - print >>sys.__stderr__, "Connection from", self.client_address - - def finish(self): - print >>sys.__stderr__, "End connection from", self.client_address - SocketServer.BaseRequestHandler.finish(self) - def handle(self): self.mainloop() --- 391,396 ---- SocketServer.BaseRequestHandler.__init__(self, sock, addr, svr) def handle(self): + "handle() method required by SocketServer" self.mainloop() *************** *** 405,414 **** class RPCClient(SocketIO): ! nextseq = 1 # Requests coming from the client are odd def __init__(self, address, family=socket.AF_INET, type=socket.SOCK_STREAM): ! sock = socket.socket(family, type) ! sock.connect(address) ! SocketIO.__init__(self, sock) def get_remote_proxy(self, oid): --- 400,418 ---- class RPCClient(SocketIO): ! nextseq = 1 # Requests coming from the client are odd numbered def __init__(self, address, family=socket.AF_INET, type=socket.SOCK_STREAM): ! self.sock = socket.socket(family, type) ! self.sock.bind(address) ! self.sock.listen(1) ! ! def accept(self): ! newsock, address = self.sock.accept() ! if address[0] == '127.0.0.1': ! print>>sys.__stderr__, "Idle accepted connection from ", address ! SocketIO.__init__(self, newsock) ! else: ! print>>sys.__stderr__, "Invalid host: ", address ! raise socket.error def get_remote_proxy(self, oid): *************** *** 478,481 **** --- 482,486 ---- def testServer(addr): + # XXX 25 Jul 02 KBK needs update to use rpc.py register/unregister methods class RemotePerson: def __init__(self,name): *************** *** 506,513 **** def testClient(addr): ! ! # ! # demonstrates RPC Client ! # import time clt=RPCClient(addr) --- 511,516 ---- def testClient(addr): ! "demonstrates RPC Client" ! # XXX 25 Jul 02 KBK needs update to use rpc.py register/unregister methods import time clt=RPCClient(addr) *************** *** 524,528 **** print time.sleep(2) - # demonstrates remote server calling local instance class LocalPerson: --- 527,530 ---- Index: run.py =================================================================== RCS file: /cvsroot/idlefork/idle/run.py,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -r1.3 -r1.4 *** run.py 26 Jun 2002 02:32:09 -0000 1.3 --- run.py 26 Jul 2002 00:06:42 -0000 1.4 *************** *** 1,6 **** --- 1,24 ---- import sys + import time + import socket import rpc def main(): + """Start the Python execution server in a subprocess + + In Idle, RPCServer is instantiated with handlerclass MyHandler, which + inherits register/unregister methods from RPCHandler via the mix-in class + SocketIO. + + When the RPCServer is instantiated, the TCPServer initialization creates an + instance of run.MyHandler and calls its handle() method. handle() + instantiates a run.Executive, passing it a reference to the MyHandler + object. That reference is saved as an attribute of the Executive instance. + The Executive methods have access to the reference and can pass it on to + entities that they command (e.g. RemoteDebugger.Debugger.start_debugger()). + The latter, in turn, can call MyHandler(SocketIO) register/unregister + methods via the reference to register and unregister themselves. + + """ port = 8833 if sys.argv[1:]: *************** *** 8,12 **** sys.argv[:] = [""] addr = ("localhost", port) ! svr = rpc.RPCServer(addr, MyHandler) svr.handle_request() # A single request only --- 26,43 ---- sys.argv[:] = [""] addr = ("localhost", port) ! for i in range(12): ! time.sleep(i) ! try: ! svr = rpc.RPCServer(addr, MyHandler) ! break ! except socket.error, err: ! if i < 5: ! print>>sys.__stderr__, ".. ", ! else: ! print>>sys.__stderr__,"\nPython subprocess socket error: "\ ! + err[1] + ", retrying...." ! else: ! print>>sys.__stderr__, "\nConnection to Idle failed, exiting." ! sys.exit() svr.handle_request() # A single request only From kbk@users.sourceforge.net Sun Jul 28 04:35:33 2002 From: kbk@users.sourceforge.net (Kurt B. Kaiser) Date: Sat, 27 Jul 2002 20:35:33 -0700 Subject: [Idle-dev] CVS: idle run.py,1.4,1.5 ScriptBinding.py,1.6,1.7 Message-ID: Update of /cvsroot/idlefork/idle In directory usw-pr-cvs1:/tmp/cvs-serv18267 Modified Files: run.py ScriptBinding.py Log Message: Reset the Python execution server environment to its initial value prior to executing Run/F5 from an EditorWindow. M ScriptBinding.py : add call to clear_the_environment() M run.py : implemented Executive.clear_the_environment() Index: run.py =================================================================== RCS file: /cvsroot/idlefork/idle/run.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -r1.4 -r1.5 *** run.py 26 Jul 2002 00:06:42 -0000 1.4 --- run.py 28 Jul 2002 03:35:31 -0000 1.5 *************** *** 2,5 **** --- 2,6 ---- import time import socket + import __main__ import rpc *************** *** 56,64 **** def __init__(self, rpchandler): self.rpchandler = rpchandler ! import __main__ ! self.locals = __main__.__dict__ def runcode(self, code): ! exec code in self.locals def start_the_debugger(self, gui_adap_oid): --- 57,72 ---- def __init__(self, rpchandler): self.rpchandler = rpchandler ! self.base_env_keys = __main__.__dict__.keys() def runcode(self, code): ! exec code in __main__.__dict__ ! ! def clear_the_environment(self): ! global __main__ ! env = __main__.__dict__ ! for key in env.keys(): ! if key not in self.base_env_keys: ! del env[key] ! env['__doc__'] = None def start_the_debugger(self, gui_adap_oid): Index: ScriptBinding.py =================================================================== RCS file: /cvsroot/idlefork/idle/ScriptBinding.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -r1.6 -r1.7 *** ScriptBinding.py 12 Jun 2002 03:28:57 -0000 1.6 --- ScriptBinding.py 28 Jul 2002 03:35:31 -0000 1.7 *************** *** 145,152 **** if not filename: return - flist = self.editwin.flist shell = flist.open_shell() interp = shell.interp # XXX Too often this discards arguments the user just set... interp.runcommand("""if 1: --- 145,153 ---- if not filename: return flist = self.editwin.flist shell = flist.open_shell() interp = shell.interp + # clear the subprocess environment before every Run/F5 invocation + interp.rpcclt.remotecall("exec", "clear_the_environment", (), {}) # XXX Too often this discards arguments the user just set... interp.runcommand("""if 1: *************** *** 156,159 **** --- 157,161 ---- if (not _sys.argv or _basename(_sys.argv[0]) != _basename(_filename)): + # XXX 25 July 2002 KBK should this be sys.argv not _sys.argv? _sys.argv = [_filename] del _filename, _sys, _basename From gvanrossum@comcast.net Sun Jul 28 20:47:35 2002 From: gvanrossum@comcast.net (gvanrossum@comcast.net) Date: Sun, 28 Jul 2002 15:47:35 -0400 Subject: [Idle-dev] massive cruftectomy References: <1027558287.10870.24.camel@oberon> Message-ID: <012701c2366f$a20e2160$0b01000a@reston01.va.comcast.net> > Greetings idleforkers everywhere. > > As part of belting the idlefork code into shape for the upcoming series > of testing releases, I'm currently carrying out some refactoring with > one major aim being the removal of a lot of the no longer used modules > that idlefork has accumulated during the course of it's existence (in > fact, a certain amount of this dead wood seems to have been inherited > directly from idle). > > This has left me with three categories of 'modules under suspicion'. The > first category comprises those modules that I know for a fact serve no > useful purpose in idlefork today and that I am about to excise with glee > (like eventparse.py and all its hundreds of crufty "binding comments" > that I can't wait to clean out of the source). Yup. Glad to see it go. > The second category > comprises a few modules relating to the old configuration backend that I > need to remove the final dependencies on from the current code so that > the old config backend can be finally fully retired. The third category > is the biggest one, and the one I'd like to request comments on from > you, dear readers. > > This last group of modules seem to all no longer fulfill any useful role > in idlefork (if indeed some of them ever did). I can't find any part of > idlefork as it currently stands that imports or uses any of these > modules in any way, but before I move them into the cvs attic I'd like > to list them here in case anyone with perhaps a better historical > perspective on the codebase can suggest why they need to be retained; or > in case I'm simply mistaken about any of these modules being dead wood. > > The modules in question are: FrameViewer.py, loader.py, > MultiScrolledLists.py, Remote.py, RemoteInterp.py, Separator.py, and > ToolTip.py . > > If you've had any connection with idlefork or idle in the past please > cast an eye over that list and let me know if you think any of those > modules still need to be in idlefork. I think all of these can go. Here are my comments: FrameViewer.py: probably a very early experiment of mine in GUI tools. loader.py: doesn't occur in Python's CVS, so I guess it was added by a later effort. MultiScrolledLists.py: an old GUI feature; before I had a decent tree widget this is how I browsed class hierarchies etc. Remote.py: not in python cvs; I expect it's part of the older remote interpreter effort. RemoteInterp.py: a never-used attempt at a remote interpreter by Jeremy Hylton. Can go now. Separator.py: part of MultiScrolledLists.py ToolTip.py: this might be handy, it's an attempt at creating a generally useful tooltip feature. But maybe there's another approach to that already? (CallTips doesn't seem to use this.) --Guido van Rossum (home page: http://www.python.org/~guido/)