[Python-checkins] r65052 - in sandbox/trunk/ttk-gsoc/src/idlelib: EditorWindow.py HyperParser.py editorpage.py tabbedpages_new.py tabbedpages_old.py

guilherme.polo python-checkins at python.org
Thu Jul 17 03:27:36 CEST 2008


Author: guilherme.polo
Date: Thu Jul 17 03:27:35 2008
New Revision: 65052

Log:
Moved a lot of stuff from EditorWindow to a new module: editorpage. tabs are not working at all yet, this is a first step towards tabs support

Added:
   sandbox/trunk/ttk-gsoc/src/idlelib/editorpage.py
Modified:
   sandbox/trunk/ttk-gsoc/src/idlelib/EditorWindow.py
   sandbox/trunk/ttk-gsoc/src/idlelib/HyperParser.py
   sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_new.py
   sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_old.py

Modified: sandbox/trunk/ttk-gsoc/src/idlelib/EditorWindow.py
==============================================================================
--- sandbox/trunk/ttk-gsoc/src/idlelib/EditorWindow.py	(original)
+++ sandbox/trunk/ttk-gsoc/src/idlelib/EditorWindow.py	Thu Jul 17 03:27:35 2008
@@ -6,25 +6,17 @@
 import webbrowser
 import tkMessageBox
 import tkSimpleDialog
-from Tkinter import Frame, Text, Menu, Scrollbar, TclError, BooleanVar
-from Tkconstants import INSERT, END, RIGHT, BOTTOM, TOP, X, Y, BOTH, LEFT
+from Tkinter import Menu, Scrollbar, TclError, BooleanVar
+from Tkconstants import INSERT, END, RIGHT, BOTTOM, TOP, X, Y, BOTH
 
-import idlever
-import textView
-import aboutDialog
-import configDialog
 import macosxSupport
-import PyParse
 import Bindings
-import GrepDialog
 import WindowList
 import PathBrowser
 import ClassBrowser
-import SearchDialog
-import ReplaceDialog
+from editorpage import EditorPage, classifyws
 from tabbedpages import get_tabbedpage
 from configHandler import idleConf
-from MultiCall import MultiCallCreator
 from IOBinding import IOBinding, filesystemencoding, encoding
 from Percolator import Percolator
 from UndoDelegator import UndoDelegator
@@ -32,8 +24,9 @@
 
 TabbedPageSet = get_tabbedpage()
 
-if idleConf.GetOption('main', 'General', 'use-ttk', type='int'):
-    from ttk import Frame, Scrollbar
+TTK = idleConf.GetOption('main', 'General', 'use-ttk', type='int')
+if TTK:
+    from ttk import Scrollbar
 
 # The default tab setting for a Text widget, in average-width characters.
 TK_TABWIDTH_DEFAULT = 8
@@ -58,6 +51,24 @@
 class EditorWindow(object):
     from ColorDelegator import ColorDelegator
     help_url = None
+    rmenu = None
+    rmenu_specs = [
+        # ("Label", "<<virtual-event>>"), ...
+        ("Close", "<<close-window>>"), # Example
+    ]
+    menu_specs = [
+        ("file", "_File"),
+        ("edit", "_Edit"),
+        ("format", "F_ormat"),
+        ("run", "_Run"),
+        ("options", "_Options"),
+        ("windows", "_Windows"),
+        ("help", "_Help"),
+    ]
+
+    if macosxSupport.runningAsOSXApp():
+        del menu_specs[-3]
+        menu_specs[-2] = ("windows", "_Window")
 
     def __init__(self, flist=None, filename=None, key=None, root=None):
         if EditorWindow.help_url is None:
@@ -114,63 +125,18 @@
 
         # create a Notebook where the text pages for this EditorWindow will
         # reside
-        first_page_title = "#1"
-        self.text_notebook = TabbedPageSet(top, page_names=[first_page_title])
+        self.text_notebook = TabbedPageSet(top)
+        self.text = text = self.new_tab()
+        self.top.focused_widget = self.text
+        self.text_notebook.pack(fill=BOTH, expand=True)
 
-        page_frame = self.text_notebook.pages[first_page_title].frame
-        vbar = Scrollbar(page_frame, name='vbar')
         # The following "width" attribute is used by PyShell, so keep it here
-        self.width = idleConf.GetOption('main', 'EditorWindow', 'width')
-        self.text = text = MultiCallCreator(Text)(
-                page_frame, name='text', padx=5, wrap='none', width=self.width,
-                height=idleConf.GetOption('main', 'EditorWindow', 'height'))
-        self.top.focused_widget = self.text
+        self.width = idleConf.GetOption('main', 'EditorPage', 'width')
 
         self.createmenubar()
-        self.apply_bindings()
 
         self.top.protocol("WM_DELETE_WINDOW", self.close)
         self.top.bind("<<close-window>>", self.close_event)
