1ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport sys
2ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport os
3ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport re
4ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport imp
5ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom Tkinter import *
6ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport tkSimpleDialog
7ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport tkMessageBox
8ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport webbrowser
9ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
10ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom idlelib.MultiCall import MultiCallCreator
11ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom idlelib import idlever
12ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom idlelib import WindowList
13ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom idlelib import SearchDialog
14ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom idlelib import GrepDialog
15ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom idlelib import ReplaceDialog
16ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom idlelib import PyParse
17ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom idlelib.configHandler import idleConf
18ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom idlelib import aboutDialog, textView, configDialog
19ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom idlelib import macosxSupport
20ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
21ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# The default tab setting for a Text widget, in average-width characters.
22ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehTK_TABWIDTH_DEFAULT = 8
23ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
24ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef _sphinx_version():
25ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    "Format sys.version_info to produce the Sphinx version string used to install the chm docs"
26ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    major, minor, micro, level, serial = sys.version_info
27ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    release = '%s%s' % (major, minor)
28ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if micro:
29ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        release += '%s' % (micro,)
30ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if level == 'candidate':
31ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        release += 'rc%s' % (serial,)
32ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    elif level != 'final':
33ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        release += '%s%s' % (level[0], serial)
34ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    return release
35ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
36ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef _find_module(fullname, path=None):
37ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """Version of imp.find_module() that handles hierarchical module names"""
38ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
39ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    file = None
40ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    for tgt in fullname.split('.'):
41ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if file is not None:
42ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            file.close()            # close intermediate files
43ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        (file, filename, descr) = imp.find_module(tgt, path)
44ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if descr[2] == imp.PY_SOURCE:
45ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            break                   # find but not load the source file
46ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        module = imp.load_module(tgt, file, filename, descr)
47ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
48ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            path = module.__path__
49ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except AttributeError:
50ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            raise ImportError, 'No source for module ' + module.__name__
51ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if descr[2] != imp.PY_SOURCE:
52ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # If all of the above fails and didn't raise an exception,fallback
53ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # to a straight import which can find __init__.py in a package.
54ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        m = __import__(fullname)
55ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
56ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            filename = m.__file__
57ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except AttributeError:
58ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            pass
59ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
60ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            file = None
61ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            base, ext = os.path.splitext(filename)
62ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if ext == '.pyc':
63ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                ext = '.py'
64ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            filename = base + ext
65ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            descr = filename, None, imp.PY_SOURCE
66ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    return file, filename, descr
67ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
68ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
69ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass HelpDialog(object):
70ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
71ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __init__(self):
72ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.parent = None      # parent of help window
73ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.dlg = None         # the help window iteself
74ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
75ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def display(self, parent, near=None):
76ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """ Display the help dialog.
77ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
78ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            parent - parent widget for the help window
79ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
80ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            near - a Toplevel widget (e.g. EditorWindow or PyShell)
81ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                   to use as a reference for placing the help window
82ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
83ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.dlg is None:
84ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.show_dialog(parent)
85ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if near:
86ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.nearwindow(near)
87ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
88ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def show_dialog(self, parent):
89ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.parent = parent
90ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'help.txt')
91ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.dlg = dlg = textView.view_file(parent,'Help',fn, modal=False)
92ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dlg.bind('<Destroy>', self.destroy, '+')
93ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
94ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def nearwindow(self, near):
95ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Place the help dialog near the window specified by parent.
96ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Note - this may not reposition the window in Metacity
97ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #  if "/apps/metacity/general/disable_workarounds" is enabled
98ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dlg = self.dlg
99ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        geom = (near.winfo_rootx() + 10, near.winfo_rooty() + 10)
100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dlg.withdraw()
101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dlg.geometry("=+%d+%d" % geom)
102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dlg.deiconify()
103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dlg.lift()
104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def destroy(self, ev=None):
106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.dlg = None
107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.parent = None
108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehhelpDialog = HelpDialog()  # singleton instance
110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass EditorWindow(object):
113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    from idlelib.Percolator import Percolator
114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    from idlelib.ColorDelegator import ColorDelegator
115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    from idlelib.UndoDelegator import UndoDelegator
116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    from idlelib.IOBinding import IOBinding, filesystemencoding, encoding
117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    from idlelib import Bindings
118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    from Tkinter import Toplevel
119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    from idlelib.MultiStatusBar import MultiStatusBar
120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    help_url = None
122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __init__(self, flist=None, filename=None, key=None, root=None):
124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if EditorWindow.help_url is None:
125ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            dochome =  os.path.join(sys.prefix, 'Doc', 'index.html')
126ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if sys.platform.count('linux'):
127ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # look for html docs in a couple of standard places
128ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                pyver = 'python-docs-' + '%s.%s.%s' % sys.version_info[:3]
129ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if os.path.isdir('/var/www/html/python/'):  # "python2" rpm
130ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    dochome = '/var/www/html/python/index.html'
131ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
132ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    basepath = '/usr/share/doc/'  # standard location
133ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    dochome = os.path.join(basepath, pyver,
134ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                           'Doc', 'index.html')
135ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            elif sys.platform[:3] == 'win':
136ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                chmfile = os.path.join(sys.prefix, 'Doc',
137ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                       'Python%s.chm' % _sphinx_version())
138ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if os.path.isfile(chmfile):
139ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    dochome = chmfile
140ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            elif macosxSupport.runningAsOSXApp():
141ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # documentation is stored inside the python framework
142ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                dochome = os.path.join(sys.prefix,
143ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        'Resources/English.lproj/Documentation/index.html')
144ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            dochome = os.path.normpath(dochome)
145ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if os.path.isfile(dochome):
146ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                EditorWindow.help_url = dochome
147ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if sys.platform == 'darwin':
148ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # Safari requires real file:-URLs
149ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    EditorWindow.help_url = 'file://' + EditorWindow.help_url
150ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
151ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                EditorWindow.help_url = "http://docs.python.org/%d.%d" % sys.version_info[:2]
152ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        currentTheme=idleConf.CurrentTheme()
153ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.flist = flist
154ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        root = root or flist.root
155ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.root = root
156ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
157ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            sys.ps1
158ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except AttributeError:
159ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            sys.ps1 = '>>> '
160ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.menubar = Menu(root)
161ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.top = top = WindowList.ListedToplevel(root, menu=self.menubar)
162ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if flist:
163ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.tkinter_vars = flist.vars
164ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            #self.top.instance_dict makes flist.inversedict available to
165ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            #configDialog.py so it can access all EditorWindow instances
166ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.top.instance_dict = flist.inversedict
167ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
168ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.tkinter_vars = {}  # keys: Tkinter event names
169ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                    # values: Tkinter variable instances
170ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.top.instance_dict = {}
171ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.recent_files_path = os.path.join(idleConf.GetUserCfgDir(),
172ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                'recent-files.lst')
173ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text_frame = text_frame = Frame(top)
174ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.vbar = vbar = Scrollbar(text_frame, name='vbar')
175ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.width = idleConf.GetOption('main','EditorWindow','width', type='int')
176ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text_options = {
177ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                'name': 'text',
178ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                'padx': 5,
179ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                'wrap': 'none',
180ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                'width': self.width,
181ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                'height': idleConf.GetOption('main', 'EditorWindow', 'height', type='int')}
182ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if TkVersion >= 8.5:
183ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Starting with tk 8.5 we have to set the new tabstyle option
184ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # to 'wordprocessor' to achieve the same display of tabs as in
185ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # older tk versions.
186ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text_options['tabstyle'] = 'wordprocessor'
187ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text = text = MultiCallCreator(Text)(text_frame, **text_options)
188ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.top.focused_widget = self.text
189ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
190ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.createmenubar()
191ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.apply_bindings()
192ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
193ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.top.protocol("WM_DELETE_WINDOW", self.close)
194ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.top.bind("<<close-window>>", self.close_event)
195ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if macosxSupport.runningAsOSXApp():
196ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Command-W on editorwindows doesn't work without this.
197ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.bind('<<close-window>>', self.close_event)
198ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Some OS X systems have only one mouse button,
199ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # so use control-click for pulldown menus there.
200ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            #  (Note, AquaTk defines <2> as the right button if
201ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            #   present and the Tk Text widget already binds <2>.)
202ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.bind("<Control-Button-1>",self.right_menu_event)
203ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
204ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Elsewhere, use right-click for pulldown menus.
205ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.bind("<3>",self.right_menu_event)
206ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<cut>>", self.cut)
207ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<copy>>", self.copy)
208ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<paste>>", self.paste)
209ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<center-insert>>", self.center_insert_event)
210ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<help>>", self.help_dialog)
211ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<python-docs>>", self.python_docs)
212ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<about-idle>>", self.about_dialog)
213ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<open-config-dialog>>", self.config_dialog)
214ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<open-module>>", self.open_module)
215ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<do-nothing>>", lambda event: "break")
216ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<select-all>>", self.select_all)
217ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<remove-selection>>", self.remove_selection)
218ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<find>>", self.find_event)
219ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<find-again>>", self.find_again_event)
220ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<find-in-files>>", self.find_in_files_event)
221ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<find-selection>>", self.find_selection_event)
222ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<replace>>", self.replace_event)
223ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<goto-line>>", self.goto_line_event)
224ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<smart-backspace>>",self.smart_backspace_event)
225ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<newline-and-indent>>",self.newline_and_indent_event)
226ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<smart-indent>>",self.smart_indent_event)
227ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<indent-region>>",self.indent_region_event)
228ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<dedent-region>>",self.dedent_region_event)
229ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<comment-region>>",self.comment_region_event)
230ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<uncomment-region>>",self.uncomment_region_event)
231ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<tabify-region>>",self.tabify_region_event)
232ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<untabify-region>>",self.untabify_region_event)
233ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<toggle-tabs>>",self.toggle_tabs_event)
234ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<change-indentwidth>>",self.change_indentwidth_event)
235ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<Left>", self.move_at_edge_if_selection(0))
236ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<Right>", self.move_at_edge_if_selection(1))
237ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<del-word-left>>", self.del_word_left)
238ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<del-word-right>>", self.del_word_right)
239ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.bind("<<beginning-of-line>>", self.home_callback)
240ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
241ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if flist:
242ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            flist.inversedict[self] = key
243ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if key:
244ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                flist.dict[key] = self
245ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.bind("<<open-new-window>>", self.new_callback)
246ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.bind("<<close-all-windows>>", self.flist.close_all_callback)
247ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.bind("<<open-class-browser>>", self.open_class_browser)
248ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.bind("<<open-path-browser>>", self.open_path_browser)
249ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
250ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.set_status_bar()
251ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        vbar['command'] = text.yview
252ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        vbar.pack(side=RIGHT, fill=Y)
253ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text['yscrollcommand'] = vbar.set
254ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        fontWeight = 'normal'
255ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if idleConf.GetOption('main', 'EditorWindow', 'font-bold', type='bool'):
256ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            fontWeight='bold'
257ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.config(font=(idleConf.GetOption('main', 'EditorWindow', 'font'),
258ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                          idleConf.GetOption('main', 'EditorWindow',
259ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                             'font-size', type='int'),
260ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                          fontWeight))
261ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text_frame.pack(side=LEFT, fill=BOTH, expand=1)
262ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.pack(side=TOP, fill=BOTH, expand=1)
263ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.focus_set()
264ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
265ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # usetabs true  -> literal tab characters are used by indent and
266ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #                  dedent cmds, possibly mixed with spaces if
267ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #                  indentwidth is not a multiple of tabwidth,
268ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #                  which will cause Tabnanny to nag!
269ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #         false -> tab characters are converted to spaces by indent
270ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #                  and dedent cmds, and ditto TAB keystrokes
271ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Although use-spaces=0 can be configured manually in config-main.def,
272ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # configuration of tabs v. spaces is not supported in the configuration
273ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # dialog.  IDLE promotes the preferred Python indentation: use spaces!
274ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        usespaces = idleConf.GetOption('main', 'Indent', 'use-spaces', type='bool')
275ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.usetabs = not usespaces
276ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
277ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # tabwidth is the display width of a literal tab character.
278ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # CAUTION:  telling Tk to use anything other than its default
279ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # tab setting causes it to use an entirely different tabbing algorithm,
280ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # treating tab stops as fixed distances from the left margin.
281ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Nobody expects this, so for now tabwidth should never be changed.
282ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.tabwidth = 8    # must remain 8 until Tk is fixed.
283ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
284ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # indentwidth is the number of screen characters per indent level.
285ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # The recommended Python indentation is four spaces.
286ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.indentwidth = self.tabwidth
287ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.set_notabs_indentwidth()
288ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
289ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # If context_use_ps1 is true, parsing searches back for a ps1 line;
290ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # else searches for a popular (if, def, ...) Python stmt.
291ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.context_use_ps1 = False
292ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
293ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # When searching backwards for a reliable place to begin parsing,
294ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # first start num_context_lines[0] lines back, then
295ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # num_context_lines[1] lines back if that didn't work, and so on.
296ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # The last value should be huge (larger than the # of lines in a
297ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # conceivable file).
298ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Making the initial values larger slows things down more often.
299ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.num_context_lines = 50, 500, 5000000
300ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
301ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.per = per = self.Percolator(text)
302ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
303ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.undo = undo = self.UndoDelegator()
304ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        per.insertfilter(undo)
305ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.undo_block_start = undo.undo_block_start
306ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.undo_block_stop = undo.undo_block_stop
307ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        undo.set_saved_change_hook(self.saved_change_hook)
308ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
309ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # IOBinding implements file I/O and printing functionality
310ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.io = io = self.IOBinding(self)
311ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        io.set_filename_change_hook(self.filename_change_hook)
312ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
313ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Create the recent files submenu
314ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.recent_files_menu = Menu(self.menubar)
315ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.menudict['file'].insert_cascade(3, label='Recent Files',
316ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                             underline=0,
317ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                             menu=self.recent_files_menu)
318ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.update_recent_files_list()
319ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
320ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.color = None # initialized below in self.ResetColorizer
321ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if filename:
322ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if os.path.exists(filename) and not os.path.isdir(filename):
323ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                io.loadfile(filename)
324ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
325ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                io.set_filename(filename)
326ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.ResetColorizer()
327ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.saved_change_hook()
328ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
329ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.set_indentation_params(self.ispythonsource(filename))
330ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
331ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.load_extensions()
332ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
333ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        menu = self.menudict.get('windows')
334ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if menu:
335ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            end = menu.index("end")
336ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if end is None:
337ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                end = -1
338ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if end >= 0:
339ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                menu.add_separator()
340ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                end = end + 1
341ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.wmenu_end = end
342ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            WindowList.register_callback(self.postwindowsmenu)
343ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
344ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Some abstractions so IDLE extensions are cross-IDE
345ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.askyesno = tkMessageBox.askyesno
346ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.askinteger = tkSimpleDialog.askinteger
347ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.showerror = tkMessageBox.showerror
348ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
349ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def _filename_to_unicode(self, filename):
350ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """convert filename to unicode in order to display it in Tk"""
351ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if isinstance(filename, unicode) or not filename:
352ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return filename
353ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
354ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
355ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return filename.decode(self.filesystemencoding)
356ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except UnicodeDecodeError:
357ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # XXX
358ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                try:
359ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    return filename.decode(self.encoding)
360ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                except UnicodeDecodeError:
361ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # byte-to-byte conversion
362ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    return filename.decode('iso8859-1')
363ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
364ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def new_callback(self, event):
365ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dirname, basename = self.io.defaultfilename()
366ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.flist.new(dirname)
367ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
368ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
369ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def home_callback(self, event):
370ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if (event.state & 4) != 0 and event.keysym == "Home":
371ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # state&4==Control. If <Control-Home>, use the Tk binding.
372ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return
373ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.text.index("iomark") and \
374ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh           self.text.compare("iomark", "<=", "insert lineend") and \
375ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh           self.text.compare("insert linestart", "<=", "iomark"):
376ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # In Shell on input line, go to just after prompt
377ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            insertpt = int(self.text.index("iomark").split(".")[1])
378ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
379ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            line = self.text.get("insert linestart", "insert lineend")
380ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for insertpt in xrange(len(line)):
381ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if line[insertpt] not in (' ','\t'):
382ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    break
383ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
384ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                insertpt=len(line)
385ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        lineat = int(self.text.index("insert").split('.')[1])
386ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if insertpt == lineat:
387ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            insertpt = 0
388ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dest = "insert linestart+"+str(insertpt)+"c"
389ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if (event.state&1) == 0:
390ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # shift was not pressed
391ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.tag_remove("sel", "1.0", "end")
392ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
393ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if not self.text.index("sel.first"):
394ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.text.mark_set("my_anchor", "insert")  # there was no previous selection
395ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
396ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if self.text.compare(self.text.index("sel.first"), "<", self.text.index("insert")):
397ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self.text.mark_set("my_anchor", "sel.first") # extend back
398ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
399ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self.text.mark_set("my_anchor", "sel.last") # extend forward
400ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            first = self.text.index(dest)
401ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            last = self.text.index("my_anchor")
402ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if self.text.compare(first,">",last):
403ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                first,last = last,first
404ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.tag_remove("sel", "1.0", "end")
405ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.tag_add("sel", first, last)
406ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.mark_set("insert", dest)
407ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.see("insert")
408ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
409ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
410ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def set_status_bar(self):
411ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.status_bar = self.MultiStatusBar(self.top)
412ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if macosxSupport.runningAsOSXApp():
413ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Insert some padding to avoid obscuring some of the statusbar
414ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # by the resize widget.
415ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.status_bar.set_label('_padding1', '    ', side=RIGHT)
416ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.status_bar.set_label('column', 'Col: ?', side=RIGHT)
417ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.status_bar.set_label('line', 'Ln: ?', side=RIGHT)
418ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.status_bar.pack(side=BOTTOM, fill=X)
419ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.bind("<<set-line-and-column>>", self.set_line_and_column)
420ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.event_add("<<set-line-and-column>>",
421ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            "<KeyRelease>", "<ButtonRelease>")
422ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.after_idle(self.set_line_and_column)
423ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
424ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def set_line_and_column(self, event=None):
425ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        line, column = self.text.index(INSERT).split('.')
426ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.status_bar.set_label('column', 'Col: %s' % column)
427ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.status_bar.set_label('line', 'Ln: %s' % line)
428ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
429ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    menu_specs = [
430ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ("file", "_File"),
431ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ("edit", "_Edit"),
432ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ("format", "F_ormat"),
433ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ("run", "_Run"),
434ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ("options", "_Options"),
435ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ("windows", "_Windows"),
436ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ("help", "_Help"),
437ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    ]
438ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
439ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if macosxSupport.runningAsOSXApp():
440ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        del menu_specs[-3]
441ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        menu_specs[-2] = ("windows", "_Window")
442ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
443ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
444ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def createmenubar(self):
445ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        mbar = self.menubar
446ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.menudict = menudict = {}
447ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for name, label in self.menu_specs:
448ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            underline, label = prepstr(label)
449ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            menudict[name] = menu = Menu(mbar, name=name)
450ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            mbar.add_cascade(label=label, menu=menu, underline=underline)
451ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
452ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if macosxSupport.isCarbonAquaTk(self.root):
453ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Insert the application menu
454ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            menudict['application'] = menu = Menu(mbar, name='apple')
455ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            mbar.add_cascade(label='IDLE', menu=menu)
456ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
457ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.fill_menus()
458ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.base_helpmenu_length = self.menudict['help'].index(END)
459ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.reset_help_menu_entries()
460ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
461ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def postwindowsmenu(self):
462ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Only called when Windows menu exists
463ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        menu = self.menudict['windows']
464ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        end = menu.index("end")
465ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if end is None:
466ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            end = -1
467ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if end > self.wmenu_end:
468ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            menu.delete(self.wmenu_end+1, end)
469ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        WindowList.add_windows_to_menu(menu)
470ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
471ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    rmenu = None
472ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
473ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def right_menu_event(self, event):
474ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
475ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not self.rmenu:
476ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.make_rmenu()
477ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        rmenu = self.rmenu
478ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.event = event
479ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        iswin = sys.platform[:3] == 'win'
480ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if iswin:
481ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.config(cursor="arrow")
482ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
483ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for item in self.rmenu_specs:
484ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
485ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                label, eventname, verify_state = item
486ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except ValueError: # see issue1207589
487ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                continue
488ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
489ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if verify_state is None:
490ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                continue
491ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            state = getattr(self, verify_state)()
492ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            rmenu.entryconfigure(label, state=state)
493ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
494ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        rmenu.tk_popup(event.x_root, event.y_root)
495ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if iswin:
496ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.config(cursor="ibeam")
497ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
498ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    rmenu_specs = [
499ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # ("Label", "<<virtual-event>>", "statefuncname"), ...
500ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ("Close", "<<close-window>>", None), # Example
501ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    ]
502ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
503ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def make_rmenu(self):
504ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        rmenu = Menu(self.text, tearoff=0)
505ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for item in self.rmenu_specs:
506ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            label, eventname = item[0], item[1]
507ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if label is not None:
508ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                def command(text=self.text, eventname=eventname):
509ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    text.event_generate(eventname)
510ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                rmenu.add_command(label=label, command=command)
511ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
512ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                rmenu.add_separator()
513ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.rmenu = rmenu
514ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
515ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def rmenu_check_cut(self):
516ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.rmenu_check_copy()
517ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
518ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def rmenu_check_copy(self):
519ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
520ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            indx = self.text.index('sel.first')
521ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except TclError:
522ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return 'disabled'
523ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
524ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return 'normal' if indx else 'disabled'
525ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
526ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def rmenu_check_paste(self):
527ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
528ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.tk.call('tk::GetSelection', self.text, 'CLIPBOARD')
529ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except TclError:
530ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return 'disabled'
531ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
532ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return 'normal'
533ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
534ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def about_dialog(self, event=None):
535ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        aboutDialog.AboutDialog(self.top,'About IDLE')
536ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
537ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def config_dialog(self, event=None):
538ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        configDialog.ConfigDialog(self.top,'Settings')
539ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
540ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def help_dialog(self, event=None):
541ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.root:
542ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            parent = self.root
543ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
544ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            parent = self.top
545ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        helpDialog.display(parent, near=self.top)
546ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
547ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def python_docs(self, event=None):
548ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if sys.platform[:3] == 'win':
549ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
550ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                os.startfile(self.help_url)
551ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except WindowsError as why:
552ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                tkMessageBox.showerror(title='Document Start Failure',
553ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    message=str(why), parent=self.text)
554ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
555ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            webbrowser.open(self.help_url)
556ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
557ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
558ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def cut(self,event):
559ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.event_generate("<<Cut>>")
560ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
561ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
562ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def copy(self,event):
563ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not self.text.tag_ranges("sel"):
564ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # There is no selection, so do nothing and maybe interrupt.
565ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return
566ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.event_generate("<<Copy>>")
567ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
568ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
569ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def paste(self,event):
570ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.event_generate("<<Paste>>")
571ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.see("insert")
572ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
573ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
574ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def select_all(self, event=None):
575ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.tag_add("sel", "1.0", "end-1c")
576ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.mark_set("insert", "1.0")
577ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.see("insert")
578ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
579ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
580ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def remove_selection(self, event=None):
581ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.tag_remove("sel", "1.0", "end")
582ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.see("insert")
583ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
584ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def move_at_edge_if_selection(self, edge_index):
585ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Cursor move begins at start or end of selection
586ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
587ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        When a left/right cursor key is pressed create and return to Tkinter a
588ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        function which causes a cursor move from the associated edge of the
589ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        selection.
590ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
591ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
592ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self_text_index = self.text.index
593ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self_text_mark_set = self.text.mark_set
594ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        edges_table = ("sel.first+1c", "sel.last-1c")
595ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        def move_at_edge(event):
596ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if (event.state & 5) == 0: # no shift(==1) or control(==4) pressed
597ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                try:
598ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self_text_index("sel.first")
599ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self_text_mark_set("insert", edges_table[edge_index])
600ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                except TclError:
601ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    pass
602ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return move_at_edge
603ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
604ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def del_word_left(self, event):
605ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.event_generate('<Meta-Delete>')
606ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
607ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
608ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def del_word_right(self, event):
609ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.event_generate('<Meta-d>')
610ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
611ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
612ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def find_event(self, event):
613ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        SearchDialog.find(self.text)
614ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
615ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
616ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def find_again_event(self, event):
617ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        SearchDialog.find_again(self.text)
618ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
619ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
620ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def find_selection_event(self, event):
621ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        SearchDialog.find_selection(self.text)
622ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
623ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
624ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def find_in_files_event(self, event):
625ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        GrepDialog.grep(self.text, self.io, self.flist)
626ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
627ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
628ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def replace_event(self, event):
629ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ReplaceDialog.replace(self.text)
630ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
631ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
632ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def goto_line_event(self, event):
633ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text = self.text
634ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        lineno = tkSimpleDialog.askinteger("Goto",
635ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                "Go to line number:",parent=text)
636ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if lineno is None:
637ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return "break"
638ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if lineno <= 0:
639ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.bell()
640ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return "break"
641ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.mark_set("insert", "%d.0" % lineno)
642ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.see("insert")
643ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
644ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def open_module(self, event=None):
645ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # XXX Shouldn't this be in IOBinding or in FileList?
646ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
647ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            name = self.text.get("sel.first", "sel.last")
648ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except TclError:
649ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            name = ""
650ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
651ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            name = name.strip()
652ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        name = tkSimpleDialog.askstring("Module",
653ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                 "Enter the name of a Python module\n"
654ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                 "to search on sys.path and open:",
655ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                 parent=self.text, initialvalue=name)
656ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if name:
657ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            name = name.strip()
658ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not name:
659ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return
660ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # XXX Ought to insert current file's directory in front of path
661ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
662ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            (f, file, (suffix, mode, type)) = _find_module(name)
663ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except (NameError, ImportError), msg:
664ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            tkMessageBox.showerror("Import error", str(msg), parent=self.text)
665ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return
666ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if type != imp.PY_SOURCE:
667ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            tkMessageBox.showerror("Unsupported type",
668ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                "%s is not a source module" % name, parent=self.text)
669ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return
670ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if f:
671ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            f.close()
672ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.flist:
673ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.flist.open(file)
674ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
675ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.io.loadfile(file)
676ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
677ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def open_class_browser(self, event=None):
678ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        filename = self.io.filename
679ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not filename:
680ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            tkMessageBox.showerror(
681ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                "No filename",
682ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                "This buffer has no associated filename",
683ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                master=self.text)
684ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.focus_set()
685ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return None
686ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        head, tail = os.path.split(filename)
687ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base, ext = os.path.splitext(tail)
688ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        from idlelib import ClassBrowser
689ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ClassBrowser.ClassBrowser(self.flist, base, [head])
690ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
691ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def open_path_browser(self, event=None):
692ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        from idlelib import PathBrowser
693ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        PathBrowser.PathBrowser(self.flist)
694ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
695ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def gotoline(self, lineno):
696ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if lineno is not None and lineno > 0:
697ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.mark_set("insert", "%d.0" % lineno)
698ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.tag_remove("sel", "1.0", "end")
699ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.tag_add("sel", "insert", "insert +1l")
700ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.center()
701ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
702ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def ispythonsource(self, filename):
703ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not filename or os.path.isdir(filename):
704ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return True
705ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base, ext = os.path.splitext(os.path.basename(filename))
706ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if os.path.normcase(ext) in (".py", ".pyw"):
707ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return True
708ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
709ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            f = open(filename)
710ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            line = f.readline()
711ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            f.close()
712ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except IOError:
713ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return False
714ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return line.startswith('#!') and line.find('python') >= 0
715ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
716ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def close_hook(self):
717ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.flist:
718ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.flist.unregister_maybe_terminate(self)
719ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.flist = None
720ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
721ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def set_close_hook(self, close_hook):
722ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.close_hook = close_hook
723ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
724ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def filename_change_hook(self):
725ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.flist:
726ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.flist.filename_changed_edit(self)
727ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.saved_change_hook()
728ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.top.update_windowlist_registry(self)
729ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.ResetColorizer()
730ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
731ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def _addcolorizer(self):
732ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.color:
733ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return
734ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.ispythonsource(self.io.filename):
735ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.color = self.ColorDelegator()
736ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # can add more colorizers here...
737ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.color:
738ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.per.removefilter(self.undo)
739ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.per.insertfilter(self.color)
740ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.per.insertfilter(self.undo)
741ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
742ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def _rmcolorizer(self):
743ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not self.color:
744ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return
745ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.color.removecolors()
746ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.per.removefilter(self.color)
747ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.color = None
748ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
749ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def ResetColorizer(self):
750ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        "Update the colour theme"
751ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Called from self.filename_change_hook and from configDialog.py
752ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self._rmcolorizer()
753ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self._addcolorizer()
754ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        theme = idleConf.GetOption('main','Theme','name')
755ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        normal_colors = idleConf.GetHighlight(theme, 'normal')
756ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cursor_color = idleConf.GetHighlight(theme, 'cursor', fgBg='fg')
757ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        select_colors = idleConf.GetHighlight(theme, 'hilite')
758ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.config(
759ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            foreground=normal_colors['foreground'],
760ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            background=normal_colors['background'],
761ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            insertbackground=cursor_color,
762ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            selectforeground=select_colors['foreground'],
763ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            selectbackground=select_colors['background'],
764ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            )
765ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
766ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def ResetFont(self):
767ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        "Update the text widgets' font if it is changed"
768ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Called from configDialog.py
769ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        fontWeight='normal'
770ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if idleConf.GetOption('main','EditorWindow','font-bold',type='bool'):
771ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            fontWeight='bold'
772ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.config(font=(idleConf.GetOption('main','EditorWindow','font'),
773ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                idleConf.GetOption('main','EditorWindow','font-size',
774ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                   type='int'),
775ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                fontWeight))
776ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
777ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def RemoveKeybindings(self):
778ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        "Remove the keybindings before they are changed."
779ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Called from configDialog.py
780ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.Bindings.default_keydefs = keydefs = idleConf.GetCurrentKeySet()
781ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for event, keylist in keydefs.items():
782ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.event_delete(event, *keylist)
783ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for extensionName in self.get_standard_extension_names():
784ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            xkeydefs = idleConf.GetExtensionBindings(extensionName)
785ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if xkeydefs:
786ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                for event, keylist in xkeydefs.items():
787ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self.text.event_delete(event, *keylist)
788ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
789ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def ApplyKeybindings(self):
790ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        "Update the keybindings after they are changed"
791ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Called from configDialog.py
792ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.Bindings.default_keydefs = keydefs = idleConf.GetCurrentKeySet()
793ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.apply_bindings()
794ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for extensionName in self.get_standard_extension_names():
795ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            xkeydefs = idleConf.GetExtensionBindings(extensionName)
796ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if xkeydefs:
797ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.apply_bindings(xkeydefs)
798ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #update menu accelerators
799ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        menuEventDict = {}
800ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for menu in self.Bindings.menudefs:
801ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            menuEventDict[menu[0]] = {}
802ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for item in menu[1]:
803ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if item:
804ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    menuEventDict[menu[0]][prepstr(item[0])[1]] = item[1]
805ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for menubarItem in self.menudict.keys():
806ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            menu = self.menudict[menubarItem]
807ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            end = menu.index(END) + 1
808ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for index in range(0, end):
809ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if menu.type(index) == 'command':
810ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    accel = menu.entrycget(index, 'accelerator')
811ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    if accel:
812ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        itemName = menu.entrycget(index, 'label')
813ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        event = ''
814ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        if menubarItem in menuEventDict:
815ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            if itemName in menuEventDict[menubarItem]:
816ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                event = menuEventDict[menubarItem][itemName]
817ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        if event:
818ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            accel = get_accelerator(keydefs, event)
819ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            menu.entryconfig(index, accelerator=accel)
820ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
821ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def set_notabs_indentwidth(self):
822ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        "Update the indentwidth if changed and not using tabs in this window"
823ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Called from configDialog.py
824ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not self.usetabs:
825ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.indentwidth = idleConf.GetOption('main', 'Indent','num-spaces',
826ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                                  type='int')
827ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
828ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def reset_help_menu_entries(self):
829ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        "Update the additional help entries on the Help menu"
830ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        help_list = idleConf.GetAllExtraHelpSourcesList()
831ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        helpmenu = self.menudict['help']
832ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # first delete the extra help entries, if any
833ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        helpmenu_length = helpmenu.index(END)
834ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if helpmenu_length > self.base_helpmenu_length:
835ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            helpmenu.delete((self.base_helpmenu_length + 1), helpmenu_length)
836ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # then rebuild them
837ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if help_list:
838ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            helpmenu.add_separator()
839ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for entry in help_list:
840ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                cmd = self.__extra_help_callback(entry[1])
841ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                helpmenu.add_command(label=entry[0], command=cmd)
842ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # and update the menu dictionary
843ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.menudict['help'] = helpmenu
844ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
845ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __extra_help_callback(self, helpfile):
846ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        "Create a callback with the helpfile value frozen at definition time"
847ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        def display_extra_help(helpfile=helpfile):
848ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if not helpfile.startswith(('www', 'http')):
849ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                helpfile = os.path.normpath(helpfile)
850ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if sys.platform[:3] == 'win':
851ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                try:
852ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    os.startfile(helpfile)
853ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                except WindowsError as why:
854ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    tkMessageBox.showerror(title='Document Start Failure',
855ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        message=str(why), parent=self.text)
856ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
857ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                webbrowser.open(helpfile)
858ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return display_extra_help
859ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
860ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def update_recent_files_list(self, new_file=None):
861ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        "Load and update the recent files list and menus"
862ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        rf_list = []
863ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if os.path.exists(self.recent_files_path):
864ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            rf_list_file = open(self.recent_files_path,'r')
865ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
866ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                rf_list = rf_list_file.readlines()
867ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            finally:
868ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                rf_list_file.close()
869ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if new_file:
870ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            new_file = os.path.abspath(new_file) + '\n'
871ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if new_file in rf_list:
872ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                rf_list.remove(new_file)  # move to top
873ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            rf_list.insert(0, new_file)
874ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # clean and save the recent files list
875ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        bad_paths = []
876ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for path in rf_list:
877ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if '\0' in path or not os.path.exists(path[0:-1]):
878ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                bad_paths.append(path)
879ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        rf_list = [path for path in rf_list if path not in bad_paths]
880ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ulchars = "1234567890ABCDEFGHIJK"
881ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        rf_list = rf_list[0:len(ulchars)]
882ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
883ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            with open(self.recent_files_path, 'w') as rf_file:
884ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                rf_file.writelines(rf_list)
885ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except IOError as err:
886ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if not getattr(self.root, "recentfilelist_error_displayed", False):
887ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.root.recentfilelist_error_displayed = True
888ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                tkMessageBox.showerror(title='IDLE Error',
889ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    message='Unable to update Recent Files list:\n%s'
890ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        % str(err),
891ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    parent=self.text)
892ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # for each edit window instance, construct the recent files menu
893ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for instance in self.top.instance_dict.keys():
894ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            menu = instance.recent_files_menu
895ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            menu.delete(0, END)  # clear, and rebuild:
896ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for i, file_name in enumerate(rf_list):
897ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                file_name = file_name.rstrip()  # zap \n
898ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # make unicode string to display non-ASCII chars correctly
899ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                ufile_name = self._filename_to_unicode(file_name)
900ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                callback = instance.__recent_file_callback(file_name)
901ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                menu.add_command(label=ulchars[i] + " " + ufile_name,
902ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                 command=callback,
903ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                 underline=0)
904ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
905ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __recent_file_callback(self, file_name):
906ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        def open_recent_file(fn_closure=file_name):
907ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.io.open(editFile=fn_closure)
908ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return open_recent_file
909ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
910ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def saved_change_hook(self):
911ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        short = self.short_title()
912ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        long = self.long_title()
913ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if short and long:
914ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            title = short + " - " + long
915ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        elif short:
916ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            title = short
917ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        elif long:
918ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            title = long
919ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
920ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            title = "Untitled"
921ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        icon = short or long or title
922ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not self.get_saved():
923ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            title = "*%s*" % title
924ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            icon = "*%s" % icon
925ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.top.wm_title(title)
926ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.top.wm_iconname(icon)
927ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
928ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def get_saved(self):
929ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.undo.get_saved()
930ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
931ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def set_saved(self, flag):
932ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.undo.set_saved(flag)
933ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
934ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def reset_undo(self):
935ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.undo.reset_undo()
936ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
937ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def short_title(self):
938ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        filename = self.io.filename
939ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if filename:
940ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            filename = os.path.basename(filename)
941ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # return unicode string to display non-ASCII chars correctly
942ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self._filename_to_unicode(filename)
943ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
944ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def long_title(self):
945ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # return unicode string to display non-ASCII chars correctly
946ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self._filename_to_unicode(self.io.filename or "")
947ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
948ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def center_insert_event(self, event):
949ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.center()
950ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
951ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def center(self, mark="insert"):
952ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text = self.text
953ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        top, bot = self.getwindowlines()
954ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        lineno = self.getlineno(mark)
955ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        height = bot - top
956ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        newtop = max(1, lineno - height//2)
957ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.yview(float(newtop))
958ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
959ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def getwindowlines(self):
960ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text = self.text
961ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        top = self.getlineno("@0,0")
962ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        bot = self.getlineno("@0,65535")
963ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if top == bot and text.winfo_height() == 1:
964ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Geometry manager hasn't run yet
965ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            height = int(text['height'])
966ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            bot = top + height - 1
967ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return top, bot
968ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
969ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def getlineno(self, mark="insert"):
970ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text = self.text
971ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return int(float(text.index(mark)))
972ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
973ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def get_geometry(self):
974ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        "Return (width, height, x, y)"
975ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        geom = self.top.wm_geometry()
976ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        m = re.match(r"(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geom)
977ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tuple = (map(int, m.groups()))
978ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return tuple
979ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
980ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def close_event(self, event):
981ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.close()
982ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
983ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def maybesave(self):
984ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.io:
985ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if not self.get_saved():
986ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if self.top.state()!='normal':
987ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self.top.deiconify()
988ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.top.lower()
989ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.top.lift()
990ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return self.io.maybesave()
991ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
992ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def close(self):
993ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        reply = self.maybesave()
994ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if str(reply) != "cancel":
995ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self._close()
996ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return reply
997ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
998ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def _close(self):
999ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.io.filename:
1000ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.update_recent_files_list(new_file=self.io.filename)
1001ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        WindowList.unregister_callback(self.postwindowsmenu)
1002ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.unload_extensions()
1003ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.io.close()
1004ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.io = None
1005ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.undo = None
1006ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.color:
1007ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.color.close(False)
1008ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.color = None
1009ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text = None
1010ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.tkinter_vars = None
1011ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.per.close()
1012ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.per = None
1013ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.top.destroy()
1014ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.close_hook:
1015ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # unless override: unregister from flist, terminate if last window
1016ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.close_hook()
1017ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1018ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def load_extensions(self):
1019ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.extensions = {}
1020ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.load_standard_extensions()
1021ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1022ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def unload_extensions(self):
1023ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for ins in self.extensions.values():
1024ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if hasattr(ins, "close"):
1025ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                ins.close()
1026ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.extensions = {}
1027ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1028ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def load_standard_extensions(self):
1029ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for name in self.get_standard_extension_names():
1030ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
1031ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.load_extension(name)
1032ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except:
1033ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                print "Failed to load extension", repr(name)
1034ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                import traceback
1035ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                traceback.print_exc()
1036ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1037ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def get_standard_extension_names(self):
1038ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return idleConf.GetExtensions(editor_only=True)
1039ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1040ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def load_extension(self, name):
1041ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
1042ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            mod = __import__(name, globals(), locals(), [])
1043ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except ImportError:
1044ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            print "\nFailed to import extension: ", name
1045ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return
1046ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = getattr(mod, name)
1047ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        keydefs = idleConf.GetExtensionBindings(name)
1048ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if hasattr(cls, "menudefs"):
1049ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.fill_menus(cls.menudefs, keydefs)
1050ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ins = cls(self)
1051ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.extensions[name] = ins
1052ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if keydefs:
1053ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.apply_bindings(keydefs)
1054ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for vevent in keydefs.keys():
1055ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                methodname = vevent.replace("-", "_")
1056ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                while methodname[:1] == '<':
1057ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    methodname = methodname[1:]
1058ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                while methodname[-1:] == '>':
1059ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    methodname = methodname[:-1]
1060ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                methodname = methodname + "_event"
1061ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if hasattr(ins, methodname):
1062ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self.text.bind(vevent, getattr(ins, methodname))
1063ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1064ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def apply_bindings(self, keydefs=None):
1065ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if keydefs is None:
1066ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            keydefs = self.Bindings.default_keydefs
1067ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text = self.text
1068ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.keydefs = keydefs
1069ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for event, keylist in keydefs.items():
1070ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if keylist:
1071ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                text.event_add(event, *keylist)
1072ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1073ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def fill_menus(self, menudefs=None, keydefs=None):
1074ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Add appropriate entries to the menus and submenus
1075ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1076ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        Menus that are absent or None in self.menudict are ignored.
1077ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
1078ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if menudefs is None:
1079ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            menudefs = self.Bindings.menudefs
1080ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if keydefs is None:
1081ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            keydefs = self.Bindings.default_keydefs
1082ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        menudict = self.menudict
1083ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text = self.text
1084ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for mname, entrylist in menudefs:
1085ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            menu = menudict.get(mname)
1086ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if not menu:
1087ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                continue
1088ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for entry in entrylist:
1089ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if not entry:
1090ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    menu.add_separator()
1091ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
1092ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    label, eventname = entry
1093ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    checkbutton = (label[:1] == '!')
1094ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    if checkbutton:
1095ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        label = label[1:]
1096ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    underline, label = prepstr(label)
1097ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    accelerator = get_accelerator(keydefs, eventname)
1098ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    def command(text=text, eventname=eventname):
1099ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        text.event_generate(eventname)
1100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    if checkbutton:
1101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        var = self.get_var_obj(eventname, BooleanVar)
1102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        menu.add_checkbutton(label=label, underline=underline,
1103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            command=command, accelerator=accelerator,
1104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            variable=var)
1105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    else:
1106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        menu.add_command(label=label, underline=underline,
1107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                         command=command,
1108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                         accelerator=accelerator)
1109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def getvar(self, name):
1111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        var = self.get_var_obj(name)
1112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if var:
1113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            value = var.get()
1114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return value
1115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
1116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            raise NameError, name
1117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def setvar(self, name, value, vartype=None):
1119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        var = self.get_var_obj(name, vartype)
1120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if var:
1121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            var.set(value)
1122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
1123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            raise NameError, name
1124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1125ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def get_var_obj(self, name, vartype=None):
1126ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        var = self.tkinter_vars.get(name)
1127ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not var and vartype:
1128ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # create a Tkinter variable object with self.text as master:
1129ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.tkinter_vars[name] = var = vartype(self.text)
1130ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return var
1131ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1132ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Tk implementations of "virtual text methods" -- each platform
1133ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # reusing IDLE's support code needs to define these for its GUI's
1134ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # flavor of widget.
1135ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1136ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Is character at text_index in a Python string?  Return 0 for
1137ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # "guaranteed no", true for anything else.  This info is expensive
1138ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # to compute ab initio, but is probably already known by the
1139ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # platform's colorizer.
1140ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1141ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def is_char_in_string(self, text_index):
1142ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.color:
1143ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Return true iff colorizer hasn't (re)gotten this far
1144ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # yet, or the character is tagged as being in a string
1145ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return self.text.tag_prevrange("TODO", text_index) or \
1146ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                   "STRING" in self.text.tag_names(text_index)
1147ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
1148ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # The colorizer is missing: assume the worst
1149ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return 1
1150ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1151ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # If a selection is defined in the text widget, return (start,
1152ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # end) as Tkinter text indices, otherwise return (None, None)
1153ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def get_selection_indices(self):
1154ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
1155ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            first = self.text.index("sel.first")
1156ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            last = self.text.index("sel.last")
1157ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return first, last
1158ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except TclError:
1159ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return None, None
1160ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1161ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Return the text widget's current view of what a tab stop means
1162ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # (equivalent width in spaces).
1163ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1164ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def get_tabwidth(self):
1165ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        current = self.text['tabs'] or TK_TABWIDTH_DEFAULT
1166ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return int(current)
1167ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1168ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Set the text widget's current view of what a tab stop means.
1169ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1170ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def set_tabwidth(self, newtabwidth):
1171ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text = self.text
1172ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.get_tabwidth() != newtabwidth:
1173ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            pixels = text.tk.call("font", "measure", text["font"],
1174ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                  "-displayof", text.master,
1175ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                  "n" * newtabwidth)
1176ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.configure(tabs=pixels)
1177ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1178ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # If ispythonsource and guess are true, guess a good value for
1179ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # indentwidth based on file content (if possible), and if
1180ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # indentwidth != tabwidth set usetabs false.
1181ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # In any case, adjust the Text widget's view of what a tab
1182ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # character means.
1183ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1184ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def set_indentation_params(self, ispythonsource, guess=True):
1185ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if guess and ispythonsource:
1186ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            i = self.guess_indent()
1187ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if 2 <= i <= 8:
1188ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.indentwidth = i
1189ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if self.indentwidth != self.tabwidth:
1190ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.usetabs = False
1191ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.set_tabwidth(self.tabwidth)
1192ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1193ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def smart_backspace_event(self, event):
1194ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text = self.text
1195ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        first, last = self.get_selection_indices()
1196ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if first and last:
1197ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.delete(first, last)
1198ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.mark_set("insert", first)
1199ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return "break"
1200ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Delete whitespace left, until hitting a real char or closest
1201ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # preceding virtual tab stop.
1202ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        chars = text.get("insert linestart", "insert")
1203ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if chars == '':
1204ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if text.compare("insert", ">", "1.0"):
1205ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # easy: delete preceding newline
1206ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                text.delete("insert-1c")
1207ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
1208ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                text.bell()     # at start of buffer
1209ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return "break"
1210ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if  chars[-1] not in " \t":
1211ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # easy: delete preceding real char
1212ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.delete("insert-1c")
1213ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return "break"
1214ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Ick.  It may require *inserting* spaces if we back up over a
1215ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # tab character!  This is written to be clear, not fast.
1216ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tabwidth = self.tabwidth
1217ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        have = len(chars.expandtabs(tabwidth))
1218ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        assert have > 0
1219ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        want = ((have - 1) // self.indentwidth) * self.indentwidth
1220ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Debug prompt is multilined....
1221ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.context_use_ps1:
1222ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            last_line_of_prompt = sys.ps1.split('\n')[-1]
1223ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
1224ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            last_line_of_prompt = ''
1225ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ncharsdeleted = 0
1226ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        while 1:
1227ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if chars == last_line_of_prompt:
1228ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                break
1229ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            chars = chars[:-1]
1230ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            ncharsdeleted = ncharsdeleted + 1
1231ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            have = len(chars.expandtabs(tabwidth))
1232ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if have <= want or chars[-1] not in " \t":
1233ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                break
1234ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.undo_block_start()
1235ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.delete("insert-%dc" % ncharsdeleted, "insert")
1236ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if have < want:
1237ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.insert("insert", ' ' * (want - have))
1238ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.undo_block_stop()
1239ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
1240ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1241ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def smart_indent_event(self, event):
1242ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # if intraline selection:
1243ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #     delete it
1244ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # elif multiline selection:
1245ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #     do indent-region
1246ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # else:
1247ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #     indent one level
1248ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text = self.text
1249ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        first, last = self.get_selection_indices()
1250ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.undo_block_start()
1251ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
1252ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if first and last:
1253ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if index2line(first) != index2line(last):
1254ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    return self.indent_region_event(event)
1255ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                text.delete(first, last)
1256ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                text.mark_set("insert", first)
1257ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            prefix = text.get("insert linestart", "insert")
1258ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            raw, effective = classifyws(prefix, self.tabwidth)
1259ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if raw == len(prefix):
1260ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # only whitespace to the left
1261ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.reindent_to(effective + self.indentwidth)
1262ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
1263ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # tab to the next 'stop' within or to right of line's text:
1264ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if self.usetabs:
1265ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    pad = '\t'
1266ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
1267ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    effective = len(prefix.expandtabs(self.tabwidth))
1268ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    n = self.indentwidth
1269ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    pad = ' ' * (n - effective % n)
1270ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                text.insert("insert", pad)
1271ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.see("insert")
1272ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return "break"
1273ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        finally:
1274ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.undo_block_stop()
1275ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1276ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def newline_and_indent_event(self, event):
1277ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text = self.text
1278ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        first, last = self.get_selection_indices()
1279ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.undo_block_start()
1280ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
1281ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if first and last:
1282ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                text.delete(first, last)
1283ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                text.mark_set("insert", first)
1284ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            line = text.get("insert linestart", "insert")
1285ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            i, n = 0, len(line)
1286ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            while i < n and line[i] in " \t":
1287ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                i = i+1
1288ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if i == n:
1289ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # the cursor is in or at leading indentation in a continuation
1290ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # line; just inject an empty line at the start
1291ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                text.insert("insert linestart", '\n')
1292ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return "break"
1293ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            indent = line[:i]
1294ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # strip whitespace before insert point unless it's in the prompt
1295ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            i = 0
1296ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            last_line_of_prompt = sys.ps1.split('\n')[-1]
1297ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            while line and line[-1] in " \t" and line != last_line_of_prompt:
1298ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                line = line[:-1]
1299ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                i = i+1
1300ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if i:
1301ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                text.delete("insert - %d chars" % i, "insert")
1302ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # strip whitespace after insert point
1303ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            while text.get("insert") in " \t":
1304ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                text.delete("insert")
1305ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # start new line
1306ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.insert("insert", '\n')
1307ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1308ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # adjust indentation for continuations and block
1309ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # open/close first need to find the last stmt
1310ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            lno = index2line(text.index('insert'))
1311ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            y = PyParse.Parser(self.indentwidth, self.tabwidth)
1312ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if not self.context_use_ps1:
1313ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                for context in self.num_context_lines:
1314ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    startat = max(lno - context, 1)
1315ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    startatindex = repr(startat) + ".0"
1316ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    rawtext = text.get(startatindex, "insert")
1317ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    y.set_str(rawtext)
1318ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    bod = y.find_good_parse_start(
1319ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                              self.context_use_ps1,
1320ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                              self._build_char_in_string_func(startatindex))
1321ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    if bod is not None or startat == 1:
1322ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        break
1323ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                y.set_lo(bod or 0)
1324ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
1325ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                r = text.tag_prevrange("console", "insert")
1326ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if r:
1327ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    startatindex = r[1]
1328ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
1329ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    startatindex = "1.0"
1330ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                rawtext = text.get(startatindex, "insert")
1331ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                y.set_str(rawtext)
1332ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                y.set_lo(0)
1333ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1334ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            c = y.get_continuation_type()
1335ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if c != PyParse.C_NONE:
1336ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # The current stmt hasn't ended yet.
1337ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if c == PyParse.C_STRING_FIRST_LINE:
1338ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # after the first line of a string; do not indent at all
1339ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    pass
1340ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                elif c == PyParse.C_STRING_NEXT_LINES:
1341ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # inside a string which started before this line;
1342ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # just mimic the current indent
1343ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    text.insert("insert", indent)
1344ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                elif c == PyParse.C_BRACKET:
1345ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # line up with the first (if any) element of the
1346ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # last open bracket structure; else indent one
1347ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # level beyond the indent of the line with the
1348ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # last open bracket
1349ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self.reindent_to(y.compute_bracket_indent())
1350ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                elif c == PyParse.C_BACKSLASH:
1351ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # if more than one line in this stmt already, just
1352ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # mimic the current indent; else if initial line
1353ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # has a start on an assignment stmt, indent to
1354ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # beyond leftmost =; else to beyond first chunk of
1355ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # non-whitespace on initial line
1356ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    if y.get_num_lines_in_stmt() > 1:
1357ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        text.insert("insert", indent)
1358ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    else:
1359ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        self.reindent_to(y.compute_backslash_indent())
1360ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
1361ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    assert 0, "bogus continuation type %r" % (c,)
1362ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return "break"
1363ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1364ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # This line starts a brand new stmt; indent relative to
1365ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # indentation of initial line of closest preceding
1366ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # interesting stmt.
1367ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            indent = y.get_base_indent_string()
1368ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.insert("insert", indent)
1369ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if y.is_block_opener():
1370ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.smart_indent_event(event)
1371ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            elif indent and y.is_block_closer():
1372ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.smart_backspace_event(event)
1373ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return "break"
1374ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        finally:
1375ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.see("insert")
1376ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.undo_block_stop()
1377ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1378ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Our editwin provides a is_char_in_string function that works
1379ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # with a Tk text index, but PyParse only knows about offsets into
1380ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # a string. This builds a function for PyParse that accepts an
1381ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # offset.
1382ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1383ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def _build_char_in_string_func(self, startindex):
1384ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        def inner(offset, _startindex=startindex,
1385ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  _icis=self.is_char_in_string):
1386ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return _icis(_startindex + "+%dc" % offset)
1387ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return inner
1388ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1389ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def indent_region_event(self, event):
1390ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        head, tail, chars, lines = self.get_region()
1391ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pos in range(len(lines)):
1392ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            line = lines[pos]
1393ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if line:
1394ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                raw, effective = classifyws(line, self.tabwidth)
1395ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                effective = effective + self.indentwidth
1396ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                lines[pos] = self._make_blanks(effective) + line[raw:]
1397ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.set_region(head, tail, chars, lines)
1398ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
1399ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1400ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def dedent_region_event(self, event):
1401ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        head, tail, chars, lines = self.get_region()
1402ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pos in range(len(lines)):
1403ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            line = lines[pos]
1404ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if line:
1405ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                raw, effective = classifyws(line, self.tabwidth)
1406ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                effective = max(effective - self.indentwidth, 0)
1407ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                lines[pos] = self._make_blanks(effective) + line[raw:]
1408ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.set_region(head, tail, chars, lines)
1409ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
1410ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1411ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def comment_region_event(self, event):
1412ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        head, tail, chars, lines = self.get_region()
1413ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pos in range(len(lines) - 1):
1414ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            line = lines[pos]
1415ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            lines[pos] = '##' + line
1416ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.set_region(head, tail, chars, lines)
1417ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1418ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def uncomment_region_event(self, event):
1419ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        head, tail, chars, lines = self.get_region()
1420ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pos in range(len(lines)):
1421ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            line = lines[pos]
1422ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if not line:
1423ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                continue
1424ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if line[:2] == '##':
1425ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                line = line[2:]
1426ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            elif line[:1] == '#':
1427ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                line = line[1:]
1428ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            lines[pos] = line
1429ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.set_region(head, tail, chars, lines)
1430ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1431ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def tabify_region_event(self, event):
1432ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        head, tail, chars, lines = self.get_region()
1433ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tabwidth = self._asktabwidth()
1434ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if tabwidth is None: return
1435ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pos in range(len(lines)):
1436ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            line = lines[pos]
1437ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if line:
1438ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                raw, effective = classifyws(line, tabwidth)
1439ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                ntabs, nspaces = divmod(effective, tabwidth)
1440ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:]
1441ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.set_region(head, tail, chars, lines)
1442ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1443ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def untabify_region_event(self, event):
1444ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        head, tail, chars, lines = self.get_region()
1445ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tabwidth = self._asktabwidth()
1446ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if tabwidth is None: return
1447ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pos in range(len(lines)):
1448ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            lines[pos] = lines[pos].expandtabs(tabwidth)
1449ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.set_region(head, tail, chars, lines)
1450ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1451ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def toggle_tabs_event(self, event):
1452ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.askyesno(
1453ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh              "Toggle tabs",
1454ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh              "Turn tabs " + ("on", "off")[self.usetabs] +
1455ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh              "?\nIndent width " +
1456ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh              ("will be", "remains at")[self.usetabs] + " 8." +
1457ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh              "\n Note: a tab is always 8 columns",
1458ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh              parent=self.text):
1459ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.usetabs = not self.usetabs
1460ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Try to prevent inconsistent indentation.
1461ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # User must change indent width manually after using tabs.
1462ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.indentwidth = 8
1463ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
1464ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1465ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # XXX this isn't bound to anything -- see tabwidth comments
1466ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh##     def change_tabwidth_event(self, event):
1467ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh##         new = self._asktabwidth()
1468ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh##         if new != self.tabwidth:
1469ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh##             self.tabwidth = new
1470ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh##             self.set_indentation_params(0, guess=0)
1471ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh##         return "break"
1472ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1473ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def change_indentwidth_event(self, event):
1474ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        new = self.askinteger(
1475ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  "Indent width",
1476ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  "New indent width (2-16)\n(Always use 8 when using tabs)",
1477ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  parent=self.text,
1478ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  initialvalue=self.indentwidth,
1479ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  minvalue=2,
1480ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  maxvalue=16)
1481ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if new and new != self.indentwidth and not self.usetabs:
1482ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.indentwidth = new
1483ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
1484ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1485ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def get_region(self):
1486ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text = self.text
1487ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        first, last = self.get_selection_indices()
1488ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if first and last:
1489ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            head = text.index(first + " linestart")
1490ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            tail = text.index(last + "-1c lineend +1c")
1491ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
1492ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            head = text.index("insert linestart")
1493ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            tail = text.index("insert lineend +1c")
1494ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        chars = text.get(head, tail)
1495ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        lines = chars.split("\n")
1496ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return head, tail, chars, lines
1497ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1498ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def set_region(self, head, tail, chars, lines):
1499ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text = self.text
1500ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        newchars = "\n".join(lines)
1501ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if newchars == chars:
1502ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.bell()
1503ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return
1504ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.tag_remove("sel", "1.0", "end")
1505ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.mark_set("insert", head)
1506ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.undo_block_start()
1507ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.delete(head, tail)
1508ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.insert(head, newchars)
1509ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.undo_block_stop()
1510ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.tag_add("sel", head, "insert")
1511ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1512ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Make string that displays as n leading blanks.
1513ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1514ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def _make_blanks(self, n):
1515ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.usetabs:
1516ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            ntabs, nspaces = divmod(n, self.tabwidth)
1517ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return '\t' * ntabs + ' ' * nspaces
1518ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
1519ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return ' ' * n
1520ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1521ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Delete from beginning of line to insert point, then reinsert
1522ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # column logical (meaning use tabs if appropriate) spaces.
1523ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1524ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def reindent_to(self, column):
1525ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text = self.text
1526ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.undo_block_start()
1527ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if text.compare("insert linestart", "!=", "insert"):
1528ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.delete("insert linestart", "insert")
1529ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if column:
1530ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text.insert("insert", self._make_blanks(column))
1531ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        text.undo_block_stop()
1532ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1533ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def _asktabwidth(self):
1534ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.askinteger(
1535ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            "Tab width",
1536ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            "Columns per tab? (2-16)",
1537ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            parent=self.text,
1538ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            initialvalue=self.indentwidth,
1539ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            minvalue=2,
1540ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            maxvalue=16)
1541ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1542ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Guess indentwidth from text content.
1543ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Return guessed indentwidth.  This should not be believed unless
1544ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # it's in a reasonable range (e.g., it will be 0 if no indented
1545ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # blocks are found).
1546ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1547ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def guess_indent(self):
1548ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        opener, indented = IndentSearcher(self.text, self.tabwidth).run()
1549ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if opener and indented:
1550ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            raw, indentsmall = classifyws(opener, self.tabwidth)
1551ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            raw, indentlarge = classifyws(indented, self.tabwidth)
1552ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
1553ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            indentsmall = indentlarge = 0
1554ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return indentlarge - indentsmall
1555ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1556ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# "line.col" -> line, as an int
1557ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef index2line(index):
1558ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    return int(float(index))
1559ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1560ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Look at the leading whitespace in s.
1561ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Return pair (# of leading ws characters,
1562ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#              effective # of leading blanks after expanding
1563ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#              tabs to width tabwidth)
1564ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1565ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef classifyws(s, tabwidth):
1566ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    raw = effective = 0
1567ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    for ch in s:
1568ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if ch == ' ':
1569ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            raw = raw + 1
1570ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            effective = effective + 1
1571ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        elif ch == '\t':
1572ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            raw = raw + 1
1573ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            effective = (effective // tabwidth + 1) * tabwidth
1574ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
1575ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            break
1576ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    return raw, effective
1577ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1578ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport tokenize
1579ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh_tokenize = tokenize
1580ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdel tokenize
1581ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1582ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass IndentSearcher(object):
1583ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1584ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # .run() chews over the Text widget, looking for a block opener
1585ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # and the stmt following it.  Returns a pair,
1586ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    #     (line containing block opener, line containing stmt)
1587ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Either or both may be None.
1588ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1589ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __init__(self, text, tabwidth):
1590ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text = text
1591ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.tabwidth = tabwidth
1592ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.i = self.finished = 0
1593ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.blkopenline = self.indentedline = None
1594ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1595ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def readline(self):
1596ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.finished:
1597ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return ""
1598ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        i = self.i = self.i + 1
1599ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        mark = repr(i) + ".0"
1600ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.text.compare(mark, ">=", "end"):
1601ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return ""
1602ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.text.get(mark, mark + " lineend+1c")
1603ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1604ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def tokeneater(self, type, token, start, end, line,
1605ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                   INDENT=_tokenize.INDENT,
1606ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                   NAME=_tokenize.NAME,
1607ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                   OPENERS=('class', 'def', 'for', 'if', 'try', 'while')):
1608ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.finished:
1609ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            pass
1610ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        elif type == NAME and token in OPENERS:
1611ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.blkopenline = line
1612ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        elif type == INDENT and self.blkopenline:
1613ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.indentedline = line
1614ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.finished = 1
1615ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1616ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def run(self):
1617ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        save_tabsize = _tokenize.tabsize
1618ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        _tokenize.tabsize = self.tabwidth
1619ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
1620ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
1621ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                _tokenize.tokenize(self.readline, self.tokeneater)
1622ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except (_tokenize.TokenError, SyntaxError):
1623ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # since we cut off the tokenizer early, we can trigger
1624ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # spurious errors
1625ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                pass
1626ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        finally:
1627ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            _tokenize.tabsize = save_tabsize
1628ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.blkopenline, self.indentedline
1629ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1630ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh### end autoindent code ###
1631ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1632ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef prepstr(s):
1633ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Helper to extract the underscore from a string, e.g.
1634ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # prepstr("Co_py") returns (2, "Copy").
1635ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    i = s.find('_')
1636ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if i >= 0:
1637ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        s = s[:i] + s[i+1:]
1638ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    return i, s
1639ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1640ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1641ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehkeynames = {
1642ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'bracketleft': '[',
1643ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'bracketright': ']',
1644ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'slash': '/',
1645ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh}
1646ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1647ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef get_accelerator(keydefs, eventname):
1648ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    keylist = keydefs.get(eventname)
1649ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # issue10940: temporary workaround to prevent hang with OS X Cocoa Tk 8.5
1650ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # if not keylist:
1651ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if (not keylist) or (macosxSupport.runningAsOSXApp() and eventname in {
1652ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            "<<open-module>>",
1653ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            "<<goto-line>>",
1654ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            "<<change-indentwidth>>"}):
1655ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return ""
1656ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    s = keylist[0]
1657ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    s = re.sub(r"-[a-z]\b", lambda m: m.group().upper(), s)
1658ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s)
1659ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    s = re.sub("Key-", "", s)
1660ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    s = re.sub("Cancel","Ctrl-Break",s)   # dscherer@cmu.edu
1661ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    s = re.sub("Control-", "Ctrl-", s)
1662ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    s = re.sub("-", "+", s)
1663ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    s = re.sub("><", " ", s)
1664ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    s = re.sub("<", "", s)
1665ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    s = re.sub(">", "", s)
1666ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    return s
1667ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1668ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1669ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef fixwordbreaks(root):
1670ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Make sure that Tk's double-click and next/previous word
1671ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # operations use our definition of a word (i.e. an identifier)
1672ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    tk = root.tk
1673ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded
1674ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_]')
1675ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]')
1676ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1677ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1678ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef test():
1679ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    root = Tk()
1680ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    fixwordbreaks(root)
1681ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    root.withdraw()
1682ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if sys.argv[1:]:
1683ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        filename = sys.argv[1]
1684ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    else:
1685ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        filename = None
1686ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    edit = EditorWindow(root=root, filename=filename)
1687ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    edit.set_close_hook(root.quit)
1688ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    edit.text.bind("<<close-all-windows>>", edit.close_event)
1689ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    root.mainloop()
1690ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    root.destroy()
1691ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1692ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehif __name__ == '__main__':
1693ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    test()
1694