EditorWindow.py revision 260cb9034c861fa159f26fba8679ac265af47109
17aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport sys
27aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport os
37aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport re
47aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport imp
57aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererfrom Tkinter import *
67aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport tkSimpleDialog
77aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport tkMessageBox
8fd182cd9d36adefba00d86542eb3134119cdc804Kurt B. Kaiser
9fd182cd9d36adefba00d86542eb3134119cdc804Kurt B. Kaiserimport webbrowser
107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport idlever
117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport WindowList
12c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gavaimport SearchDialog
13c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gavaimport GrepDialog
14c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gavaimport ReplaceDialog
15cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserimport PyParse
16dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gavafrom configHandler import idleConf
173b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gavaimport aboutDialog, textView, configDialog
187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer# The default tab setting for a Text widget, in average-width characters.
207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David SchererTK_TABWIDTH_DEFAULT = 8
217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
22220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiserdef _find_module(fullname, path=None):
23220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser    """Version of imp.find_module() that handles hierarchical module names"""
24220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser
25220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser    file = None
26220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser    for tgt in fullname.split('.'):
27220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser        if file is not None:
28220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser            file.close()            # close intermediate files
29220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser        (file, filename, descr) = imp.find_module(tgt, path)
30220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser        if descr[2] == imp.PY_SOURCE:
31220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser            break                   # find but not load the source file
32220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser        module = imp.load_module(tgt, file, filename, descr)
3369e8afcc9fcd8a41a1035893d60893d51fae62f1Kurt B. Kaiser        try:
3469e8afcc9fcd8a41a1035893d60893d51fae62f1Kurt B. Kaiser            path = module.__path__
3569e8afcc9fcd8a41a1035893d60893d51fae62f1Kurt B. Kaiser        except AttributeError:
3669e8afcc9fcd8a41a1035893d60893d51fae62f1Kurt B. Kaiser            raise ImportError, 'No source for module ' + module.__name__
37220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser    return file, filename, descr
38220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser
397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererclass EditorWindow:
407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    from Percolator import Percolator
417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    from ColorDelegator import ColorDelegator
427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    from UndoDelegator import UndoDelegator
437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    from IOBinding import IOBinding
447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    import Bindings
457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    from Tkinter import Toplevel
467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    from MultiStatusBar import MultiStatusBar
477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    vars = {}
49114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser    help_url = None
507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def __init__(self, flist=None, filename=None, key=None, root=None):
52114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser        if EditorWindow.help_url is None:
53114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser            if sys.platform.count('linux'):
54114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser                # look for html docs in a couple of standard places
55114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser                pyver = 'python-docs-' + '%s.%s.%s' % sys.version_info[:3]
56114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser                if os.path.isdir('/var/www/html/python/'):  # "python2" rpm
57114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser                    dochome = '/var/www/html/python/index.html'
58114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser                else:
59114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser                    basepath = '/usr/share/doc/'  # standard location
60114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser                    dochome = os.path.join(basepath, pyver,
61114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser                                           'Doc', 'index.html')
62114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser            else:
63114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser                dochome =  os.path.join(sys.prefix, 'Doc', 'index.html')
64114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser            dochome = os.path.normpath(dochome)
65114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser            if os.path.isfile(dochome):
66114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser                EditorWindow.help_url = dochome
67114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser            else:
68114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser                EditorWindow.help_url = "http://www.python.org/doc/current"
69dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava        currentTheme=idleConf.CurrentTheme()
707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.flist = flist
717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        root = root or flist.root
727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.root = root
737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.menubar = Menu(root)
747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.top = top = self.Toplevel(root, menu=self.menubar)
750c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava        if flist:
760c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava            self.vars = flist.vars
770c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava            #self.top.instanceDict makes flist.inversedict avalable to
780c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava            #configDialog.py so it can access all EditorWindow instaces
790c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava            self.top.instanceDict=flist.inversedict
801d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        self.recentFilesPath=os.path.join(idleConf.GetUserCfgDir(),
811d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                'recent-files.lst')
827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.vbar = vbar = Scrollbar(top, name='vbar')
837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text_frame = text_frame = Frame(top)
841061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser        self.width = idleConf.GetOption('main','EditorWindow','width')
85a1dee069831c5551dc28d90d495ab5de967c17d5Kurt B. Kaiser        self.text = text = Text(text_frame, name='text', padx=5, wrap='none',
86dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                foreground=idleConf.GetHighlight(currentTheme,
87dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                        'normal',fgBg='fg'),
88dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                background=idleConf.GetHighlight(currentTheme,
89dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                        'normal',fgBg='bg'),
90dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                highlightcolor=idleConf.GetHighlight(currentTheme,
91dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                        'hilite',fgBg='fg'),
92dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                highlightbackground=idleConf.GetHighlight(currentTheme,
93dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                        'hilite',fgBg='bg'),
94dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                insertbackground=idleConf.GetHighlight(currentTheme,
95dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                        'cursor',fgBg='fg'),
961061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser                width=self.width,
97dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                height=idleConf.GetOption('main','EditorWindow','height') )
987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.createmenubar()
1007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.apply_bindings()
1017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
1027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.top.protocol("WM_DELETE_WINDOW", self.close)
1037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.top.bind("<<close-window>>", self.close_event)
10484f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser        text.bind("<<cut>>", self.cut)
10584f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser        text.bind("<<copy>>", self.copy)
10684f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser        text.bind("<<paste>>", self.paste)
1077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<center-insert>>", self.center_insert_event)
1087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<help>>", self.help_dialog)
109abdfc4147d1f1334bb4dbaf5d9dd66af1db175adSteven M. Gava        text.bind("<<view-readme>>", self.view_readme)
1107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<python-docs>>", self.python_docs)
1117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<about-idle>>", self.about_dialog)
1123b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gava        text.bind("<<open-config-dialog>>", self.config_dialog)
1137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<open-module>>", self.open_module)
1147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<do-nothing>>", lambda event: "break")
1157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<select-all>>", self.select_all)
1167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<remove-selection>>", self.remove_selection)
117c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.bind("<<find>>", self.find_event)
118c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.bind("<<find-again>>", self.find_again_event)
119c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.bind("<<find-in-files>>", self.find_in_files_event)
120c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.bind("<<find-selection>>", self.find_selection_event)
121c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.bind("<<replace>>", self.replace_event)
122c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.bind("<<goto-line>>", self.goto_line_event)
1237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<3>", self.right_menu_event)
124cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.bind("<<smart-backspace>>",self.smart_backspace_event)
125cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.bind("<<newline-and-indent>>",self.newline_and_indent_event)
126cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.bind("<<smart-indent>>",self.smart_indent_event)
127cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.bind("<<indent-region>>",self.indent_region_event)
128cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.bind("<<dedent-region>>",self.dedent_region_event)
129cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.bind("<<comment-region>>",self.comment_region_event)
130cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.bind("<<uncomment-region>>",self.uncomment_region_event)
131cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.bind("<<tabify-region>>",self.tabify_region_event)
132cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.bind("<<untabify-region>>",self.untabify_region_event)
133cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.bind("<<toggle-tabs>>",self.toggle_tabs_event)
134cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.bind("<<change-indentwidth>>",self.change_indentwidth_event)
1355ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser        text.bind("<Left>", self.move_at_edge_if_selection(0))
1365ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser        text.bind("<Right>", self.move_at_edge_if_selection(1))
1376655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser
1387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if flist:
1397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            flist.inversedict[self] = key
1407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if key:
1417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                flist.dict[key] = self
142d2f4861a0b52a2af5ea3395267a5c56541352f8fKurt B. Kaiser            text.bind("<<open-new-window>>", self.new_callback)
1437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            text.bind("<<close-all-windows>>", self.flist.close_all_callback)
1447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            text.bind("<<open-class-browser>>", self.open_class_browser)
1457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            text.bind("<<open-path-browser>>", self.open_path_browser)
1467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
147898a365c276951ab2471afe2e24bbc910666d361Steven M. Gava        self.set_status_bar()
1487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        vbar['command'] = text.yview
1497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        vbar.pack(side=RIGHT, fill=Y)
1507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text['yscrollcommand'] = vbar.set
151b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava        fontWeight='normal'
152b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava        if idleConf.GetOption('main','EditorWindow','font-bold',type='bool'):
153b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava            fontWeight='bold'
154dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava        text.config(font=(idleConf.GetOption('main','EditorWindow','font'),
155b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava                idleConf.GetOption('main','EditorWindow','font-size'),
156b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava                fontWeight))
1577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text_frame.pack(side=LEFT, fill=BOTH, expand=1)
1587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.pack(side=TOP, fill=BOTH, expand=1)
1597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.focus_set()
1607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
1617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per = per = self.Percolator(text)
1627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.ispythonsource(filename):
163dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser            self.color = color = self.ColorDelegator()
164dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser            per.insertfilter(color)
1657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        else:
1667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.color = None
167dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser
168dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser        self.undo = undo = self.UndoDelegator()
169dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser        per.insertfilter(undo)
170dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser        text.undo_block_start = undo.undo_block_start
171dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser        text.undo_block_stop = undo.undo_block_stop
172dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser        undo.set_saved_change_hook(self.saved_change_hook)
173dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser
174dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser        # IOBinding implements file I/O and printing functionality
1757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.io = io = self.IOBinding(self)
176dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser        io.set_filename_change_hook(self.filename_change_hook)
177dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser
1781d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        #create the Recent Files submenu
1791d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        self.menuRecentFiles=Menu(self.menubar)
1801d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        self.menudict['file'].insert_cascade(3,label='Recent Files',
1811d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                underline=0,menu=self.menuRecentFiles)
1821d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        self.UpdateRecentFilesList()
1837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
1847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if filename:
185d2f4861a0b52a2af5ea3395267a5c56541352f8fKurt B. Kaiser            if os.path.exists(filename) and not os.path.isdir(filename):
1867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                io.loadfile(filename)
1877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            else:
1887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                io.set_filename(filename)
1897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.saved_change_hook()
1907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
1917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.load_extensions()
1927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
1937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        menu = self.menudict.get('windows')
1947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if menu:
1957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            end = menu.index("end")
1967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if end is None:
1977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                end = -1
1987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if end >= 0:
1997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                menu.add_separator()
2007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                end = end + 1
2017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.wmenu_end = end
2027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            WindowList.register_callback(self.postwindowsmenu)
2037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # Some abstractions so IDLE extensions are cross-IDE
2057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.askyesno = tkMessageBox.askyesno
2067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.askinteger = tkSimpleDialog.askinteger
2077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.showerror = tkMessageBox.showerror
2087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.extensions.has_key('AutoIndent'):
2107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.extensions['AutoIndent'].set_indentation_params(
2117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                self.ispythonsource(filename))
2126655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser
213d2f4861a0b52a2af5ea3395267a5c56541352f8fKurt B. Kaiser    def new_callback(self, event):
214d2f4861a0b52a2af5ea3395267a5c56541352f8fKurt B. Kaiser        dirname, basename = self.io.defaultfilename()
215d2f4861a0b52a2af5ea3395267a5c56541352f8fKurt B. Kaiser        self.flist.new(dirname)
216d2f4861a0b52a2af5ea3395267a5c56541352f8fKurt B. Kaiser        return "break"
217d2f4861a0b52a2af5ea3395267a5c56541352f8fKurt B. Kaiser
2187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def set_status_bar(self):
219898a365c276951ab2471afe2e24bbc910666d361Steven M. Gava        self.status_bar = self.MultiStatusBar(self.top)
2207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.status_bar.set_label('column', 'Col: ?', side=RIGHT)
2217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.status_bar.set_label('line', 'Ln: ?', side=RIGHT)
2227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.status_bar.pack(side=BOTTOM, fill=X)
2237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.bind('<KeyRelease>', self.set_line_and_column)
2247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.bind('<ButtonRelease>', self.set_line_and_column)
2257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.after_idle(self.set_line_and_column)
2267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def set_line_and_column(self, event=None):
228220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser        line, column = self.text.index(INSERT).split('.')
2297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.status_bar.set_label('column', 'Col: %s' % column)
2307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.status_bar.set_label('line', 'Ln: %s' % line)
2317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def wakeup(self):
2337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.top.wm_state() == "iconic":
2347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.top.wm_deiconify()
2357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        else:
2367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.top.tkraise()
2377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.focus_set()
2387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    menu_specs = [
2407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ("file", "_File"),
2417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ("edit", "_Edit"),
2427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ("format", "F_ormat"),
2437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ("run", "_Run"),
2441061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser        ("options", "_Options"),
2457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ("windows", "_Windows"),
2467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ("help", "_Help"),
2477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    ]
2487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def createmenubar(self):
2507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        mbar = self.menubar
2517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.menudict = menudict = {}
2527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        for name, label in self.menu_specs:
2537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            underline, label = prepstr(label)
2547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            menudict[name] = menu = Menu(mbar, name=name)
2557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            mbar.add_cascade(label=label, menu=menu, underline=underline)
2567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.fill_menus()
2578e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        self.base_helpmenu_length = self.menudict['help'].index(END)
2588e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        self.reset_help_menu_entries()
2597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def postwindowsmenu(self):
2617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # Only called when Windows menu exists
2627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # XXX Actually, this Just-In-Time updating interferes badly
2637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # XXX with the tear-off feature.  It would be better to update
2647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # XXX all Windows menus whenever the list of windows changes.
2657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        menu = self.menudict['windows']
2667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        end = menu.index("end")
2677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if end is None:
2687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            end = -1
2697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if end > self.wmenu_end:
2707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            menu.delete(self.wmenu_end+1, end)
2717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        WindowList.add_windows_to_menu(menu)
2727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    rmenu = None
2747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def right_menu_event(self, event):
2767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.tag_remove("sel", "1.0", "end")
2777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
2787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not self.rmenu:
2797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.make_rmenu()
2807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        rmenu = self.rmenu
2817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.event = event
2827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        iswin = sys.platform[:3] == 'win'
2837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if iswin:
2847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.text.config(cursor="arrow")
2857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        rmenu.tk_popup(event.x_root, event.y_root)
2867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if iswin:
2877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.text.config(cursor="ibeam")
2887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    rmenu_specs = [
2907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # ("Label", "<<virtual-event>>"), ...
2917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ("Close", "<<close-window>>"), # Example
2927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    ]
2937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def make_rmenu(self):
2957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        rmenu = Menu(self.text, tearoff=0)
2967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        for label, eventname in self.rmenu_specs:
2977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            def command(text=self.text, eventname=eventname):
2987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                text.event_generate(eventname)
2997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            rmenu.add_command(label=label, command=command)
3007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.rmenu = rmenu
3017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
3027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def about_dialog(self, event=None):
3037d9ed726fb6ec15dbfb8e922d35aa8816cbd0b0cSteven M. Gava        aboutDialog.AboutDialog(self.top,'About IDLEfork')
3046655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser
3053b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gava    def config_dialog(self, event=None):
3063b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gava        configDialog.ConfigDialog(self.top,'Settings')
3076655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser
308abdfc4147d1f1334bb4dbaf5d9dd66af1db175adSteven M. Gava    def view_readme(self, event=None):
309abdfc4147d1f1334bb4dbaf5d9dd66af1db175adSteven M. Gava        fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'README.txt')
3106655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser        textView.TextViewer(self.top,'IDLEfork - README',fn)
311abdfc4147d1f1334bb4dbaf5d9dd66af1db175adSteven M. Gava
3127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def help_dialog(self, event=None):
313b9d07b5a8b8b70268ffa520895e7843ab594a486Steven M. Gava        fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'help.txt')
3146655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser        textView.TextViewer(self.top,'Help',fn)
3156655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser
316114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser    def python_docs(self, event=None):
317114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser        if sys.platform.count('win') or sys.platform.count('nt'):
318931625dc77cfd527b059e579615d517d8d994110Steven M. Gava            os.startfile(self.help_url)
319114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser            return "break"
320114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser        else:
321114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser            webbrowser.open(self.help_url)
322114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser            return "break"
3230c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava
3240c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava    def display_docs(self, url):
3258e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        if not (url.startswith('www') or url.startswith('http')):
3268e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser            url = os.path.normpath(url)
327114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser        if sys.platform.count('win') or sys.platform.count('nt'):
328114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser            os.startfile(url)
329114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser        else:
330114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser            webbrowser.open(url)
3317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
33284f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser    def cut(self,event):
33384f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser        self.text.event_generate("<<Cut>>")
33484f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser        return "break"
33584f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser
33684f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser    def copy(self,event):
33784f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser        self.text.event_generate("<<Copy>>")
33884f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser        return "break"
33984f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser
34084f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser    def paste(self,event):
34184f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser        self.text.event_generate("<<Paste>>")
34284f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser        return "break"
34384f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser
3447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def select_all(self, event=None):
3457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.tag_add("sel", "1.0", "end-1c")
3467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.mark_set("insert", "1.0")
3477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.see("insert")
3487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return "break"
3497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
3507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def remove_selection(self, event=None):
3517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.tag_remove("sel", "1.0", "end")
3527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.see("insert")
3537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
3545ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser    def move_at_edge_if_selection(self, edge_index):
3555ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser        """Cursor move begins at start or end of selection
3565ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser
3575ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser        When a left/right cursor key is pressed create and return to Tkinter a
3585ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser        function which causes a cursor move from the associated edge of the
3595ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser        selection.
3605ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser
3615ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser        """
3625ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser        self_text_index = self.text.index
3635ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser        self_text_mark_set = self.text.mark_set
3645ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser        edges_table = ("sel.first+1c", "sel.last-1c")
3655ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser        def move_at_edge(event):
3665ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser            if (event.state & 5) == 0: # no shift(==1) or control(==4) pressed
3675ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser                try:
3685ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser                    self_text_index("sel.first")
3695ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser                    self_text_mark_set("insert", edges_table[edge_index])
3705ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser                except TclError:
3715ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser                    pass
3725ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser        return move_at_edge
3735ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser
374c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava    def find_event(self, event):
375c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        SearchDialog.find(self.text)
376c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        return "break"
377c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava
378c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava    def find_again_event(self, event):
379c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        SearchDialog.find_again(self.text)
380c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        return "break"
381c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava
382c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava    def find_selection_event(self, event):
383c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        SearchDialog.find_selection(self.text)
384c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        return "break"
385c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava
386c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava    def find_in_files_event(self, event):
387c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        GrepDialog.grep(self.text, self.io, self.flist)
388c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        return "break"
389c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava
390c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava    def replace_event(self, event):
391c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        ReplaceDialog.replace(self.text)
392c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        return "break"
393c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava
394c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava    def goto_line_event(self, event):
395c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text = self.text
396c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        lineno = tkSimpleDialog.askinteger("Goto",
397c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava                "Go to line number:",parent=text)
398c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        if lineno is None:
399c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava            return "break"
400c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        if lineno <= 0:
401c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava            text.bell()
402c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava            return "break"
403c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.mark_set("insert", "%d.0" % lineno)
404c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.see("insert")
405c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava
4067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def open_module(self, event=None):
4077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # XXX Shouldn't this be in IOBinding or in FileList?
4087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        try:
4097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            name = self.text.get("sel.first", "sel.last")
4107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        except TclError:
4117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            name = ""
4127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        else:
413220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser            name = name.strip()
414852f35bbeb23d898fb0d16489effb1197ee3fe02Guido van Rossum        name = tkSimpleDialog.askstring("Module",
415852f35bbeb23d898fb0d16489effb1197ee3fe02Guido van Rossum                 "Enter the name of a Python module\n"
416852f35bbeb23d898fb0d16489effb1197ee3fe02Guido van Rossum                 "to search on sys.path and open:",
417852f35bbeb23d898fb0d16489effb1197ee3fe02Guido van Rossum                 parent=self.text, initialvalue=name)
418852f35bbeb23d898fb0d16489effb1197ee3fe02Guido van Rossum        if name:
419852f35bbeb23d898fb0d16489effb1197ee3fe02Guido van Rossum            name = name.strip()
4207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not name:
421852f35bbeb23d898fb0d16489effb1197ee3fe02Guido van Rossum            return
4227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # XXX Ought to insert current file's directory in front of path
4237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        try:
424220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser            (f, file, (suffix, mode, type)) = _find_module(name)
4257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        except (NameError, ImportError), msg:
4267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            tkMessageBox.showerror("Import error", str(msg), parent=self.text)
4277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return
4287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if type != imp.PY_SOURCE:
4297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            tkMessageBox.showerror("Unsupported type",
4307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                "%s is not a source module" % name, parent=self.text)
4317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return
4327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if f:
4337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            f.close()
4347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.flist:
4357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.flist.open(file)
4367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        else:
4377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.io.loadfile(file)
4387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def open_class_browser(self, event=None):
4407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        filename = self.io.filename
4417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not filename:
4427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            tkMessageBox.showerror(
4437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                "No filename",
4447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                "This buffer has no associated filename",
4457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                master=self.text)
4467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.text.focus_set()
4477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return None
4487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        head, tail = os.path.split(filename)
4497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        base, ext = os.path.splitext(tail)
4507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        import ClassBrowser
4517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ClassBrowser.ClassBrowser(self.flist, base, [head])
4527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def open_path_browser(self, event=None):
4547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        import PathBrowser
4557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        PathBrowser.PathBrowser(self.flist)
4567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def gotoline(self, lineno):
4587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if lineno is not None and lineno > 0:
4597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.text.mark_set("insert", "%d.0" % lineno)
4607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.text.tag_remove("sel", "1.0", "end")
4617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.text.tag_add("sel", "insert", "insert +1l")
4627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.center()
4637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def ispythonsource(self, filename):
4657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not filename:
466220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser            return True
4677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        base, ext = os.path.splitext(os.path.basename(filename))
4687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if os.path.normcase(ext) in (".py", ".pyw"):
469220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser            return True
4707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        try:
4717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            f = open(filename)
4727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            line = f.readline()
4737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            f.close()
4747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        except IOError:
475220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser            return False
47683a3560527f9e62bce6adbc12b8ff6b57be8b1acKurt B. Kaiser        return line.startswith('#!') and line.find('python') >= 0
4777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def close_hook(self):
4797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.flist:
4807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.flist.close_edit(self)
4817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def set_close_hook(self, close_hook):
4837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.close_hook = close_hook
4847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def filename_change_hook(self):
4867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.flist:
4877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.flist.filename_changed_edit(self)
4887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.saved_change_hook()
489260cb9034c861fa159f26fba8679ac265af47109Kurt B. Kaiser        self.top.update_windowlist_registry(self)
4907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.ispythonsource(self.io.filename):
4917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.addcolorizer()
4927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        else:
4937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.rmcolorizer()
4947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def addcolorizer(self):
4967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.color:
4977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return
4987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per.removefilter(self.undo)
4997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.color = self.ColorDelegator()
5007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per.insertfilter(self.color)
5017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per.insertfilter(self.undo)
5027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
5037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def rmcolorizer(self):
5047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not self.color:
5057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return
5067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per.removefilter(self.undo)
5077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per.removefilter(self.color)
5087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.color = None
5097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per.insertfilter(self.undo)
5106655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser
511b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava    def ResetColorizer(self):
51283118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        "Update the colour theme if it is changed"
51383118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        # Called from configDialog.py
514b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava        if self.color:
515b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava            self.color = self.ColorDelegator()
516b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava            self.per.insertfilter(self.color)
5177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
518b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava    def ResetFont(self):
5196655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser        "Update the text widgets' font if it is changed"
52083118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        # Called from configDialog.py
521b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava        fontWeight='normal'
522b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava        if idleConf.GetOption('main','EditorWindow','font-bold',type='bool'):
523b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava            fontWeight='bold'
524b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava        self.text.config(font=(idleConf.GetOption('main','EditorWindow','font'),
525b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava                idleConf.GetOption('main','EditorWindow','font-size'),
526b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava                fontWeight))
527b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava
528dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava    def ResetKeybindings(self):
52983118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        "Update the keybindings if they are changed"
53083118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        # Called from configDialog.py
531dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        self.Bindings.default_keydefs=idleConf.GetCurrentKeySet()
532dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        keydefs = self.Bindings.default_keydefs
533dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        for event, keylist in keydefs.items():
534dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava            self.text.event_delete(event)
535dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        self.apply_bindings()
536dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        #update menu accelerators
537dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        menuEventDict={}
538dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        for menu in self.Bindings.menudefs:
539dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava            menuEventDict[menu[0]]={}
540dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava            for item in menu[1]:
541dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                if item:
542dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                    menuEventDict[menu[0]][prepstr(item[0])[1]]=item[1]
543dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        for menubarItem in self.menudict.keys():
544dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava            menu=self.menudict[menubarItem]
545dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava            end=menu.index(END)+1
546dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava            for index in range(0,end):
547dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                if menu.type(index)=='command':
548dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                    accel=menu.entrycget(index,'accelerator')
549dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                    if accel:
550dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                        itemName=menu.entrycget(index,'label')
551dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                        event=''
552dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                        if menuEventDict.has_key(menubarItem):
553dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                            if menuEventDict[menubarItem].has_key(itemName):
554dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                                event=menuEventDict[menubarItem][itemName]
555dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                        if event:
556dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                            #print 'accel was:',accel
557dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                            accel=get_accelerator(keydefs, event)
558dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                            menu.entryconfig(index,accelerator=accel)
559dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                            #print 'accel now:',accel,'\n'
560dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava
5618e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser    def reset_help_menu_entries(self):
5628e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        "Update the additional help entries on the Help menu"
5638e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        help_list = idleConf.GetAllExtraHelpSourcesList()
5648e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        helpmenu = self.menudict['help']
5658e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        # first delete the extra help entries, if any
5668e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        helpmenu_length = helpmenu.index(END)
5678e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        if helpmenu_length > self.base_helpmenu_length:
5688e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser            helpmenu.delete((self.base_helpmenu_length + 1), helpmenu_length)
5698e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        # then rebuild them
5708e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        if help_list:
5718e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser            helpmenu.add_separator()
5728e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser            for entry in help_list:
5738e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser                cmd = self.__extra_help_callback(entry[1])
5748e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser                helpmenu.add_command(label=entry[0], command=cmd)
5758e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        # and update the menu dictionary
5768e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        self.menudict['help'] = helpmenu
5778e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser
5788e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser    def __extra_help_callback(self, helpfile):
5798e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        "Create a callback with the helpfile value frozen at definition time"
5808e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        def display_extra_help(helpfile=helpfile):
5818e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser            self.display_docs(helpfile)
5828e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser        return display_extra_help
5836655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser
5841d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava    def UpdateRecentFilesList(self,newFile=None):
58583118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        "Load or update the recent files list, and menu if required"
5861d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        rfList=[]
5871d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        if os.path.exists(self.recentFilesPath):
5881d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            RFfile=open(self.recentFilesPath,'r')
5891d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            try:
5901d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                rfList=RFfile.readlines()
5911d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            finally:
5921d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                RFfile.close()
5936655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser        if newFile:
5941d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            newFile=os.path.abspath(newFile)+'\n'
5951d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            if newFile in rfList:
5961d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                rfList.remove(newFile)
5971d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            rfList.insert(0,newFile)
5981d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        rfList=self.__CleanRecentFiles(rfList)
59983118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        #print self.flist.inversedict
60083118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        #print self.top.instanceDict
60183118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        #print self
602c9a5b5c72e6017c154b26d2796141091e7614d44Kurt B. Kaiser        ullist = "1234567890ABCDEFGHIJ"
6031d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        if rfList:
6041d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            for instance in self.top.instanceDict.keys():
605c9a5b5c72e6017c154b26d2796141091e7614d44Kurt B. Kaiser                menu = instance.menuRecentFiles
606c9a5b5c72e6017c154b26d2796141091e7614d44Kurt B. Kaiser                menu.delete(1,END)
6076655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser                i = 0 ; ul = 0; ullen = len(ullist)
6081d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                for file in rfList:
6091d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                    fileName=file[0:-1]
610c9a5b5c72e6017c154b26d2796141091e7614d44Kurt B. Kaiser                    callback = instance.__RecentFileCallback(fileName)
611c9a5b5c72e6017c154b26d2796141091e7614d44Kurt B. Kaiser                    if i > ullen: # don't underline menuitems
612c9a5b5c72e6017c154b26d2796141091e7614d44Kurt B. Kaiser                        ul=None
613c9a5b5c72e6017c154b26d2796141091e7614d44Kurt B. Kaiser                    menu.add_command(label=ullist[i] + " " + fileName,
614c9a5b5c72e6017c154b26d2796141091e7614d44Kurt B. Kaiser                                     command=callback,
615c9a5b5c72e6017c154b26d2796141091e7614d44Kurt B. Kaiser                                     underline=ul)
616c9a5b5c72e6017c154b26d2796141091e7614d44Kurt B. Kaiser                    i += 1
6176655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser
6181d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava    def __CleanRecentFiles(self,rfList):
6191d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        origRfList=rfList[:]
6201d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        count=0
6211d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        nonFiles=[]
6221d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        for path in rfList:
6236655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser            if not os.path.exists(path[0:-1]):
6241d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                nonFiles.append(count)
6251d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            count=count+1
6261d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        if nonFiles:
6271d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            nonFiles.reverse()
6281d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            for index in nonFiles:
6291d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                del(rfList[index])
6301d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        if len(rfList)>19:
6311d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            rfList=rfList[0:19]
6321d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        #if rfList != origRfList:
6331d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        RFfile=open(self.recentFilesPath,'w')
6341d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        try:
6351d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            RFfile.writelines(rfList)
6361d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        finally:
6371d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            RFfile.close()
6381d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        return rfList
6396655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser
6401d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava    def __RecentFileCallback(self,fileName):
6411d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        def OpenRecentFile(fileName=fileName):
6421d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            self.io.open(editFile=fileName)
6431d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        return OpenRecentFile
6446655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser
6457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def saved_change_hook(self):
6467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        short = self.short_title()
6477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        long = self.long_title()
6487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if short and long:
6497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            title = short + " - " + long
6507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        elif short:
6517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            title = short
6527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        elif long:
6537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            title = long
6547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        else:
6557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            title = "Untitled"
6567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        icon = short or long or title
6577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not self.get_saved():
6587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            title = "*%s*" % title
6597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            icon = "*%s" % icon
6607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.top.wm_title(title)
6617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.top.wm_iconname(icon)
6627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def get_saved(self):
6647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return self.undo.get_saved()
6657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def set_saved(self, flag):
6677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.undo.set_saved(flag)
6687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def reset_undo(self):
6707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.undo.reset_undo()
6717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def short_title(self):
6737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        filename = self.io.filename
6747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if filename:
6757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            filename = os.path.basename(filename)
6767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return filename
6777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def long_title(self):
6797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return self.io.filename or ""
6807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def center_insert_event(self, event):
6827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.center()
6837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def center(self, mark="insert"):
6857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text = self.text
6867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        top, bot = self.getwindowlines()
6877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        lineno = self.getlineno(mark)
6887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        height = bot - top
689220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser        newtop = max(1, lineno - height//2)
6907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.yview(float(newtop))
6917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def getwindowlines(self):
6937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text = self.text
6947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        top = self.getlineno("@0,0")
6957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        bot = self.getlineno("@0,65535")
6967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if top == bot and text.winfo_height() == 1:
6977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            # Geometry manager hasn't run yet
6987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            height = int(text['height'])
6997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            bot = top + height - 1
7007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return top, bot
7017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def getlineno(self, mark="insert"):
7037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text = self.text
7047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return int(float(text.index(mark)))
7057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7061061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser    def get_geometry(self):
7071061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser        "Return (width, height, x, y)"
7081061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser        geom = self.top.wm_geometry()
7091061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser        m = re.match(r"(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geom)
7101061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser        tuple = (map(int, m.groups()))
7111061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser        return tuple
7121061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser
7137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def close_event(self, event):
7147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.close()
7157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def maybesave(self):
7177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.io:
71867716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava            if not self.get_saved():
7196655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser                if self.top.state()!='normal':
72067716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava                    self.top.deiconify()
72167716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava                self.top.lower()
72267716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava                self.top.lift()
7237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return self.io.maybesave()
7247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def close(self):
7267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        reply = self.maybesave()
7277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if reply != "cancel":
7287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self._close()
7297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return reply
7307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def _close(self):
73283118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        #print self.io.filename
7331d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        if self.io.filename:
7341d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            self.UpdateRecentFilesList(newFile=self.io.filename)
7357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        WindowList.unregister_callback(self.postwindowsmenu)
7367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.close_hook:
7377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.close_hook()
7387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.flist = None
7397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        colorizing = 0
7407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.unload_extensions()
7417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.io.close(); self.io = None
7427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.undo = None # XXX
7437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.color:
7447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            colorizing = self.color.colorizing
7457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            doh = colorizing and self.top
7467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.color.close(doh) # Cancel colorization
7477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text = None
7487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.vars = None
7497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per.close(); self.per = None
7507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not colorizing:
7517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.top.destroy()
7527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def load_extensions(self):
7547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.extensions = {}
7557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.load_standard_extensions()
7567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def unload_extensions(self):
7587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        for ins in self.extensions.values():
7597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if hasattr(ins, "close"):
7607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                ins.close()
7617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.extensions = {}
7627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def load_standard_extensions(self):
7647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        for name in self.get_standard_extension_names():
7657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            try:
7667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                self.load_extension(name)
7677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            except:
7687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                print "Failed to load extension", `name`
7697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                import traceback
7707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                traceback.print_exc()
7717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def get_standard_extension_names(self):
773dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava        return idleConf.GetExtensions()
7747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def load_extension(self, name):
7767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        mod = __import__(name, globals(), locals(), [])
7777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        cls = getattr(mod, name)
7787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ins = cls(self)
7797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.extensions[name] = ins
78072c3bf076f785aaf54d63a7e8cae29bc8282920eSteven M. Gava        keydefs=idleConf.GetExtensionBindings(name)
7817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if keydefs:
7827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.apply_bindings(keydefs)
7837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            for vevent in keydefs.keys():
784220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser                methodname = vevent.replace("-", "_")
7857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                while methodname[:1] == '<':
7867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    methodname = methodname[1:]
7877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                while methodname[-1:] == '>':
7887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    methodname = methodname[:-1]
7897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                methodname = methodname + "_event"
7907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                if hasattr(ins, methodname):
7917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    self.text.bind(vevent, getattr(ins, methodname))
7927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if hasattr(ins, "menudefs"):
7937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.fill_menus(ins.menudefs, keydefs)
7947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return ins
7957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def apply_bindings(self, keydefs=None):
7977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if keydefs is None:
7987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            keydefs = self.Bindings.default_keydefs
7997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text = self.text
8007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.keydefs = keydefs
8017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        for event, keylist in keydefs.items():
8027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if keylist:
8037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                apply(text.event_add, (event,) + tuple(keylist))
8047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def fill_menus(self, defs=None, keydefs=None):
80683118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        """Add appropriate entries to the menus and submenus
80783118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser
80883118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        Menus that are absent or None in self.menudict are ignored.
80983118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        """
8107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if defs is None:
8117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            defs = self.Bindings.menudefs
8127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if keydefs is None:
8137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            keydefs = self.Bindings.default_keydefs
8147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        menudict = self.menudict
8157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text = self.text
8167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        for mname, itemlist in defs:
8177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            menu = menudict.get(mname)
8187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if not menu:
8197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                continue
8207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            for item in itemlist:
8217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                if not item:
8227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    menu.add_separator()
8237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                else:
8247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    label, event = item
8257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    checkbutton = (label[:1] == '!')
8267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    if checkbutton:
8277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                        label = label[1:]
8287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    underline, label = prepstr(label)
8297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    accelerator = get_accelerator(keydefs, event)
8307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    def command(text=text, event=event):
8317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                        text.event_generate(event)
8327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    if checkbutton:
8337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                        var = self.getrawvar(event, BooleanVar)
8347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                        menu.add_checkbutton(label=label, underline=underline,
8357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                            command=command, accelerator=accelerator,
8367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                            variable=var)
8377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    else:
8387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                        menu.add_command(label=label, underline=underline,
83984f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser                                         command=command,
84084f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser                                         accelerator=accelerator)
8417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def getvar(self, name):
8437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        var = self.getrawvar(name)
8447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if var:
8457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return var.get()
8467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def setvar(self, name, value, vartype=None):
8487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        var = self.getrawvar(name, vartype)
8497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if var:
8507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            var.set(value)
8517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def getrawvar(self, name, vartype=None):
8537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        var = self.vars.get(name)
8547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not var and vartype:
8557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.vars[name] = var = vartype(self.text)
8567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return var
8577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # Tk implementations of "virtual text methods" -- each platform
8597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # reusing IDLE's support code needs to define these for its GUI's
8607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # flavor of widget.
8617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # Is character at text_index in a Python string?  Return 0 for
8637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # "guaranteed no", true for anything else.  This info is expensive
8647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # to compute ab initio, but is probably already known by the
8657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # platform's colorizer.
8667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def is_char_in_string(self, text_index):
8687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.color:
8697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            # Return true iff colorizer hasn't (re)gotten this far
8707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            # yet, or the character is tagged as being in a string
8717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return self.text.tag_prevrange("TODO", text_index) or \
8727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                   "STRING" in self.text.tag_names(text_index)
8737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        else:
8747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            # The colorizer is missing: assume the worst
8757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return 1
8767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # If a selection is defined in the text widget, return (start,
8787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # end) as Tkinter text indices, otherwise return (None, None)
8797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def get_selection_indices(self):
8807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        try:
8817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            first = self.text.index("sel.first")
8827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            last = self.text.index("sel.last")
8837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return first, last
8847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        except TclError:
8857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return None, None
8867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # Return the text widget's current view of what a tab stop means
8887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # (equivalent width in spaces).
8897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def get_tabwidth(self):
8917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        current = self.text['tabs'] or TK_TABWIDTH_DEFAULT
8927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return int(current)
8937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # Set the text widget's current view of what a tab stop means.
8957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def set_tabwidth(self, newtabwidth):
8977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text = self.text
8987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.get_tabwidth() != newtabwidth:
8997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            pixels = text.tk.call("font", "measure", text["font"],
9007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                                  "-displayof", text.master,
901afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser                                  "n" * newtabwidth)
9027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            text.configure(tabs=pixels)
9037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
904cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser### begin autoindent code ###
905cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
906cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # usetabs true  -> literal tab characters are used by indent and
907cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    #                  dedent cmds, possibly mixed with spaces if
908cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    #                  indentwidth is not a multiple of tabwidth
909cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    #         false -> tab characters are converted to spaces by indent
910cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    #                  and dedent cmds, and ditto TAB keystrokes
911cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # indentwidth is the number of characters per logical indent level.
912cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # tabwidth is the display width of a literal tab character.
913cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # CAUTION:  telling Tk to use anything other than its default
914cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # tab setting causes it to use an entirely different tabbing algorithm,
915cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # treating tab stops as fixed distances from the left margin.
916cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # Nobody expects this, so for now tabwidth should never be changed.
917cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    usetabs = 0
918cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    indentwidth = 4
919cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    tabwidth = 8    # for IDLE use, must remain 8 until Tk is fixed
920cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
921cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # If context_use_ps1 is true, parsing searches back for a ps1 line;
922cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # else searches for a popular (if, def, ...) Python stmt.
923cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    context_use_ps1 = 0
924cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
925cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # When searching backwards for a reliable place to begin parsing,
926cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # first start num_context_lines[0] lines back, then
927cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # num_context_lines[1] lines back if that didn't work, and so on.
928cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # The last value should be huge (larger than the # of lines in a
929cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # conceivable file).
930cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # Making the initial values larger slows things down more often.
931cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    num_context_lines = 50, 500, 5000000
932cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
933cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def config(self, **options):
934cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        for key, value in options.items():
935cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if key == 'usetabs':
936cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                self.usetabs = value
937cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            elif key == 'indentwidth':
938cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                self.indentwidth = value
939cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            elif key == 'tabwidth':
940cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                self.tabwidth = value
941cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            elif key == 'context_use_ps1':
942cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                self.context_use_ps1 = value
943cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            else:
944cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                raise KeyError, "bad option name: %s" % `key`
945cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
946cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # If ispythonsource and guess are true, guess a good value for
947cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # indentwidth based on file content (if possible), and if
948cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # indentwidth != tabwidth set usetabs false.
949cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # In any case, adjust the Text widget's view of what a tab
950cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # character means.
951cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
952cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def set_indentation_params(self, ispythonsource, guess=1):
953cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if guess and ispythonsource:
954cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            i = self.guess_indent()
955cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if 2 <= i <= 8:
956cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                self.indentwidth = i
957cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if self.indentwidth != self.tabwidth:
958cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                self.usetabs = 0
959cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
960cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        self.set_tabwidth(self.tabwidth)
961cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
962cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def smart_backspace_event(self, event):
963cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text = self.text
964cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        first, last = self.get_selection_indices()
965cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if first and last:
966cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            text.delete(first, last)
967cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            text.mark_set("insert", first)
968cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            return "break"
969cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        # Delete whitespace left, until hitting a real char or closest
970cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        # preceding virtual tab stop.
971cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        chars = text.get("insert linestart", "insert")
972cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if chars == '':
973cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if text.compare("insert", ">", "1.0"):
974cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                # easy: delete preceding newline
975cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                text.delete("insert-1c")
976cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            else:
977cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                text.bell()     # at start of buffer
978cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            return "break"
979cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if  chars[-1] not in " \t":
980cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            # easy: delete preceding real char
981cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            text.delete("insert-1c")
982cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            return "break"
983cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        # Ick.  It may require *inserting* spaces if we back up over a
984cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        # tab character!  This is written to be clear, not fast.
9851b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser        tabwidth = self.tabwidth
9861b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser        have = len(chars.expandtabs(tabwidth))
987cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        assert have > 0
988cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        want = ((have - 1) // self.indentwidth) * self.indentwidth
9894ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser        # Debug prompt is multilined....
9904ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser        last_line_of_prompt = sys.ps1.split('\n')[-1]
991cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        ncharsdeleted = 0
992cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        while 1:
9934ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser            if chars == last_line_of_prompt:
9941bdca5e051a5424aaaaf7968c710d31132a6c335Kurt B. Kaiser                break
995cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            chars = chars[:-1]
996cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            ncharsdeleted = ncharsdeleted + 1
9971b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser            have = len(chars.expandtabs(tabwidth))
998cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if have <= want or chars[-1] not in " \t":
999cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                break
1000cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.undo_block_start()
1001cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.delete("insert-%dc" % ncharsdeleted, "insert")
1002cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if have < want:
1003cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            text.insert("insert", ' ' * (want - have))
1004cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.undo_block_stop()
1005cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        return "break"
1006cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1007cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def smart_indent_event(self, event):
1008cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        # if intraline selection:
1009cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        #     delete it
1010cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        # elif multiline selection:
1011cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        #     do indent-region & return
1012cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        # indent one level
1013cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text = self.text
1014cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        first, last = self.get_selection_indices()
1015cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.undo_block_start()
1016cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        try:
1017cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if first and last:
1018cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                if index2line(first) != index2line(last):
1019cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    return self.indent_region_event(event)
1020cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                text.delete(first, last)
1021cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                text.mark_set("insert", first)
1022cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            prefix = text.get("insert linestart", "insert")
1023cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            raw, effective = classifyws(prefix, self.tabwidth)
1024cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if raw == len(prefix):
1025cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                # only whitespace to the left
1026cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                self.reindent_to(effective + self.indentwidth)
1027cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            else:
1028cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                if self.usetabs:
1029cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    pad = '\t'
1030cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                else:
10311b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser                    effective = len(prefix.expandtabs(self.tabwidth))
1032cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    n = self.indentwidth
1033cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    pad = ' ' * (n - effective % n)
1034cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                text.insert("insert", pad)
1035cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            text.see("insert")
1036cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            return "break"
1037cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        finally:
1038cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            text.undo_block_stop()
1039cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1040cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def newline_and_indent_event(self, event):
1041cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text = self.text
1042cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        first, last = self.get_selection_indices()
1043cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.undo_block_start()
1044cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        try:
1045cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if first and last:
1046cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                text.delete(first, last)
1047cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                text.mark_set("insert", first)
1048cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            line = text.get("insert linestart", "insert")
1049cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            i, n = 0, len(line)
1050cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            while i < n and line[i] in " \t":
1051cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                i = i+1
1052cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if i == n:
10534ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser                # the cursor is in or at leading indentation in a continuation
10544ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser                # line; just inject an empty line at the start
1055cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                text.insert("insert linestart", '\n')
1056cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                return "break"
1057cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            indent = line[:i]
10584ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser            # strip whitespace before insert point unless it's in the prompt
1059cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            i = 0
10604ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser            last_line_of_prompt = sys.ps1.split('\n')[-1]
10614ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser            while line and line[-1] in " \t" and line != last_line_of_prompt:
1062cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                line = line[:-1]
1063cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                i = i+1
1064cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if i:
1065cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                text.delete("insert - %d chars" % i, "insert")
1066cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            # strip whitespace after insert point
1067cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            while text.get("insert") in " \t":
1068cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                text.delete("insert")
1069cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            # start new line
1070cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            text.insert("insert", '\n')
1071cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1072cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            # adjust indentation for continuations and block
1073cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            # open/close first need to find the last stmt
1074cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            lno = index2line(text.index('insert'))
1075cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            y = PyParse.Parser(self.indentwidth, self.tabwidth)
1076cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            for context in self.num_context_lines:
1077cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                startat = max(lno - context, 1)
1078cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                startatindex = `startat` + ".0"
1079cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                rawtext = text.get(startatindex, "insert")
1080cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                y.set_str(rawtext)
1081cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                bod = y.find_good_parse_start(
1082cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                          self.context_use_ps1,
1083cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                          self._build_char_in_string_func(startatindex))
1084cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                if bod is not None or startat == 1:
1085cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    break
1086cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            y.set_lo(bod or 0)
1087cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            c = y.get_continuation_type()
1088cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if c != PyParse.C_NONE:
1089cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                # The current stmt hasn't ended yet.
1090cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                if c == PyParse.C_STRING:
1091cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    # inside a string; just mimic the current indent
1092cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    text.insert("insert", indent)
1093cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                elif c == PyParse.C_BRACKET:
1094cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    # line up with the first (if any) element of the
1095cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    # last open bracket structure; else indent one
1096cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    # level beyond the indent of the line with the
1097cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    # last open bracket
1098cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    self.reindent_to(y.compute_bracket_indent())
1099cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                elif c == PyParse.C_BACKSLASH:
1100cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    # if more than one line in this stmt already, just
1101cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    # mimic the current indent; else if initial line
1102cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    # has a start on an assignment stmt, indent to
1103cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    # beyond leftmost =; else to beyond first chunk of
1104cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    # non-whitespace on initial line
1105cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    if y.get_num_lines_in_stmt() > 1:
1106cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                        text.insert("insert", indent)
1107cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    else:
1108cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                        self.reindent_to(y.compute_backslash_indent())
1109cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                else:
1110cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                    assert 0, "bogus continuation type " + `c`
1111cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                return "break"
1112cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1113cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            # This line starts a brand new stmt; indent relative to
1114cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            # indentation of initial line of closest preceding
1115cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            # interesting stmt.
1116cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            indent = y.get_base_indent_string()
1117cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            text.insert("insert", indent)
1118cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if y.is_block_opener():
1119cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                self.smart_indent_event(event)
1120cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            elif indent and y.is_block_closer():
1121cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                self.smart_backspace_event(event)
1122cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            return "break"
1123cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        finally:
1124cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            text.see("insert")
1125cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            text.undo_block_stop()
1126cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1127cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # Our editwin provides a is_char_in_string function that works
1128cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # with a Tk text index, but PyParse only knows about offsets into
1129cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # a string. This builds a function for PyParse that accepts an
1130cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # offset.
1131cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1132cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def _build_char_in_string_func(self, startindex):
1133cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        def inner(offset, _startindex=startindex,
1134cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                  _icis=self.is_char_in_string):
1135cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            return _icis(_startindex + "+%dc" % offset)
1136cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        return inner
1137cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1138cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def indent_region_event(self, event):
1139cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        head, tail, chars, lines = self.get_region()
1140cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        for pos in range(len(lines)):
1141cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            line = lines[pos]
1142cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if line:
1143cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                raw, effective = classifyws(line, self.tabwidth)
1144cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                effective = effective + self.indentwidth
1145cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                lines[pos] = self._make_blanks(effective) + line[raw:]
1146cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        self.set_region(head, tail, chars, lines)
1147cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        return "break"
1148cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1149cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def dedent_region_event(self, event):
1150cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        head, tail, chars, lines = self.get_region()
1151cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        for pos in range(len(lines)):
1152cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            line = lines[pos]
1153cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if line:
1154cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                raw, effective = classifyws(line, self.tabwidth)
1155cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                effective = max(effective - self.indentwidth, 0)
1156cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                lines[pos] = self._make_blanks(effective) + line[raw:]
1157cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        self.set_region(head, tail, chars, lines)
1158cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        return "break"
1159cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1160cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def comment_region_event(self, event):
1161cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        head, tail, chars, lines = self.get_region()
1162cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        for pos in range(len(lines) - 1):
1163cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            line = lines[pos]
1164cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            lines[pos] = '##' + line
1165cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        self.set_region(head, tail, chars, lines)
1166cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1167cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def uncomment_region_event(self, event):
1168cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        head, tail, chars, lines = self.get_region()
1169cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        for pos in range(len(lines)):
1170cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            line = lines[pos]
1171cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if not line:
1172cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                continue
1173cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if line[:2] == '##':
1174cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                line = line[2:]
1175cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            elif line[:1] == '#':
1176cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                line = line[1:]
1177cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            lines[pos] = line
1178cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        self.set_region(head, tail, chars, lines)
1179cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1180cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def tabify_region_event(self, event):
1181cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        head, tail, chars, lines = self.get_region()
1182cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        tabwidth = self._asktabwidth()
1183cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        for pos in range(len(lines)):
1184cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            line = lines[pos]
1185cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            if line:
1186cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                raw, effective = classifyws(line, tabwidth)
1187cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                ntabs, nspaces = divmod(effective, tabwidth)
1188cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:]
1189cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        self.set_region(head, tail, chars, lines)
1190cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1191cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def untabify_region_event(self, event):
1192cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        head, tail, chars, lines = self.get_region()
1193cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        tabwidth = self._asktabwidth()
1194cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        for pos in range(len(lines)):
11951b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser            lines[pos] = lines[pos].expandtabs(tabwidth)
1196cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        self.set_region(head, tail, chars, lines)
1197cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1198cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def toggle_tabs_event(self, event):
1199cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if self.askyesno(
1200cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser              "Toggle tabs",
1201cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser              "Turn tabs " + ("on", "off")[self.usetabs] + "?",
1202cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser              parent=self.text):
1203cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            self.usetabs = not self.usetabs
1204cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        return "break"
1205cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1206cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # XXX this isn't bound to anything -- see class tabwidth comments
1207cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def change_tabwidth_event(self, event):
1208cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        new = self._asktabwidth()
1209cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if new != self.tabwidth:
1210cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            self.tabwidth = new
1211cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            self.set_indentation_params(0, guess=0)
1212cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        return "break"
1213cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1214cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def change_indentwidth_event(self, event):
1215cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        new = self.askinteger(
1216cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                  "Indent width",
1217cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                  "New indent width (2-16)",
1218cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                  parent=self.text,
1219cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                  initialvalue=self.indentwidth,
1220cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                  minvalue=2,
1221cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                  maxvalue=16)
1222cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if new and new != self.indentwidth:
1223cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            self.indentwidth = new
1224cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        return "break"
1225cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1226cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def get_region(self):
1227cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text = self.text
1228cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        first, last = self.get_selection_indices()
1229cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if first and last:
1230cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            head = text.index(first + " linestart")
1231cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            tail = text.index(last + "-1c lineend +1c")
1232cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        else:
1233cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            head = text.index("insert linestart")
1234cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            tail = text.index("insert lineend +1c")
1235cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        chars = text.get(head, tail)
12361b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser        lines = chars.split("\n")
1237cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        return head, tail, chars, lines
1238cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1239cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def set_region(self, head, tail, chars, lines):
1240cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text = self.text
12411b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser        newchars = "\n".join(lines)
1242cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if newchars == chars:
1243cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            text.bell()
1244cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            return
1245cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.tag_remove("sel", "1.0", "end")
1246cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.mark_set("insert", head)
1247cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.undo_block_start()
1248cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.delete(head, tail)
1249cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.insert(head, newchars)
1250cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.undo_block_stop()
1251cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.tag_add("sel", head, "insert")
1252cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1253cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # Make string that displays as n leading blanks.
1254cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1255cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def _make_blanks(self, n):
1256cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if self.usetabs:
1257cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            ntabs, nspaces = divmod(n, self.tabwidth)
1258cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            return '\t' * ntabs + ' ' * nspaces
1259cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        else:
1260cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            return ' ' * n
1261cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1262cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # Delete from beginning of line to insert point, then reinsert
1263cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # column logical (meaning use tabs if appropriate) spaces.
1264cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1265cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def reindent_to(self, column):
1266cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text = self.text
1267cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.undo_block_start()
1268cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if text.compare("insert linestart", "!=", "insert"):
1269cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            text.delete("insert linestart", "insert")
1270cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if column:
1271cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            text.insert("insert", self._make_blanks(column))
1272cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        text.undo_block_stop()
1273cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1274cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def _asktabwidth(self):
1275cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        return self.askinteger(
1276cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            "Tab width",
1277cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            "Spaces per tab? (2-16)",
1278cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            parent=self.text,
1279cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            initialvalue=self.indentwidth,
1280cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            minvalue=2,
1281cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            maxvalue=16) or self.tabwidth
1282cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1283cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # Guess indentwidth from text content.
1284cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # Return guessed indentwidth.  This should not be believed unless
1285cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # it's in a reasonable range (e.g., it will be 0 if no indented
1286cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # blocks are found).
1287cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1288cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def guess_indent(self):
1289cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        opener, indented = IndentSearcher(self.text, self.tabwidth).run()
1290cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if opener and indented:
1291cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            raw, indentsmall = classifyws(opener, self.tabwidth)
1292cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            raw, indentlarge = classifyws(indented, self.tabwidth)
1293cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        else:
1294cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            indentsmall = indentlarge = 0
1295cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        return indentlarge - indentsmall
1296cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1297cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser# "line.col" -> line, as an int
1298cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserdef index2line(index):
1299cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    return int(float(index))
1300cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1301cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser# Look at the leading whitespace in s.
1302cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser# Return pair (# of leading ws characters,
1303cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser#              effective # of leading blanks after expanding
1304cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser#              tabs to width tabwidth)
1305cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1306cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserdef classifyws(s, tabwidth):
1307cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    raw = effective = 0
1308cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    for ch in s:
1309cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if ch == ' ':
1310cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            raw = raw + 1
1311cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            effective = effective + 1
1312cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        elif ch == '\t':
1313cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            raw = raw + 1
1314cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            effective = (effective // tabwidth + 1) * tabwidth
1315cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        else:
1316cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            break
1317cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    return raw, effective
1318cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1319cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserimport tokenize
1320cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser_tokenize = tokenize
1321cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserdel tokenize
1322cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1323cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserclass IndentSearcher:
1324cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1325cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # .run() chews over the Text widget, looking for a block opener
1326cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # and the stmt following it.  Returns a pair,
1327cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    #     (line containing block opener, line containing stmt)
1328cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    # Either or both may be None.
1329cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1330cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def __init__(self, text, tabwidth):
1331cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        self.text = text
1332cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        self.tabwidth = tabwidth
1333cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        self.i = self.finished = 0
1334cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        self.blkopenline = self.indentedline = None
1335cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1336cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def readline(self):
1337cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if self.finished:
1338cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            return ""
1339cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        i = self.i = self.i + 1
1340cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        mark = `i` + ".0"
1341cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if self.text.compare(mark, ">=", "end"):
1342cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            return ""
1343cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        return self.text.get(mark, mark + " lineend+1c")
1344cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1345cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def tokeneater(self, type, token, start, end, line,
1346cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                   INDENT=_tokenize.INDENT,
1347cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                   NAME=_tokenize.NAME,
1348cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                   OPENERS=('class', 'def', 'for', 'if', 'try', 'while')):
1349cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        if self.finished:
1350cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            pass
1351cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        elif type == NAME and token in OPENERS:
1352cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            self.blkopenline = line
1353cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        elif type == INDENT and self.blkopenline:
1354cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            self.indentedline = line
1355cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            self.finished = 1
1356cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1357cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser    def run(self):
1358cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        save_tabsize = _tokenize.tabsize
1359cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        _tokenize.tabsize = self.tabwidth
1360cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        try:
1361cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            try:
1362cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                _tokenize.tokenize(self.readline, self.tokeneater)
1363cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            except _tokenize.TokenError:
1364cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                # since we cut off the tokenizer early, we can trigger
1365cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                # spurious errors
1366cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser                pass
1367cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        finally:
1368cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser            _tokenize.tabsize = save_tabsize
1369cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser        return self.blkopenline, self.indentedline
1370cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
1371cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser### end autoindent code ###
1372cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser
13737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef prepstr(s):
13747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # Helper to extract the underscore from a string, e.g.
13757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # prepstr("Co_py") returns (2, "Copy").
1376220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser    i = s.find('_')
13777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    if i >= 0:
13787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        s = s[:i] + s[i+1:]
13797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    return i, s
13807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
13817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
13827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererkeynames = {
13837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 'bracketleft': '[',
13847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 'bracketright': ']',
13857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 'slash': '/',
13867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer}
13877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
13887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef get_accelerator(keydefs, event):
13897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    keylist = keydefs.get(event)
13907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    if not keylist:
13917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return ""
13927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = keylist[0]
1393220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser    s = re.sub(r"-[a-z]\b", lambda m: m.group().upper(), s)
13947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s)
13957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub("Key-", "", s)
13967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub("Cancel","Ctrl-Break",s)   # dscherer@cmu.edu
13977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub("Control-", "Ctrl-", s)
13987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub("-", "+", s)
13997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub("><", " ", s)
14007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub("<", "", s)
14017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub(">", "", s)
14027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    return s
14037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
14047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
14057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef fixwordbreaks(root):
14067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # Make sure that Tk's double-click and next/previous word
14077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # operations use our definition of a word (i.e. an identifier)
14087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    tk = root.tk
14097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded
14107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_]')
14117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]')
14127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
14137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
14147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef test():
14157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    root = Tk()
14167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    fixwordbreaks(root)
14177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    root.withdraw()
14187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    if sys.argv[1:]:
14197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        filename = sys.argv[1]
14207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    else:
14217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        filename = None
14227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    edit = EditorWindow(root=root, filename=filename)
14237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    edit.set_close_hook(root.quit)
14247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    root.mainloop()
14257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    root.destroy()
14267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
14277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererif __name__ == '__main__':
14287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    test()
1429