-        if macosxSupport.runningAsOSXApp():
-            # Command-W on editorwindows doesn't work without this.
-            text.bind('<<close-window>>', self.close_event)
-        text.bind("<<close-tab>>", self.close_tab)
-        text.bind("<<open-new-tab>>", self.new_editor_page)
-        text.bind("<<cut>>", self.cut)
-        text.bind("<<copy>>", self.copy)
-        text.bind("<<paste>>", self.paste)
-        text.bind("<<center-insert>>", self.center_insert_event)
-        text.bind("<<help>>", self.help_dialog)
-        text.bind("<<python-docs>>", self.python_docs)
-        text.bind("<<about-idle>>", self.about_dialog)
-        text.bind("<<open-config-dialog>>", self.config_dialog)
-        text.bind("<<open-module>>", self.open_module)
-        text.bind("<<do-nothing>>", lambda event: "break")
-        text.bind("<<select-all>>", self.select_all)
-        text.bind("<<remove-selection>>", self.remove_selection)
-        text.bind("<<find>>", self.find_event)
-        text.bind("<<find-again>>", self.find_again_event)
-        text.bind("<<find-in-files>>", self.find_in_files_event)
-        text.bind("<<find-selection>>", self.find_selection_event)
-        text.bind("<<replace>>", self.replace_event)
-        text.bind("<<goto-line>>", self.goto_line_event)
-        text.bind("<3>", self.right_menu_event)
-        text.bind("<<smart-backspace>>",self.smart_backspace_event)
-        text.bind("<<newline-and-indent>>",self.newline_and_indent_event)
-        text.bind("<<smart-indent>>",self.smart_indent_event)
-        text.bind("<<indent-region>>",self.indent_region_event)
-        text.bind("<<dedent-region>>",self.dedent_region_event)
-        text.bind("<<comment-region>>",self.comment_region_event)
-        text.bind("<<uncomment-region>>",self.uncomment_region_event)
-        text.bind("<<tabify-region>>",self.tabify_region_event)
-        text.bind("<<untabify-region>>",self.untabify_region_event)
-        text.bind("<<toggle-tabs>>",self.toggle_tabs_event)
-        text.bind("<<change-indentwidth>>",self.change_indentwidth_event)
-        text.bind("<Left>", self.move_at_edge_if_selection(0))
-        text.bind("<Right>", self.move_at_edge_if_selection(1))
-        text.bind("<<del-word-left>>", self.del_word_left)
-        text.bind("<<del-word-right>>", self.del_word_right)
-        text.bind("<<beginning-of-line>>", self.home_callback)
 
         if flist:
             flist.inversedict[self] = key
@@ -182,18 +148,6 @@
             text.bind("<<open-path-browser>>", self.open_path_browser)
 
         self.set_status_bar()
-        vbar['command'] = text.yview
-        vbar.pack(side=RIGHT, fill=Y)
-        text['yscrollcommand'] = vbar.set
-        fontWeight = 'normal'
-        if idleConf.GetOption('main', 'EditorWindow', 'font-bold', type='bool'):
-            fontWeight='bold'
-        text.config(font=(idleConf.GetOption('main', 'EditorWindow', 'font'),
-            idleConf.GetOption('main', 'EditorWindow', 'font-size'),
-            fontWeight))
-        text.pack(side=TOP, fill=BOTH, expand=1)
-        text.focus_set()
-        self.text_notebook.pack(fill=BOTH, expand=True)
 
         # usetabs true  -> literal tab characters are used by indent and
         #                  dedent cmds, possibly mixed with spaces if
@@ -300,54 +254,36 @@
         self.flist.new(dirname)
         return "break"
 
-    def new_editor_page(self, event):
+    def new_tab(self, event=None):
         """Create a new EditorPage and insert it into the notebook."""
-        print "Not yet"
-        return "break"
-
-    def home_callback(self, event):
-        if (event.state & 12) != 0 and event.keysym == "Home":
-            # state&1==shift, state&4==control, state&8==alt
-            return # <Modifier-Home>; fall back to class binding
-
-        if self.text.index("iomark") and \
-           self.text.compare("iomark", "<=", "insert lineend") and \
-           self.text.compare("insert linestart", "<=", "iomark"):
-            insertpt = int(self.text.index("iomark").split(".")[1])
-        else:
-            line = self.text.get("insert linestart", "insert lineend")
-            for insertpt in xrange(len(line)):
-                if line[insertpt] not in (' ','\t'):
-                    break
-            else:
-                insertpt=len(line)
-
-        lineat = int(self.text.index("insert").split('.')[1])
+        page_title = "#%d" % (len(self.text_notebook.pages) + 1)
+        page = self.text_notebook.add_page(page_title)
 
-        if insertpt == lineat:
-            insertpt = 0
-
-        dest = "insert linestart+"+str(insertpt)+"c"
-
-        if (event.state&1) == 0:
-            # shift not pressed
-            self.text.tag_remove("sel", "1.0", "end")
+        if TTK:
+            parent = page.frame
         else:
-            if not self.text.index("sel.first"):
-                self.text.mark_set("anchor","insert")
+            parent = page.frame
 
-            first = self.text.index(dest)
-            last = self.text.index("anchor")
+        vbar = Scrollbar(parent, name='vbar')
+        page.editpage = EditorPage(parent, self, name='text', padx=5,
+            wrap='none')
+        text = page.editpage.text
 
-            if self.text.compare(first,">",last):
-                first,last = last,first
+        vbar['command'] = text.yview
+        vbar.pack(side=RIGHT, fill=Y)
+        text['yscrollcommand'] = vbar.set
+        fontWeight = 'normal'
+        if idleConf.GetOption('main', 'EditorPage', 'font-bold', type='bool'):
+            fontWeight = 'bold'
+        text.config(font=(idleConf.GetOption('main', 'EditorPage', 'font'),
+            idleConf.GetOption('main', 'EditorPage', 'font-size'),
+            fontWeight))
+        text.pack(side=TOP, fill=BOTH, expand=1)
+        text.focus_set()
 
-            self.text.tag_remove("sel", "1.0", "end")
-            self.text.tag_add("sel", first, last)
+        self.apply_bindings()
 
-        self.text.mark_set("insert", dest)
-        self.text.see("insert")
-        return "break"
+        return text
 
     def set_status_bar(self):
         self.status_bar = MultiStatusBar(self.top)
@@ -368,21 +304,6 @@
         self.status_bar.set_label('column', 'Col: %s' % column)
         self.status_bar.set_label('line', 'Ln: %s' % line)
 
-    menu_specs = [
-        ("file", "_File"),
-        ("edit", "_Edit"),
-        ("format", "F_ormat"),
-        ("run", "_Run"),
-        ("options", "_Options"),
-        ("windows", "_Windows"),
-        ("help", "_Help"),
-    ]
-
-    if macosxSupport.runningAsOSXApp():
-        del menu_specs[-3]
-        menu_specs[-2] = ("windows", "_Window")
-
-
     def createmenubar(self):
         mbar = self.menubar
         self.menudict = menudict = {}
@@ -410,138 +331,6 @@
             menu.delete(self.wmenu_end+1, end)
         WindowList.add_windows_to_menu(menu)
 
-    rmenu = None
-
-    def right_menu_event(self, event):
-        self.text.tag_remove("sel", "1.0", "end")
-        self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
-        if not self.rmenu:
-            self.make_rmenu()
-        rmenu = self.rmenu
-        self.event = event
-        iswin = sys.platform[:3] == 'win'
-        if iswin:
-            self.text.config(cursor="arrow")
-        rmenu.tk_popup(event.x_root, event.y_root)
-        if iswin:
-            self.text.config(cursor="ibeam")
-
-    rmenu_specs = [
-        # ("Label", "<<virtual-event>>"), ...
-        ("Close", "<<close-window>>"), # Example
-    ]
-
-    def make_rmenu(self):
-        rmenu = Menu(self.text, tearoff=0)
-        for label, eventname in self.rmenu_specs:
-            def command(text=self.text, eventname=eventname):
-                text.event_generate(eventname)
-            rmenu.add_command(label=label, command=command)
-        self.rmenu = rmenu
-
-    def about_dialog(self, event=None):
-        aboutDialog.AboutDialog(self.top,'About IDLE')
-
-    def config_dialog(self, event=None):
-        configDialog.ConfigDialog(self.top,'Settings')
-
-    def help_dialog(self, event=None):
-        fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'help.txt')
-        textView.view_file(self.top,'Help',fn)
-
-    def python_docs(self, event=None):
-        if sys.platform[:3] == 'win':
-            os.startfile(self.help_url)
-        else:
-            webbrowser.open(self.help_url)
-        return "break"
-
-    def cut(self,event):
-        self.text.event_generate("<<Cut>>")
-        return "break"
-
-    def copy(self,event):
-        if not self.text.tag_ranges("sel"):
-            # There is no selection, so do nothing and maybe interrupt.
-            return
-        self.text.event_generate("<<Copy>>")
-        return "break"
-
-    def paste(self,event):
-        self.text.event_generate("<<Paste>>")
-        self.text.see("insert")
-        return "break"
-
-    def select_all(self, event=None):
-        self.text.tag_add("sel", "1.0", "end-1c")
-        self.text.mark_set("insert", "1.0")
-        self.text.see("insert")
-        return "break"
-
-    def remove_selection(self, event=None):
-        self.text.tag_remove("sel", "1.0", "end")
-        self.text.see("insert")
-
-    def move_at_edge_if_selection(self, edge_index):
-        """Cursor move begins at start or end of selection
-
-        When a left/right cursor key is pressed create and return to Tkinter a
-        function which causes a cursor move from the associated edge of the
-        selection.
-
-        """
-        self_text_index = self.text.index
-        self_text_mark_set = self.text.mark_set
-        edges_table = ("sel.first+1c", "sel.last-1c")
-        def move_at_edge(event):
-            if (event.state & 5) == 0: # no shift(==1) or control(==4) pressed
-                try:
-                    self_text_index("sel.first")
-                    self_text_mark_set("insert", edges_table[edge_index])
-                except TclError:
-                    pass
-        return move_at_edge
-
-    def del_word_left(self, event):
-        self.text.event_generate('<Meta-Delete>')
-        return "break"
-
-    def del_word_right(self, event):
-        self.text.event_generate('<Meta-d>')
-        return "break"
-
-    def find_event(self, event):
-        SearchDialog.find(self.text)
-        return "break"
-
-    def find_again_event(self, event):
-        SearchDialog.find_again(self.text)
-        return "break"
-
-    def find_selection_event(self, event):
-        SearchDialog.find_selection(self.text)
-        return "break"
-
-    def find_in_files_event(self, event):
-        GrepDialog.grep(self.text, self.io, self.flist)
-        return "break"
-
-    def replace_event(self, event):
-        ReplaceDialog.replace(self.text)
-        return "break"
-
-    def goto_line_event(self, event):
-        text = self.text
-        lineno = tkSimpleDialog.askinteger("Goto",
-                "Go to line number:",parent=text)
-        if lineno is None:
-            return "break"
-        if lineno <= 0:
-            text.bell()
-            return "break"
-        text.mark_set("insert", "%d.0" % lineno)
-        text.see("insert")
-
     def open_module(self, event=None):
         # XXX Shouldn't this be in IOBinding or in FileList?
         try:
@@ -591,12 +380,37 @@
     def open_path_browser(self, event=None):
         PathBrowser.PathBrowser(self.flist)
 
+    def current_page(self):
+        """Return the active EditorPage in EditorWindow."""
+        curr_tab = self.text_notebook.select()
+        if TTK:
+            page = self.text_notebook.pages[self.text_notebook.tab(
+                curr_tab)['text']].editpage
+        else:
+            page = self.text_notebook.pages[curr_tab].editpage
+        return page
+
+    def newline_and_indent_event(self, event):
+        """Call newline_and_indent_event on current EditorPage."""
+        self.current_page().newline_and_indent_event(event)
+
+    def get_selection_indices(self):
+        """Call get_selection_indices on current EditorPage."""
+        return self.current_page().get_selection_indices()
+
+    def build_char_in_string_func(self, startindex):
+        """Call build_char_in_string_func on current EditorPage."""
+        return self.current_page().build_char_in_string_func(startindex)
+
     def gotoline(self, lineno):
+        page = self.current_page()
+        text = page.text
+
         if lineno is not None and lineno > 0:
-            self.text.mark_set("insert", "%d.0" % lineno)
-            self.text.tag_remove("sel", "1.0", "end")
-            self.text.tag_add("sel", "insert", "insert +1l")
-            self.center()
+            text.mark_set("insert", "%d.0" % lineno)
+            text.tag_remove("sel", "1.0", "end")
+            text.tag_add("sel", "insert", "insert +1l")
+            page.center()
 
     def ispythonsource(self, filename):
         if not filename or os.path.isdir(filename):
@@ -665,11 +479,11 @@
     def ResetFont(self):
         "Update the text widgets' font if it is changed"
         # Called from configDialog.py
-        fontWeight='normal'
-        if idleConf.GetOption('main','EditorWindow','font-bold',type='bool'):
-            fontWeight='bold'
-        self.text.config(font=(idleConf.GetOption('main','EditorWindow','font'),
-                idleConf.GetOption('main','EditorWindow','font-size'),
+        fontWeight = 'normal'
+        if idleConf.GetOption('main', 'EditorPage', 'font-bold', type='bool'):
+            fontWeight = 'bold'
+        self.text.config(font=(idleConf.GetOption('main', 'EditorPage', 'font'),
+                idleConf.GetOption('main', 'EditorPage', 'font-size'),
                 fontWeight))
 
     def RemoveKeybindings(self):
@@ -834,31 +648,6 @@
         # return unicode string to display non-ASCII chars correctly
         return self._filename_to_unicode(self.io.filename or "")
 
-    def center_insert_event(self, event):
-        self.center()
-
-    def center(self, mark="insert"):
-        text = self.text
-        top, bot = self.getwindowlines()
-        lineno = self.getlineno(mark)
-        height = bot - top
-        newtop = max(1, lineno - height//2)
-        text.yview(float(newtop))
-
-    def getwindowlines(self):
-        text = self.text
-        top = self.getlineno("@0,0")
-        bot = self.getlineno("@0,65535")
-        if top == bot and text.winfo_height() == 1:
-            # Geometry manager hasn't run yet
-            height = int(text['height'])
-            bot = top + height - 1
-        return top, bot
-
-    def getlineno(self, mark="insert"):
-        text = self.text
-        return int(float(text.index(mark)))
-
     def get_geometry(self):
         "Return (width, height, x, y)"
         geom = self.top.wm_geometry()
@@ -869,10 +658,6 @@
     def close_event(self, event):
         self.close()
 
-    def close_tab(self, event):
-        """Close current tab, if no more tabs present, close the window."""
-        print "I do nothing right now"
-
     def maybesave(self):
         if self.io:
             if not self.get_saved():
@@ -956,11 +741,13 @@
     def apply_bindings(self, keydefs=None):
         if keydefs is None:
             keydefs = Bindings.default_keydefs
-        text = self.text
-        text.keydefs = keydefs
-        for event, keylist in keydefs.items():
-            if keylist:
-                text.event_add(event, *keylist)
+
+        for page in self.text_notebook.pages.itervalues():
+            text = page.editpage.text
+            text.keydefs = keydefs
+            for event, keylist in keydefs.items():
+                if keylist:
+                    text.event_add(event, *keylist)
 
     def fill_menus(self, menudefs=None, keydefs=None):
         """Add appropriate entries to the menus and submenus
@@ -1025,40 +812,13 @@
     # reusing IDLE's support code needs to define these for its GUI's
     # flavor of widget.
 
-    # Is character at text_index in a Python string?  Return 0 for
-    # "guaranteed no", true for anything else.  This info is expensive
-    # to compute ab initio, but is probably already known by the
-    # platform's colorizer.
-
-    def is_char_in_string(self, text_index):
-        if self.color:
-            # Return true iff colorizer hasn't (re)gotten this far
-            # yet, or the character is tagged as being in a string
-            return self.text.tag_prevrange("TODO", text_index) or \
-                   "STRING" in self.text.tag_names(text_index)
-        else:
-            # The colorizer is missing: assume the worst
-            return 1
-
-    # If a selection is defined in the text widget, return (start,
-    # end) as Tkinter text indices, otherwise return (None, None)
-    def get_selection_indices(self):
-        try:
-            first = self.text.index("sel.first")
-            last = self.text.index("sel.last")
-            return first, last
-        except TclError:
-            return None, None
-
     # Return the text widget's current view of what a tab stop means
     # (equivalent width in spaces).
-
     def get_tabwidth(self):
         current = self.text['tabs'] or TK_TABWIDTH_DEFAULT
         return int(current)
 
     # Set the text widget's current view of what a tab stop means.
-
     def set_tabwidth(self, newtabwidth):
         text = self.text
         if self.get_tabwidth() != newtabwidth:
@@ -1072,7 +832,6 @@
     # 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=True):
         if guess and ispythonsource:
             i = self.guess_indent()
@@ -1082,355 +841,10 @@
                 self.usetabs = False
         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.
-        tabwidth = self.tabwidth
-        have = len(chars.expandtabs(tabwidth))
-        assert have > 0
-        want = ((have - 1) // self.indentwidth) * self.indentwidth
-        # Debug prompt is multilined....
-        last_line_of_prompt = sys.ps1.split('\n')[-1]
-        ncharsdeleted = 0
-        while 1:
-            if chars == last_line_of_prompt:
-                break
-            chars = chars[:-1]
-            ncharsdeleted = ncharsdeleted + 1
-            have = len(chars.expandtabs(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
-        # else:
-        #     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:
-                # tab to the next 'stop' within or to right of line's text:
-                if self.usetabs:
-                    pad = '\t'
-                else:
-                    effective = len(prefix.expandtabs(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 in a continuation
-                # line; just inject an empty line at the start
-                text.insert("insert linestart", '\n')
-                return "break"
-            indent = line[:i]
-            # strip whitespace before insert point unless it's in the prompt
-            i = 0
-            last_line_of_prompt = sys.ps1.split('\n')[-1]
-            while line and line[-1] in " \t" and line != last_line_of_prompt:
-                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)
-            if not self.context_use_ps1:
-                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)
-            else:
-                r = text.tag_prevrange("console", "insert")
-                if r:
-                    startatindex = r[1]
-                else:
-                    startatindex = "1.0"
-                rawtext = text.get(startatindex, "insert")
-                y.set_str(rawtext)
-                y.set_lo(0)
-
-            c = y.get_continuation_type()
-            if c != PyParse.C_NONE:
-                # The current stmt hasn't ended yet.
-                if c == PyParse.C_STRING_FIRST_LINE:
-                    # after the first line of a string; do not indent at all
-                    pass
-                elif c == PyParse.C_STRING_NEXT_LINES:
-                    # inside a string which started before this line;
-                    # 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 %r" % (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()
-
-    # 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] = lines[pos].expandtabs(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] +
-              "?\nIndent width " +
-              ("will be", "remains at")[self.usetabs] + " 8." +
-              "\n Note: a tab is always 8 columns",
-              parent=self.text):
-            self.usetabs = not self.usetabs
-            # Try to prevent inconsistent indentation.
-            # User must change indent width manually after using tabs.
-            self.indentwidth = 8
-        return "break"
-
-    # XXX this isn't bound to anything -- see 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)\n(Always use 8 when using tabs)",
-                  parent=self.text,
-                  initialvalue=self.indentwidth,
-                  minvalue=2,
-                  maxvalue=16)
-        if new and new != self.indentwidth and not self.usetabs:
-            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 = chars.split("\n")
-        return head, tail, chars, lines
-
-    def set_region(self, head, tail, chars, lines):
-        text = self.text
-        newchars = "\n".join(lines)
-        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",
-            "Columns 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:
@@ -1440,28 +854,11 @@
             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
@@ -1558,6 +955,7 @@
 
 
 def test():
+    from Tkinter import Tk
     root = Tk()
     fixwordbreaks(root)
     root.withdraw()

Modified: sandbox/trunk/ttk-gsoc/src/idlelib/HyperParser.py
==============================================================================
--- sandbox/trunk/ttk-gsoc/src/idlelib/HyperParser.py	(original)
+++ sandbox/trunk/ttk-gsoc/src/idlelib/HyperParser.py	Thu Jul 17 03:27:35 2008
@@ -10,7 +10,9 @@
 
 import string
 import keyword
+
 import PyParse
+from editorpage import index2line
 
 class HyperParser:
 
@@ -24,8 +26,6 @@
 
         parser = PyParse.Parser(editwin.indentwidth, editwin.tabwidth)
 
-        def index2line(index):
-            return int(float(index))
         lno = index2line(text.index(index))
 
         if not editwin.context_use_ps1:
@@ -38,7 +38,7 @@
                 # its status will be the same as the char before it, if should.
                 parser.set_str(text.get(startatindex, stopatindex)+' \n')
                 bod = parser.find_good_parse_start(
-                          editwin._build_char_in_string_func(startatindex))
+                          editwin.build_char_in_string_func(startatindex))
                 if bod is not None or startat == 1:
                     break
             parser.set_lo(bod or 0)

Added: sandbox/trunk/ttk-gsoc/src/idlelib/editorpage.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/ttk-gsoc/src/idlelib/editorpage.py	Thu Jul 17 03:27:35 2008
@@ -0,0 +1,675 @@
+import os
+import sys
+import webbrowser
+import tkSimpleDialog
+from Tkinter import Text, Menu, TclError
+
+import textView
+import aboutDialog
+import configDialog
+import macosxSupport
+import PyParse
+import GrepDialog
+import SearchDialog
+import ReplaceDialog
+from configHandler import idleConf
+from MultiCall import MultiCallCreator
+
+#def callback(method, widget=None):
+#    def func(*args):
+#        if widget:
+#            return method(widget=widget, *args)
+#        else:
+#            return method(*args)
+
+#    return func
+
+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
+
+# "line.col" -> line, as an int
+def index2line(index):
+    return int(float(index))
+
+class EditorPage:
+    def __init__(self, parent, editwin, **kwargs):
+        self.editwin = editwin
+        kwargs.setdefault('width', idleConf.GetOption('main', 'EditorPage',
+            'width'))
+        kwargs.setdefault('height', idleConf.GetOption('main', 'EditorPage',
+            'height'))
+
+        self.text = MultiCallCreator(Text)(parent, **kwargs)
+        self._setup_bindings()
+
+    def center(self, mark="insert"):
+        # Used by EditorWindow.gotoline
+        text = self.text
+        top, bot = self._getwindowlines()
+        lineno = self._getlineno(mark)
+        height = bot - top
+        newtop = max(1, lineno - height//2)
+        text.yview(float(newtop))
+
+    def newline_and_indent_event(self, event):
+        # Used by EditorWindow.newline_and_indent_event which is used by PyShell
+        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 in a continuation
+                # line; just inject an empty line at the start
+                text.insert("insert linestart", '\n')
+                return "break"
+            indent = line[:i]
+            # strip whitespace before insert point unless it's in the prompt
+            i = 0
+            last_line_of_prompt = sys.ps1.split('\n')[-1]
+            while line and line[-1] in " \t" and line != last_line_of_prompt:
+                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.editwin.indentwidth, self.editwin.tabwidth)
+            if not self.editwin.context_use_ps1:
+                for context in self.editwin.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.editwin.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)
+            else:
+                r = text.tag_prevrange("console", "insert")
+                if r:
+                    startatindex = r[1]
+                else:
+                    startatindex = "1.0"
+                rawtext = text.get(startatindex, "insert")
+                y.set_str(rawtext)
+                y.set_lo(0)
+
+            c = y.get_continuation_type()
+            if c != PyParse.C_NONE:
+                # The current stmt hasn't ended yet.
+                if c == PyParse.C_STRING_FIRST_LINE:
+                    # after the first line of a string; do not indent at all
+                    pass
+                elif c == PyParse.C_STRING_NEXT_LINES:
+                    # inside a string which started before this line;
+                    # 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 %r" % (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()
+
+    # If a selection is defined in the text widget, return (start,
+    # end) as Tkinter text indices, otherwise return (None, None)
+    def get_selection_indices(self):
+        # Used by EditorWindow.get_selection_indices which is used by
+        # FormatParagraph
+        try:
+            first = self.text.index("sel.first")
+            last = self.text.index("sel.last")
+            return first, last
+        except TclError:
+            return None, None
+
+    # Our editpage 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):
+        # Used by EditorWindow.build_char_in_string_func which is used by
+        # HyperParser
+        def inner(offset, _startindex=startindex,
+                  _icis=self.__is_char_in_string):
+            return _icis(_startindex + "+%dc" % offset)
+        return inner
+
+    def _setup_bindings(self):
+        text = self.text
+        actions = ('<<close-tab>>', '<<help>>', '<<python-docs>>',
+            '<<about-idle>>', '<<open-config-dialog>>',
+            '<<cut>>', '<<copy>>', '<<paste>>', '<<select-all>>',
+            '<<remove-selection>>', '<<del-word-left>>', '<<del-word-right>>',
+            '<<beginning-of-line>>')
+
+        for action in actions:
+            prefix_size = action.count('<')
+            method_name = action[prefix_size:-prefix_size].replace('-', '_')
+            text.bind(action, getattr(self, "_%s" % method_name.lower()))
+
+        events = ('<<find>>', '<<center-insert>>', '<<find-again>>',
+            '<<find-in-files>>', '<<find-selection>>', '<<replace>>',
+            '<<goto-line>>', '<<smart-backspace>>', '<<smart-indent>>',
+            '<<indent-region>>', '<<dedent-region>>', '<<comment-region>>',
+            '<<tabify-region>>', '<<untabify-region>>', '<<toggle-tabs>>',
+            '<<change-indentwidth>>')
+
+        for event in events:
+            prefix_size = event.count('<')
+            method_name = event[prefix_size:-prefix_size].replace('-', '_')
+            text.bind(event, getattr(self, "_%s_event" % method_name.lower()))
+
+        parent_actions = ('<<new-tab>>', '<<open-module>>')
+
+        for action in parent_actions:
+            prefix_size = action.count('<')
+            method_name = action[prefix_size:-prefix_size].replace('-', '_')
+            text.bind(action, getattr(self.editwin, method_name))
+
+        text.bind('<<newline-and-indent>>', self.newline_and_indent_event)
+        text.bind("<<do-nothing>>", lambda event: "break")
+        text.bind("<Left>", self._move_at_edge_if_selection(0))
+        text.bind("<Right>", self._move_at_edge_if_selection(1))
+        text.bind("<3>", self._right_menu)
+
+        if macosxSupport.runningAsOSXApp():
+            # Command-W on editorwindows doesn't work without this.
+            text.bind('<<close-window>>', self.editwin.close_event)
+
+    def _close_tab(self, event):
+        """Close current tab, if no more tabs present, close the window."""
+        print "I do nothing right now"
+
+    def _help(self, event=None):
+        fn = os.path.join(os.path.abspath(os.path.dirname(__file__)),
+            'help.txt')
+        textView.view_file(self.text, 'Help', fn)
+
+    def _python_docs(self, event=None):
+        if sys.platform[:3] == 'win':
+            os.startfile(self.editwin.help_url)
+        else:
+            webbrowser.open(self.editwin.help_url)
+        return "break"
+
+    def _about_idle(self, event=None):
+        aboutDialog.AboutDialog(self.text, 'About IDLE')
+
+    def _open_config_dialog(self, event=None):
+        # When changing colors and saving it, it requires the attribute
+        # instance_dict making necessary to pass self.editwin.top as the
+        # parent
+        configDialog.ConfigDialog(self.editwin.top, 'Settings')
+
+    def _find_event(self, event):
+        SearchDialog.find(self.text)
+        return "break"
+
+    def _find_again_event(self, event):
+        SearchDialog.find_again(self.text)
+        return "break"
+
+    def _find_selection_event(self, event):
+        SearchDialog.find_selection(self.text)
+        return "break"
+
+    def _find_in_files_event(self, event):
+        # XXX not expected to work correctly for now
+        GrepDialog.grep(self.text, self.editwin.io, self.editwin.flist)
+        return "break"
+
+    def _replace_event(self, event):
+        ReplaceDialog.replace(self.text)
+        return "break"
+
+    def _center_insert_event(self, event):
+        self.center()
+
+    def _getwindowlines(self):
+        text = self.text
+        top = self._getlineno("@0,0")
+        bot = self._getlineno("@0,65535")
+        if top == bot and text.winfo_height() == 1:
+            # Geometry manager hasn't run yet
+            height = int(text['height'])
+            bot = top + height - 1
+        return top, bot
+
+    def _getlineno(self, mark="insert"):
+        return int(float(self.text.index(mark)))
+
+    def _goto_line_event(self, event):
+        text = self.text
+        lineno = tkSimpleDialog.askinteger("Goto", "Go to line number:",
+            parent=text)
+
+        if lineno is None:
+            return "break"
+
+        if lineno <= 0:
+            text.bell()
+            return "break"
+
+        text.mark_set("insert", "%d.0" % lineno)
+        text.see("insert")
+
+    def _cut(self, event):
+        self.text.event_generate("<<Cut>>")
+        return "break"
+
+    def _copy(self, event):
+        if not self.text.tag_ranges("sel"):
+            # There is no selection, so do nothing and maybe interrupt.
+            return
+
+        self.text.event_generate("<<Copy>>")
+        return "break"
+
+    def _paste(self, event):
+        self.text.event_generate("<<Paste>>")
+        self.text.see("insert")
+        return "break"
+
+    def _select_all(self, event=None):
+        self.text.tag_add("sel", "1.0", "end-1c")
+        self.text.mark_set("insert", "1.0")
+        self.text.see("insert")
+        return "break"
+
+    def _remove_selection(self, event=None):
+        self.text.tag_remove("sel", "1.0", "end")
+        self.text.see("insert")
+
+    def _del_word_left(self, event):
+        self.text.event_generate('<Meta-Delete>')
+        return "break"
+
+    def _del_word_right(self, event):
+        self.text.event_generate('<Meta-d>')
+        return "break"
+
+    def _move_at_edge_if_selection(self, edge_index):
+        """Cursor move begins at start or end of selection
+        When a left/right cursor key is pressed create and return to Tkinter a
+        function which causes a cursor move from the associated edge of the
+        selection.
+        """
+        text_index = self.text.index
+        text_mark_set = self.text.mark_set
+        edges_table = ("sel.first+1c", "sel.last-1c")
+
+        def move_at_edge(event):
+            if (event.state & 5) == 0: # no shift(==1) or control(==4) pressed
+                try:
+                    text_index("sel.first")
+                    text_mark_set("insert", edges_table[edge_index])
+                except TclError:
+                    pass
+
+        return move_at_edge
+
+    def _beginning_of_line(self, event):
+        if (event.state & 12) != 0 and event.keysym == "Home":
+            # state&1==shift, state&4==control, state&8==alt
+            return # <Modifier-Home>; fall back to class binding
+
+        text = self.text
+
+        if text.index("iomark") and \
+           text.compare("iomark", "<=", "insert lineend") and \
+           text.compare("insert linestart", "<=", "iomark"):
+            insertpt = int(text.index("iomark").split(".")[1])
+        else:
+            line = text.get("insert linestart", "insert lineend")
+            for insertpt in xrange(len(line)):
+                if line[insertpt] not in (' ','\t'):
+                    break
+            else:
+                insertpt=len(line)
+
+        lineat = int(text.index("insert").split('.')[1])
+
+        if insertpt == lineat:
+            insertpt = 0
+
+        dest = "insert linestart+%sc" % str(insertpt)
+
+        if (event.state & 1) == 0:
+            # shift not pressed
+            text.tag_remove("sel", "1.0", "end")
+        else:
+            if not text.index("sel.first"):
+                text.mark_set("anchor", "insert")
+
+            first = text.index(dest)
+            last = text.index("anchor")
+
+            if text.compare(first, ">", last):
+                first, last = last, first
+
+            text.tag_remove("sel", "1.0", "end")
+            text.tag_add("sel", first, last)
+
+        text.mark_set("insert", dest)
+        text.see("insert")
+        return "break"
+
+    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.
+        tabwidth = self.editwin.tabwidth
+        have = len(chars.expandtabs(tabwidth))
+        assert have > 0
+        want = ((have - 1) // 
+            self.editwin.indentwidth) * self.editwin.indentwidth
+        # Debug prompt is multilined....
+        last_line_of_prompt = sys.ps1.split('\n')[-1]
+        ncharsdeleted = 0
+        while 1:
+            if chars == last_line_of_prompt:
+                break
+            chars = chars[:-1]
+            ncharsdeleted = ncharsdeleted + 1
+            have = len(chars.expandtabs(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
+        # else:
+        #     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.editwin.tabwidth)
+            if raw == len(prefix):
+                # only whitespace to the left
+                self.__reindent_to(effective + self.editwin.indentwidth)
+            else:
+                # tab to the next 'stop' within or to right of line's text:
+                if self.editwin.usetabs:
+                    pad = '\t'
+                else:
+                    effective = len(prefix.expandtabs(self.editwin.tabwidth))
+                    n = self.editwin.indentwidth
+                    pad = ' ' * (n - effective % n)
+                text.insert("insert", pad)
+            text.see("insert")
+            return "break"
+        finally:
+            text.undo_block_stop()
+
+    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.editwin.tabwidth)
+                effective = effective + self.editwin.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.editwin.tabwidth)
+                effective = max(effective - self.editwin.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] = lines[pos].expandtabs(tabwidth)
+        self.__set_region(head, tail, chars, lines)
+
+    def _toggle_tabs_event(self, event):
+        if self.editwin.askyesno(
+              "Toggle tabs",
+              "Turn tabs " + ("on", "off")[self.editwin.usetabs] +
+              "?\nIndent width " +
+              ("will be", "remains at")[self.editwin.usetabs] + " 8." +
+              "\n Note: a tab is always 8 columns",
+              parent=self.text):
+            self.editwin.usetabs = not self.editwin.usetabs
+            # Try to prevent inconsistent indentation.
+            # User must change indent width manually after using tabs.
+            self.editwin.indentwidth = 8
+        return "break"
+
+    def _change_indentwidth_event(self, event):
+        new = self.editwin.askinteger(
+                  "Indent width",
+                  "New indent width (2-16)\n(Always use 8 when using tabs)",
+                  parent=self.text,
+                  initialvalue=self.editwin.indentwidth,
+                  minvalue=2,
+                  maxvalue=16)
+        if new and new != self.editwin.indentwidth and not self.editwin.usetabs:
+            self.editwin.indentwidth = new
+        return "break"
+
+    def _right_menu(self, event):
+        self.text.tag_remove("sel", "1.0", "end")
+        self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
+
+        if not self.editwin.rmenu:
+            self.__make_rmenu()
+
+        rmenu = self.editwin.rmenu
+        self.event = event
+        iswin = sys.platform[:3] == 'win'
+        if iswin:
+            self.text.config(cursor="arrow")
+        rmenu.tk_popup(event.x_root, event.y_root)
+        if iswin:
+            self.text.config(cursor="ibeam")
+
+    def __make_rmenu(self):
+        rmenu = Menu(self.text, tearoff=False)
+
+        for label, eventname in self.editwin.rmenu_specs:
+            def command(text=self.text, eventname=eventname):
+                text.event_generate(eventname)
+            rmenu.add_command(label=label, command=command)
+
+        self.editwin.rmenu = rmenu
+
+    def __asktabwidth(self):
+        return self.editwin.askinteger(
+            "Tab width",
+            "Columns per tab? (2-16)",
+            parent=self.text,
+            initialvalue=self.editwin.indentwidth,
+            minvalue=2,
+            maxvalue=16) or self.editwin.tabwidth
+
+    # Make string that displays as n leading blanks.
+    def __make_blanks(self, n):
+        if self.editwin.usetabs:
+            ntabs, nspaces = divmod(n, self.editwin.tabwidth)
+            return '\t' * ntabs + ' ' * nspaces
+        else:
+            return ' ' * n
+
+    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 = chars.split("\n")
+        return head, tail, chars, lines
+
+    def __set_region(self, head, tail, chars, lines):
+        text = self.text
+        newchars = "\n".join(lines)
+        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")
+
+    # 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()
+
+    # Tk implementations of "virtual text methods" -- each platform
+    # reusing IDLE's support code needs to define these for its GUI's
+    # flavor of widget.
+
+    # Is character at text_index in a Python string?  Return 0 for
+    # "guaranteed no", true for anything else.  This info is expensive
+    # to compute ab initio, but is probably already known by the
+    # platform's colorizer.
+    def __is_char_in_string(self, text_index):
+        if self.editwin.color: # XXX should this attribute be set per page ?
+            # Return true iff colorizer hasn't (re)gotten this far
+            # yet, or the character is tagged as being in a string
+            return self.text.tag_prevrange("TODO", text_index) or \
+                   "STRING" in self.text.tag_names(text_index)
+        else:
+            # The colorizer is missing: assume the worst
+            return 1

Modified: sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_new.py
==============================================================================
--- sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_new.py	(original)
+++ sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_new.py	Thu Jul 17 03:27:35 2008
@@ -51,6 +51,8 @@
         # workaround for bug #1878298 at tktoolkit sf bug tracker
         self.event_generate('<Expose>')
 
+        return fpage
+
     def remove_page(self, page_name):
         if not page_name in self.pages:
             raise KeyError("No such TabPage: '%s" % page_name)

Modified: sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_old.py
==============================================================================
--- sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_old.py	(original)
+++ sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_old.py	Thu Jul 17 03:27:35 2008
@@ -428,6 +428,8 @@
             self._default_page = page_name
             self.change_page(page_name)
 
+        return self.pages[page_name]
+
     def remove_page(self, page_name):
         """Destroy the page whose name is given in page_name."""
         if not page_name in self.pages:
@@ -467,6 +469,10 @@
 
         self._tab_set.set_selected_tab(page_name)
 
+    def select(self):
+        """Return the name of the currently selected page."""
+        return self._current_page
+
 if __name__ == '__main__':
     from Tkinter import Tk, Label, Entry, Button
     # test dialog


More information about the Python-checkins mailing list