EditorWindow.py revision 1b3c26998e0f8b6975f7bbccf043c0afe398f151
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 227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererclass EditorWindow: 237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer from Percolator import Percolator 247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer from ColorDelegator import ColorDelegator 257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer from UndoDelegator import UndoDelegator 267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer from IOBinding import IOBinding 277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer import Bindings 287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer from Tkinter import Toplevel 297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer from MultiStatusBar import MultiStatusBar 307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer vars = {} 327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def __init__(self, flist=None, filename=None, key=None, root=None): 34dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava currentTheme=idleConf.CurrentTheme() 357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.flist = flist 367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer root = root or flist.root 377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.root = root 387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.menubar = Menu(root) 397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.top = top = self.Toplevel(root, menu=self.menubar) 400c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava if flist: 410c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava self.vars = flist.vars 420c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava #self.top.instanceDict makes flist.inversedict avalable to 430c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava #configDialog.py so it can access all EditorWindow instaces 440c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava self.top.instanceDict=flist.inversedict 451d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava self.recentFilesPath=os.path.join(idleConf.GetUserCfgDir(), 461d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava 'recent-files.lst') 47889f8bf259eee088d2d81e3978fbdf34585fc9aeKurt B. Kaiser self.break_set = False 487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.vbar = vbar = Scrollbar(top, name='vbar') 497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text_frame = text_frame = Frame(top) 50dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava self.text = text = Text(text_frame, name='text', padx=5, wrap=None, 51dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava foreground=idleConf.GetHighlight(currentTheme, 52dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava 'normal',fgBg='fg'), 53dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava background=idleConf.GetHighlight(currentTheme, 54dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava 'normal',fgBg='bg'), 55dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava highlightcolor=idleConf.GetHighlight(currentTheme, 56dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava 'hilite',fgBg='fg'), 57dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava highlightbackground=idleConf.GetHighlight(currentTheme, 58dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava 'hilite',fgBg='bg'), 59dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava insertbackground=idleConf.GetHighlight(currentTheme, 60dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava 'cursor',fgBg='fg'), 61dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava width=idleConf.GetOption('main','EditorWindow','width'), 62dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava height=idleConf.GetOption('main','EditorWindow','height') ) 637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.createmenubar() 657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.apply_bindings() 667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.top.protocol("WM_DELETE_WINDOW", self.close) 687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.top.bind("<<close-window>>", self.close_event) 697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<center-insert>>", self.center_insert_event) 707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<help>>", self.help_dialog) 717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<good-advice>>", self.good_advice) 72abdfc4147d1f1334bb4dbaf5d9dd66af1db175adSteven M. Gava text.bind("<<view-readme>>", self.view_readme) 737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<python-docs>>", self.python_docs) 747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<about-idle>>", self.about_dialog) 753b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gava text.bind("<<open-config-dialog>>", self.config_dialog) 767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<open-module>>", self.open_module) 777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<do-nothing>>", lambda event: "break") 787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<select-all>>", self.select_all) 797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<remove-selection>>", self.remove_selection) 80c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.bind("<<find>>", self.find_event) 81c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.bind("<<find-again>>", self.find_again_event) 82c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.bind("<<find-in-files>>", self.find_in_files_event) 83c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.bind("<<find-selection>>", self.find_selection_event) 84c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.bind("<<replace>>", self.replace_event) 85c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.bind("<<goto-line>>", self.goto_line_event) 867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<3>", self.right_menu_event) 87cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<smart-backspace>>",self.smart_backspace_event) 88cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<newline-and-indent>>",self.newline_and_indent_event) 89cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<smart-indent>>",self.smart_indent_event) 90cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<indent-region>>",self.indent_region_event) 91cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<dedent-region>>",self.dedent_region_event) 92cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<comment-region>>",self.comment_region_event) 93cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<uncomment-region>>",self.uncomment_region_event) 94cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<tabify-region>>",self.tabify_region_event) 95cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<untabify-region>>",self.untabify_region_event) 96cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<toggle-tabs>>",self.toggle_tabs_event) 97cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<change-indentwidth>>",self.change_indentwidth_event) 98cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if flist: 1007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer flist.inversedict[self] = key 1017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if key: 1027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer flist.dict[key] = self 1037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<open-new-window>>", self.flist.new_callback) 1047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<close-all-windows>>", self.flist.close_all_callback) 1057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<open-class-browser>>", self.open_class_browser) 1067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<open-path-browser>>", self.open_path_browser) 1077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 108898a365c276951ab2471afe2e24bbc910666d361Steven M. Gava self.set_status_bar() 1097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer vbar['command'] = text.yview 1107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer vbar.pack(side=RIGHT, fill=Y) 1117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text['yscrollcommand'] = vbar.set 112b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava fontWeight='normal' 113b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava if idleConf.GetOption('main','EditorWindow','font-bold',type='bool'): 114b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava fontWeight='bold' 115dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava text.config(font=(idleConf.GetOption('main','EditorWindow','font'), 116b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava idleConf.GetOption('main','EditorWindow','font-size'), 117b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava fontWeight)) 1187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text_frame.pack(side=LEFT, fill=BOTH, expand=1) 1197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.pack(side=TOP, fill=BOTH, expand=1) 1207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.focus_set() 1217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 1227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.per = per = self.Percolator(text) 1237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.ispythonsource(filename): 124dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser self.color = color = self.ColorDelegator() 125dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser per.insertfilter(color) 1267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ##print "Initial colorizer" 1277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 1287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ##print "No initial colorizer" 1297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.color = None 130dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser 131dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser self.undo = undo = self.UndoDelegator() 132dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser per.insertfilter(undo) 133dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser text.undo_block_start = undo.undo_block_start 134dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser text.undo_block_stop = undo.undo_block_stop 135dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser undo.set_saved_change_hook(self.saved_change_hook) 136dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser 137dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser # IOBinding implements file I/O and printing functionality 1387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.io = io = self.IOBinding(self) 139dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser io.set_filename_change_hook(self.filename_change_hook) 140dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser 1411d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava #create the Recent Files submenu 1421d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava self.menuRecentFiles=Menu(self.menubar) 1431d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava self.menudict['file'].insert_cascade(3,label='Recent Files', 1441d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava underline=0,menu=self.menuRecentFiles) 1451d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava self.UpdateRecentFilesList() 1467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 1477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if filename: 1487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if os.path.exists(filename): 1497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer io.loadfile(filename) 1507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 1517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer io.set_filename(filename) 1527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.saved_change_hook() 1537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 1547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.load_extensions() 1557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 1567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu = self.menudict.get('windows') 1577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if menu: 1587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer end = menu.index("end") 1597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if end is None: 1607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer end = -1 1617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if end >= 0: 1627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu.add_separator() 1637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer end = end + 1 1647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.wmenu_end = end 1657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer WindowList.register_callback(self.postwindowsmenu) 1667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 1677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Some abstractions so IDLE extensions are cross-IDE 1687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.askyesno = tkMessageBox.askyesno 1697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.askinteger = tkSimpleDialog.askinteger 1707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.showerror = tkMessageBox.showerror 1717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 1727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.extensions.has_key('AutoIndent'): 1737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.extensions['AutoIndent'].set_indentation_params( 1747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.ispythonsource(filename)) 1750c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava 1767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def set_status_bar(self): 177898a365c276951ab2471afe2e24bbc910666d361Steven M. Gava self.status_bar = self.MultiStatusBar(self.top) 1787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.status_bar.set_label('column', 'Col: ?', side=RIGHT) 1797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.status_bar.set_label('line', 'Ln: ?', side=RIGHT) 1807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.status_bar.pack(side=BOTTOM, fill=X) 1817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.bind('<KeyRelease>', self.set_line_and_column) 1827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.bind('<ButtonRelease>', self.set_line_and_column) 1837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.after_idle(self.set_line_and_column) 1847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 1857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def set_line_and_column(self, event=None): 1867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer line, column = string.split(self.text.index(INSERT), '.') 1877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.status_bar.set_label('column', 'Col: %s' % column) 1887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.status_bar.set_label('line', 'Ln: %s' % line) 1897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 1907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def wakeup(self): 1917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.top.wm_state() == "iconic": 1927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.top.wm_deiconify() 1937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 1947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.top.tkraise() 1957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.focus_set() 1967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 1977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu_specs = [ 1987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ("file", "_File"), 1997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ("edit", "_Edit"), 2007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ("format", "F_ormat"), 2017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ("run", "_Run"), 20282c6682bb776bb59e10a522897534af69938194fSteven M. Gava ("settings", "_Settings"), 2037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ("windows", "_Windows"), 2047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ("help", "_Help"), 2057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ] 2067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 2077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def createmenubar(self): 2087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer mbar = self.menubar 2097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.menudict = menudict = {} 2107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer for name, label in self.menu_specs: 2117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer underline, label = prepstr(label) 2127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menudict[name] = menu = Menu(mbar, name=name) 2137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer mbar.add_cascade(label=label, menu=menu, underline=underline) 2147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.fill_menus() 2151d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava #create the ExtraHelp menu, if required 2160c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava self.ResetExtraHelpMenu() 2177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 2187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def postwindowsmenu(self): 2197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Only called when Windows menu exists 2207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # XXX Actually, this Just-In-Time updating interferes badly 2217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # XXX with the tear-off feature. It would be better to update 2227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # XXX all Windows menus whenever the list of windows changes. 2237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu = self.menudict['windows'] 2247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer end = menu.index("end") 2257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if end is None: 2267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer end = -1 2277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if end > self.wmenu_end: 2287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu.delete(self.wmenu_end+1, end) 2297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer WindowList.add_windows_to_menu(menu) 2307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 2317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer rmenu = None 2327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 2337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def right_menu_event(self, event): 2347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.tag_remove("sel", "1.0", "end") 2357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.mark_set("insert", "@%d,%d" % (event.x, event.y)) 2367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not self.rmenu: 2377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.make_rmenu() 2387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer rmenu = self.rmenu 2397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.event = event 2407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer iswin = sys.platform[:3] == 'win' 2417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if iswin: 2427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.config(cursor="arrow") 2437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer rmenu.tk_popup(event.x_root, event.y_root) 2447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if iswin: 2457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.config(cursor="ibeam") 2467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 2477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer rmenu_specs = [ 2487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # ("Label", "<<virtual-event>>"), ... 2497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ("Close", "<<close-window>>"), # Example 2507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ] 2517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 2527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def make_rmenu(self): 2537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer rmenu = Menu(self.text, tearoff=0) 2547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer for label, eventname in self.rmenu_specs: 2557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def command(text=self.text, eventname=eventname): 2567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.event_generate(eventname) 2577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer rmenu.add_command(label=label, command=command) 2587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.rmenu = rmenu 2597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 2607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def about_dialog(self, event=None): 2617d9ed726fb6ec15dbfb8e922d35aa8816cbd0b0cSteven M. Gava aboutDialog.AboutDialog(self.top,'About IDLEfork') 2627d9ed726fb6ec15dbfb8e922d35aa8816cbd0b0cSteven M. Gava 2633b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gava def config_dialog(self, event=None): 2643b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gava configDialog.ConfigDialog(self.top,'Settings') 2653b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gava 2667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def good_advice(self, event=None): 2677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tkMessageBox.showinfo('Advice', "Don't Panic!", master=self.text) 2687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 269abdfc4147d1f1334bb4dbaf5d9dd66af1db175adSteven M. Gava def view_readme(self, event=None): 270abdfc4147d1f1334bb4dbaf5d9dd66af1db175adSteven M. Gava fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'README.txt') 271abdfc4147d1f1334bb4dbaf5d9dd66af1db175adSteven M. Gava textView.TextViewer(self.top,'IDLEfork - README',fn) 272abdfc4147d1f1334bb4dbaf5d9dd66af1db175adSteven M. Gava 2737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def help_dialog(self, event=None): 274b9d07b5a8b8b70268ffa520895e7843ab594a486Steven M. Gava fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'help.txt') 275b9d07b5a8b8b70268ffa520895e7843ab594a486Steven M. Gava textView.TextViewer(self.top,'Help',fn) 276b9d07b5a8b8b70268ffa520895e7843ab594a486Steven M. Gava 2777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer help_url = "http://www.python.org/doc/current/" 278afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser if sys.platform[:3] == "win": 279afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser fn = os.path.dirname(__file__) 280931625dc77cfd527b059e579615d517d8d994110Steven M. Gava fn = os.path.join(fn, os.pardir, os.pardir, "pythlp.chm") 281afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser fn = os.path.normpath(fn) 282afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser if os.path.isfile(fn): 283afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser help_url = fn 284931625dc77cfd527b059e579615d517d8d994110Steven M. Gava else: 285931625dc77cfd527b059e579615d517d8d994110Steven M. Gava fn = os.path.dirname(__file__) 286931625dc77cfd527b059e579615d517d8d994110Steven M. Gava fn = os.path.join(fn, os.pardir, os.pardir, "Doc", "index.html") 287931625dc77cfd527b059e579615d517d8d994110Steven M. Gava fn = os.path.normpath(fn) 288931625dc77cfd527b059e579615d517d8d994110Steven M. Gava if os.path.isfile(fn): 289931625dc77cfd527b059e579615d517d8d994110Steven M. Gava help_url = fn 290afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser del fn 291931625dc77cfd527b059e579615d517d8d994110Steven M. Gava def python_docs(self, event=None): 292931625dc77cfd527b059e579615d517d8d994110Steven M. Gava os.startfile(self.help_url) 293931625dc77cfd527b059e579615d517d8d994110Steven M. Gava else: 294931625dc77cfd527b059e579615d517d8d994110Steven M. Gava def python_docs(self, event=None): 295931625dc77cfd527b059e579615d517d8d994110Steven M. Gava self.display_docs(self.help_url) 2960c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava 2970c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava def display_docs(self, url): 2980c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava webbrowser.open(url) 2997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 3007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def select_all(self, event=None): 3017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.tag_add("sel", "1.0", "end-1c") 3027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.mark_set("insert", "1.0") 3037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.see("insert") 3047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return "break" 3057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 3067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def remove_selection(self, event=None): 3077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.tag_remove("sel", "1.0", "end") 3087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.see("insert") 3097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 310c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava def find_event(self, event): 311c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava SearchDialog.find(self.text) 312c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava return "break" 313c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava 314c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava def find_again_event(self, event): 315c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava SearchDialog.find_again(self.text) 316c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava return "break" 317c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava 318c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava def find_selection_event(self, event): 319c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava SearchDialog.find_selection(self.text) 320c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava return "break" 321c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava 322c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava def find_in_files_event(self, event): 323c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava GrepDialog.grep(self.text, self.io, self.flist) 324c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava return "break" 325c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava 326c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava def replace_event(self, event): 327c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava ReplaceDialog.replace(self.text) 328c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava return "break" 329c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava 330c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava def goto_line_event(self, event): 331c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text = self.text 332c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava lineno = tkSimpleDialog.askinteger("Goto", 333c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava "Go to line number:",parent=text) 334c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava if lineno is None: 335c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava return "break" 336c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava if lineno <= 0: 337c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.bell() 338c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava return "break" 339c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.mark_set("insert", "%d.0" % lineno) 340c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.see("insert") 341c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava 3427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def open_module(self, event=None): 3437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # XXX Shouldn't this be in IOBinding or in FileList? 3447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer try: 3457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer name = self.text.get("sel.first", "sel.last") 3467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer except TclError: 3477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer name = "" 3487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 3497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer name = string.strip(name) 3507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not name: 3517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer name = tkSimpleDialog.askstring("Module", 3527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer "Enter the name of a Python module\n" 3537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer "to search on sys.path and open:", 3547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer parent=self.text) 3557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if name: 3567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer name = string.strip(name) 3577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not name: 3587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return 3597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # XXX Ought to support package syntax 3607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # XXX Ought to insert current file's directory in front of path 3617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer try: 3627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer (f, file, (suffix, mode, type)) = imp.find_module(name) 3637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer except (NameError, ImportError), msg: 3647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tkMessageBox.showerror("Import error", str(msg), parent=self.text) 3657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return 3667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if type != imp.PY_SOURCE: 3677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tkMessageBox.showerror("Unsupported type", 3687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer "%s is not a source module" % name, parent=self.text) 3697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return 3707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if f: 3717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer f.close() 3727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.flist: 3737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.flist.open(file) 3747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 3757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.io.loadfile(file) 3767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 3777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def open_class_browser(self, event=None): 3787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer filename = self.io.filename 3797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not filename: 3807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tkMessageBox.showerror( 3817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer "No filename", 3827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer "This buffer has no associated filename", 3837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer master=self.text) 3847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.focus_set() 3857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return None 3867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer head, tail = os.path.split(filename) 3877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer base, ext = os.path.splitext(tail) 3887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer import ClassBrowser 3897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ClassBrowser.ClassBrowser(self.flist, base, [head]) 3907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 3917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def open_path_browser(self, event=None): 3927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer import PathBrowser 3937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer PathBrowser.PathBrowser(self.flist) 3947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 3957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def gotoline(self, lineno): 3967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if lineno is not None and lineno > 0: 3977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.mark_set("insert", "%d.0" % lineno) 3987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.tag_remove("sel", "1.0", "end") 3997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.tag_add("sel", "insert", "insert +1l") 4007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.center() 4017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 4027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def ispythonsource(self, filename): 4037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not filename: 4047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return 1 4057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer base, ext = os.path.splitext(os.path.basename(filename)) 4067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if os.path.normcase(ext) in (".py", ".pyw"): 4077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return 1 4087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer try: 4097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer f = open(filename) 4107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer line = f.readline() 4117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer f.close() 4127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer except IOError: 4137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return 0 4147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return line[:2] == '#!' and string.find(line, 'python') >= 0 4157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 4167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def close_hook(self): 4177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.flist: 4187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.flist.close_edit(self) 4197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 4207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def set_close_hook(self, close_hook): 4217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.close_hook = close_hook 4227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 4237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def filename_change_hook(self): 4247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.flist: 4257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.flist.filename_changed_edit(self) 4267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.saved_change_hook() 4277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.ispythonsource(self.io.filename): 4287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.addcolorizer() 4297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 4307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.rmcolorizer() 4317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 4327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def addcolorizer(self): 4337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.color: 4347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return 4357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ##print "Add colorizer" 4367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.per.removefilter(self.undo) 4377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.color = self.ColorDelegator() 4387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.per.insertfilter(self.color) 4397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.per.insertfilter(self.undo) 4407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 4417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def rmcolorizer(self): 4427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not self.color: 4437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return 4447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ##print "Remove colorizer" 4457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.per.removefilter(self.undo) 4467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.per.removefilter(self.color) 4477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.color = None 4487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.per.insertfilter(self.undo) 449b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava 450b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava def ResetColorizer(self): 45183118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser "Update the colour theme if it is changed" 45283118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser # Called from configDialog.py 453b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava if self.color: 454b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava self.color = self.ColorDelegator() 455b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava self.per.insertfilter(self.color) 4567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 457b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava def ResetFont(self): 45883118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser "Update the text widgets' font if it is changed" 45983118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser # Called from configDialog.py 460b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava fontWeight='normal' 461b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava if idleConf.GetOption('main','EditorWindow','font-bold',type='bool'): 462b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava fontWeight='bold' 463b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava self.text.config(font=(idleConf.GetOption('main','EditorWindow','font'), 464b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava idleConf.GetOption('main','EditorWindow','font-size'), 465b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava fontWeight)) 466b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava 467dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava def ResetKeybindings(self): 46883118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser "Update the keybindings if they are changed" 46983118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser # Called from configDialog.py 470dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava self.Bindings.default_keydefs=idleConf.GetCurrentKeySet() 471dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava keydefs = self.Bindings.default_keydefs 472dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava for event, keylist in keydefs.items(): 473dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava self.text.event_delete(event) 474dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava self.apply_bindings() 475dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava #update menu accelerators 476dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava menuEventDict={} 477dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava for menu in self.Bindings.menudefs: 478dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava menuEventDict[menu[0]]={} 479dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava for item in menu[1]: 480dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava if item: 481dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava menuEventDict[menu[0]][prepstr(item[0])[1]]=item[1] 482dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava for menubarItem in self.menudict.keys(): 483dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava menu=self.menudict[menubarItem] 484dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava end=menu.index(END)+1 485dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava for index in range(0,end): 486dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava if menu.type(index)=='command': 487dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava accel=menu.entrycget(index,'accelerator') 488dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava if accel: 489dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava itemName=menu.entrycget(index,'label') 490dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava event='' 491dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava if menuEventDict.has_key(menubarItem): 492dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava if menuEventDict[menubarItem].has_key(itemName): 493dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava event=menuEventDict[menubarItem][itemName] 494dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava if event: 495dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava #print 'accel was:',accel 496dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava accel=get_accelerator(keydefs, event) 497dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava menu.entryconfig(index,accelerator=accel) 498dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava #print 'accel now:',accel,'\n' 499dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava 5000c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava def ResetExtraHelpMenu(self): 50183118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser "Load or update the Extra Help menu if required" 5020c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava menuList=idleConf.GetAllExtraHelpSourcesList() 5030c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava helpMenu=self.menudict['help'] 5040c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava cascadeIndex=helpMenu.index(END)-1 5050c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava if menuList: 5060c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava if not hasattr(self,'menuExtraHelp'): 5070c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava self.menuExtraHelp=Menu(self.menubar) 5080c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava helpMenu.insert_cascade(cascadeIndex,label='Extra Help', 5090c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava underline=1,menu=self.menuExtraHelp) 5100c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava self.menuExtraHelp.delete(1,END) 5110c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava for menuItem in menuList: 5120c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava self.menuExtraHelp.add_command(label=menuItem[0], 5131d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava command=self.__DisplayExtraHelpCallback(menuItem[1])) 5140c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava else: #no extra help items 5150c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava if hasattr(self,'menuExtraHelp'): 5160c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava helpMenu.delete(cascadeIndex-1) 5170c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava del(self.menuExtraHelp) 5181d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava 5191d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava def __DisplayExtraHelpCallback(self,helpFile): 5201d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava def DisplayExtraHelp(helpFile=helpFile): 5211d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava self.display_docs(helpFile) 5221d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava return DisplayExtraHelp 5230c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava 5241d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava def UpdateRecentFilesList(self,newFile=None): 52583118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser "Load or update the recent files list, and menu if required" 5261d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava rfList=[] 5271d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava if os.path.exists(self.recentFilesPath): 5281d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava RFfile=open(self.recentFilesPath,'r') 5291d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava try: 5301d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava rfList=RFfile.readlines() 5311d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava finally: 5321d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava RFfile.close() 5331d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava if newFile: 5341d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava newFile=os.path.abspath(newFile)+'\n' 5351d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava if newFile in rfList: 5361d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava rfList.remove(newFile) 5371d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava rfList.insert(0,newFile) 5381d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava rfList=self.__CleanRecentFiles(rfList) 53983118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser #print self.flist.inversedict 54083118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser #print self.top.instanceDict 54183118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser #print self 5421d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava if rfList: 5431d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava for instance in self.top.instanceDict.keys(): 5441d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava instance.menuRecentFiles.delete(1,END) 5451d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava for file in rfList: 5461d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava fileName=file[0:-1] 5471d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava instance.menuRecentFiles.add_command(label=fileName, 5481d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava command=instance.__RecentFileCallback(fileName)) 5491d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava 5501d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava def __CleanRecentFiles(self,rfList): 5511d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava origRfList=rfList[:] 5521d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava count=0 5531d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava nonFiles=[] 5541d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava for path in rfList: 5551d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava if not os.path.exists(path[0:-1]): 5561d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava nonFiles.append(count) 5571d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava count=count+1 5581d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava if nonFiles: 5591d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava nonFiles.reverse() 5601d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava for index in nonFiles: 5611d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava del(rfList[index]) 5621d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava if len(rfList)>19: 5631d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava rfList=rfList[0:19] 5641d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava #if rfList != origRfList: 5651d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava RFfile=open(self.recentFilesPath,'w') 5661d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava try: 5671d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava RFfile.writelines(rfList) 5681d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava finally: 5691d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava RFfile.close() 5701d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava return rfList 5711d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava 5721d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava def __RecentFileCallback(self,fileName): 5731d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava def OpenRecentFile(fileName=fileName): 5741d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava self.io.open(editFile=fileName) 5751d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava return OpenRecentFile 5761d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava 5777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def saved_change_hook(self): 5787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer short = self.short_title() 5797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer long = self.long_title() 5807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if short and long: 5817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer title = short + " - " + long 5827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer elif short: 5837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer title = short 5847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer elif long: 5857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer title = long 5867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 5877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer title = "Untitled" 5887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer icon = short or long or title 5897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not self.get_saved(): 5907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer title = "*%s*" % title 5917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer icon = "*%s" % icon 592889f8bf259eee088d2d81e3978fbdf34585fc9aeKurt B. Kaiser if self.break_set: 593889f8bf259eee088d2d81e3978fbdf34585fc9aeKurt B. Kaiser shell = self.flist.pyshell 594889f8bf259eee088d2d81e3978fbdf34585fc9aeKurt B. Kaiser shell.interp.debugger.clear_file_breaks(self) 5957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.top.wm_title(title) 5967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.top.wm_iconname(icon) 5977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 5987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def get_saved(self): 5997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return self.undo.get_saved() 6007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def set_saved(self, flag): 6027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.undo.set_saved(flag) 6037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def reset_undo(self): 6057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.undo.reset_undo() 6067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def short_title(self): 6087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer filename = self.io.filename 6097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if filename: 6107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer filename = os.path.basename(filename) 6117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return filename 6127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def long_title(self): 6147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return self.io.filename or "" 6157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def center_insert_event(self, event): 6177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.center() 6187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def center(self, mark="insert"): 6207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text = self.text 6217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer top, bot = self.getwindowlines() 6227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer lineno = self.getlineno(mark) 6237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer height = bot - top 6247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer newtop = max(1, lineno - height/2) 6257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.yview(float(newtop)) 6267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def getwindowlines(self): 6287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text = self.text 6297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer top = self.getlineno("@0,0") 6307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer bot = self.getlineno("@0,65535") 6317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if top == bot and text.winfo_height() == 1: 6327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Geometry manager hasn't run yet 6337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer height = int(text['height']) 6347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer bot = top + height - 1 6357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return top, bot 6367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def getlineno(self, mark="insert"): 6387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text = self.text 6397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return int(float(text.index(mark))) 6407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def close_event(self, event): 6427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.close() 6437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def maybesave(self): 6457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.io: 64667716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava if not self.get_saved(): 64767716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava if self.top.state()!='normal': 64867716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava self.top.deiconify() 64967716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava self.top.lower() 65067716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava self.top.lift() 6517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return self.io.maybesave() 6527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def close(self): 6547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer reply = self.maybesave() 6557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if reply != "cancel": 6567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self._close() 6577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return reply 6587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def _close(self): 66083118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser #print self.io.filename 6611d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava if self.io.filename: 6621d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava self.UpdateRecentFilesList(newFile=self.io.filename) 663889f8bf259eee088d2d81e3978fbdf34585fc9aeKurt B. Kaiser if self.break_set: 664889f8bf259eee088d2d81e3978fbdf34585fc9aeKurt B. Kaiser shell = self.flist.pyshell 66583118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser shell.interp.debugger.clear_file_breaks(self) 6667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer WindowList.unregister_callback(self.postwindowsmenu) 6677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.close_hook: 6687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.close_hook() 6697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.flist = None 6707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer colorizing = 0 6717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.unload_extensions() 6727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.io.close(); self.io = None 6737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.undo = None # XXX 6747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.color: 6757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer colorizing = self.color.colorizing 6767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer doh = colorizing and self.top 6777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.color.close(doh) # Cancel colorization 6787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text = None 6797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.vars = None 6807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.per.close(); self.per = None 6817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not colorizing: 6827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.top.destroy() 6837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def load_extensions(self): 6857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.extensions = {} 6867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.load_standard_extensions() 6877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def unload_extensions(self): 6897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer for ins in self.extensions.values(): 6907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if hasattr(ins, "close"): 6917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ins.close() 6927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.extensions = {} 6937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def load_standard_extensions(self): 6957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer for name in self.get_standard_extension_names(): 6967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer try: 6977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.load_extension(name) 6987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer except: 6997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer print "Failed to load extension", `name` 7007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer import traceback 7017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer traceback.print_exc() 7027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 7037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def get_standard_extension_names(self): 704dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava return idleConf.GetExtensions() 7057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 7067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def load_extension(self, name): 7077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer mod = __import__(name, globals(), locals(), []) 7087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer cls = getattr(mod, name) 7097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ins = cls(self) 7107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.extensions[name] = ins 71172c3bf076f785aaf54d63a7e8cae29bc8282920eSteven M. Gava keydefs=idleConf.GetExtensionBindings(name) 7127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if keydefs: 7137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.apply_bindings(keydefs) 7147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer for vevent in keydefs.keys(): 7157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer methodname = string.replace(vevent, "-", "_") 7167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer while methodname[:1] == '<': 7177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer methodname = methodname[1:] 7187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer while methodname[-1:] == '>': 7197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer methodname = methodname[:-1] 7207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer methodname = methodname + "_event" 7217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if hasattr(ins, methodname): 7227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.bind(vevent, getattr(ins, methodname)) 7237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if hasattr(ins, "menudefs"): 7247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.fill_menus(ins.menudefs, keydefs) 7257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return ins 7267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 7277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def apply_bindings(self, keydefs=None): 7287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if keydefs is None: 7297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer keydefs = self.Bindings.default_keydefs 7307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text = self.text 7317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.keydefs = keydefs 7327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer for event, keylist in keydefs.items(): 7337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if keylist: 7347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer apply(text.event_add, (event,) + tuple(keylist)) 7357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 7367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def fill_menus(self, defs=None, keydefs=None): 73783118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser """Add appropriate entries to the menus and submenus 73883118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser 73983118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser Menus that are absent or None in self.menudict are ignored. 74083118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser """ 7417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if defs is None: 7427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer defs = self.Bindings.menudefs 7437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if keydefs is None: 7447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer keydefs = self.Bindings.default_keydefs 7457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menudict = self.menudict 7467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text = self.text 7477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer for mname, itemlist in defs: 7487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu = menudict.get(mname) 7497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not menu: 7507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer continue 7517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer for item in itemlist: 7527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not item: 7537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu.add_separator() 7547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 7557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer label, event = item 7567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer checkbutton = (label[:1] == '!') 7577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if checkbutton: 7587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer label = label[1:] 7597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer underline, label = prepstr(label) 7607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer accelerator = get_accelerator(keydefs, event) 7617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def command(text=text, event=event): 7627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.event_generate(event) 7637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if checkbutton: 7647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer var = self.getrawvar(event, BooleanVar) 7657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu.add_checkbutton(label=label, underline=underline, 7667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer command=command, accelerator=accelerator, 7677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer variable=var) 7687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 7697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu.add_command(label=label, underline=underline, 7707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer command=command, accelerator=accelerator) 7717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 7727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def getvar(self, name): 7737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer var = self.getrawvar(name) 7747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if var: 7757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return var.get() 7767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 7777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def setvar(self, name, value, vartype=None): 7787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer var = self.getrawvar(name, vartype) 7797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if var: 7807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer var.set(value) 7817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 7827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def getrawvar(self, name, vartype=None): 7837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer var = self.vars.get(name) 7847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not var and vartype: 7857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.vars[name] = var = vartype(self.text) 7867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return var 7877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 7887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Tk implementations of "virtual text methods" -- each platform 7897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # reusing IDLE's support code needs to define these for its GUI's 7907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # flavor of widget. 7917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 7927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Is character at text_index in a Python string? Return 0 for 7937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # "guaranteed no", true for anything else. This info is expensive 7947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # to compute ab initio, but is probably already known by the 7957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # platform's colorizer. 7967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 7977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def is_char_in_string(self, text_index): 7987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.color: 7997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Return true iff colorizer hasn't (re)gotten this far 8007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # yet, or the character is tagged as being in a string 8017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return self.text.tag_prevrange("TODO", text_index) or \ 8027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer "STRING" in self.text.tag_names(text_index) 8037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 8047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # The colorizer is missing: assume the worst 8057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return 1 8067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # If a selection is defined in the text widget, return (start, 8087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # end) as Tkinter text indices, otherwise return (None, None) 8097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def get_selection_indices(self): 8107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer try: 8117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer first = self.text.index("sel.first") 8127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer last = self.text.index("sel.last") 8137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return first, last 8147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer except TclError: 8157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return None, None 8167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Return the text widget's current view of what a tab stop means 8187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # (equivalent width in spaces). 8197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def get_tabwidth(self): 8217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer current = self.text['tabs'] or TK_TABWIDTH_DEFAULT 8227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return int(current) 8237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Set the text widget's current view of what a tab stop means. 8257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def set_tabwidth(self, newtabwidth): 8277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text = self.text 8287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.get_tabwidth() != newtabwidth: 8297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer pixels = text.tk.call("font", "measure", text["font"], 8307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer "-displayof", text.master, 831afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser "n" * newtabwidth) 8327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.configure(tabs=pixels) 8337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 834cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser### begin autoindent code ### 835cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 836cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # usetabs true -> literal tab characters are used by indent and 837cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # dedent cmds, possibly mixed with spaces if 838cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # indentwidth is not a multiple of tabwidth 839cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # false -> tab characters are converted to spaces by indent 840cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # and dedent cmds, and ditto TAB keystrokes 841cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # indentwidth is the number of characters per logical indent level. 842cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # tabwidth is the display width of a literal tab character. 843cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # CAUTION: telling Tk to use anything other than its default 844cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # tab setting causes it to use an entirely different tabbing algorithm, 845cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # treating tab stops as fixed distances from the left margin. 846cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Nobody expects this, so for now tabwidth should never be changed. 847cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser usetabs = 0 848cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser indentwidth = 4 849cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser tabwidth = 8 # for IDLE use, must remain 8 until Tk is fixed 850cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 851cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # If context_use_ps1 is true, parsing searches back for a ps1 line; 852cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # else searches for a popular (if, def, ...) Python stmt. 853cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser context_use_ps1 = 0 854cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 855cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # When searching backwards for a reliable place to begin parsing, 856cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # first start num_context_lines[0] lines back, then 857cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # num_context_lines[1] lines back if that didn't work, and so on. 858cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # The last value should be huge (larger than the # of lines in a 859cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # conceivable file). 860cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Making the initial values larger slows things down more often. 861cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser num_context_lines = 50, 500, 5000000 862cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 863cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def config(self, **options): 864cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for key, value in options.items(): 865cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if key == 'usetabs': 866cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.usetabs = value 867cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif key == 'indentwidth': 868cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.indentwidth = value 869cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif key == 'tabwidth': 870cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.tabwidth = value 871cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif key == 'context_use_ps1': 872cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.context_use_ps1 = value 873cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 874cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raise KeyError, "bad option name: %s" % `key` 875cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 876cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # If ispythonsource and guess are true, guess a good value for 877cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # indentwidth based on file content (if possible), and if 878cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # indentwidth != tabwidth set usetabs false. 879cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # In any case, adjust the Text widget's view of what a tab 880cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # character means. 881cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 882cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def set_indentation_params(self, ispythonsource, guess=1): 883cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if guess and ispythonsource: 884cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser i = self.guess_indent() 885cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if 2 <= i <= 8: 886cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.indentwidth = i 887cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if self.indentwidth != self.tabwidth: 888cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.usetabs = 0 889cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 890cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_tabwidth(self.tabwidth) 891cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 892cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def smart_backspace_event(self, event): 893cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text = self.text 894cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser first, last = self.get_selection_indices() 895cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if first and last: 896cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete(first, last) 897cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.mark_set("insert", first) 898cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 899cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Delete whitespace left, until hitting a real char or closest 900cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # preceding virtual tab stop. 901cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser chars = text.get("insert linestart", "insert") 902cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if chars == '': 903cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if text.compare("insert", ">", "1.0"): 904cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # easy: delete preceding newline 905cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete("insert-1c") 906cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 907cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bell() # at start of buffer 908cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 909cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if chars[-1] not in " \t": 910cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # easy: delete preceding real char 911cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete("insert-1c") 912cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 913cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Ick. It may require *inserting* spaces if we back up over a 914cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # tab character! This is written to be clear, not fast. 9151b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser tabwidth = self.tabwidth 9161b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser have = len(chars.expandtabs(tabwidth)) 917cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser assert have > 0 918cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser want = ((have - 1) // self.indentwidth) * self.indentwidth 919cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser ncharsdeleted = 0 920cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser while 1: 921cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser chars = chars[:-1] 922cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser ncharsdeleted = ncharsdeleted + 1 9231b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser have = len(chars.expandtabs(tabwidth)) 924cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if have <= want or chars[-1] not in " \t": 925cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser break 926cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_start() 927cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete("insert-%dc" % ncharsdeleted, "insert") 928cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if have < want: 929cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert", ' ' * (want - have)) 930cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_stop() 931cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 932cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 933cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def smart_indent_event(self, event): 934cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # if intraline selection: 935cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # delete it 936cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # elif multiline selection: 937cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # do indent-region & return 938cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # indent one level 939cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text = self.text 940cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser first, last = self.get_selection_indices() 941cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_start() 942cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser try: 943cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if first and last: 944cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if index2line(first) != index2line(last): 945cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return self.indent_region_event(event) 946cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete(first, last) 947cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.mark_set("insert", first) 948cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser prefix = text.get("insert linestart", "insert") 949cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw, effective = classifyws(prefix, self.tabwidth) 950cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if raw == len(prefix): 951cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # only whitespace to the left 952cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.reindent_to(effective + self.indentwidth) 953cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 954cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if self.usetabs: 955cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser pad = '\t' 956cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 9571b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser effective = len(prefix.expandtabs(self.tabwidth)) 958cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser n = self.indentwidth 959cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser pad = ' ' * (n - effective % n) 960cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert", pad) 961cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.see("insert") 962cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 963cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser finally: 964cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_stop() 965cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 966cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def newline_and_indent_event(self, event): 967cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text = self.text 968cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser first, last = self.get_selection_indices() 969cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_start() 970cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser try: 971cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if first and last: 972cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete(first, last) 973cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.mark_set("insert", first) 974cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = text.get("insert linestart", "insert") 975cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser i, n = 0, len(line) 976cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser while i < n and line[i] in " \t": 977cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser i = i+1 978cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if i == n: 979cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # the cursor is in or at leading indentation; just inject 980cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # an empty line at the start 981cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert linestart", '\n') 982cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 983cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser indent = line[:i] 984cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # strip whitespace before insert point 985cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser i = 0 986cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser while line and line[-1] in " \t": 987cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = line[:-1] 988cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser i = i+1 989cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if i: 990cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete("insert - %d chars" % i, "insert") 991cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # strip whitespace after insert point 992cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser while text.get("insert") in " \t": 993cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete("insert") 994cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # start new line 995cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert", '\n') 996cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 997cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # adjust indentation for continuations and block 998cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # open/close first need to find the last stmt 999cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser lno = index2line(text.index('insert')) 1000cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser y = PyParse.Parser(self.indentwidth, self.tabwidth) 1001cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for context in self.num_context_lines: 1002cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser startat = max(lno - context, 1) 1003cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser startatindex = `startat` + ".0" 1004cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser rawtext = text.get(startatindex, "insert") 1005cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser y.set_str(rawtext) 1006cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser bod = y.find_good_parse_start( 1007cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.context_use_ps1, 1008cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self._build_char_in_string_func(startatindex)) 1009cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if bod is not None or startat == 1: 1010cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser break 1011cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser y.set_lo(bod or 0) 1012cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser c = y.get_continuation_type() 1013cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if c != PyParse.C_NONE: 1014cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # The current stmt hasn't ended yet. 1015cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if c == PyParse.C_STRING: 1016cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # inside a string; just mimic the current indent 1017cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert", indent) 1018cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif c == PyParse.C_BRACKET: 1019cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # line up with the first (if any) element of the 1020cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # last open bracket structure; else indent one 1021cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # level beyond the indent of the line with the 1022cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # last open bracket 1023cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.reindent_to(y.compute_bracket_indent()) 1024cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif c == PyParse.C_BACKSLASH: 1025cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # if more than one line in this stmt already, just 1026cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # mimic the current indent; else if initial line 1027cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # has a start on an assignment stmt, indent to 1028cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # beyond leftmost =; else to beyond first chunk of 1029cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # non-whitespace on initial line 1030cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if y.get_num_lines_in_stmt() > 1: 1031cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert", indent) 1032cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 1033cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.reindent_to(y.compute_backslash_indent()) 1034cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 1035cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser assert 0, "bogus continuation type " + `c` 1036cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1037cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1038cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # This line starts a brand new stmt; indent relative to 1039cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # indentation of initial line of closest preceding 1040cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # interesting stmt. 1041cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser indent = y.get_base_indent_string() 1042cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert", indent) 1043cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if y.is_block_opener(): 1044cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.smart_indent_event(event) 1045cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif indent and y.is_block_closer(): 1046cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.smart_backspace_event(event) 1047cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1048cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser finally: 1049cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.see("insert") 1050cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_stop() 1051cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1052cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser auto_indent = newline_and_indent_event 1053cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1054cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Our editwin provides a is_char_in_string function that works 1055cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # with a Tk text index, but PyParse only knows about offsets into 1056cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # a string. This builds a function for PyParse that accepts an 1057cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # offset. 1058cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1059cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def _build_char_in_string_func(self, startindex): 1060cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def inner(offset, _startindex=startindex, 1061cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser _icis=self.is_char_in_string): 1062cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return _icis(_startindex + "+%dc" % offset) 1063cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return inner 1064cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1065cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def indent_region_event(self, event): 1066cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head, tail, chars, lines = self.get_region() 1067cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for pos in range(len(lines)): 1068cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = lines[pos] 1069cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if line: 1070cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw, effective = classifyws(line, self.tabwidth) 1071cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser effective = effective + self.indentwidth 1072cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser lines[pos] = self._make_blanks(effective) + line[raw:] 1073cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_region(head, tail, chars, lines) 1074cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1075cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1076cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def dedent_region_event(self, event): 1077cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head, tail, chars, lines = self.get_region() 1078cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for pos in range(len(lines)): 1079cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = lines[pos] 1080cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if line: 1081cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw, effective = classifyws(line, self.tabwidth) 1082cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser effective = max(effective - self.indentwidth, 0) 1083cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser lines[pos] = self._make_blanks(effective) + line[raw:] 1084cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_region(head, tail, chars, lines) 1085cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1086cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1087cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def comment_region_event(self, event): 1088cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head, tail, chars, lines = self.get_region() 1089cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for pos in range(len(lines) - 1): 1090cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = lines[pos] 1091cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser lines[pos] = '##' + line 1092cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_region(head, tail, chars, lines) 1093cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1094cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def uncomment_region_event(self, event): 1095cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head, tail, chars, lines = self.get_region() 1096cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for pos in range(len(lines)): 1097cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = lines[pos] 1098cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if not line: 1099cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser continue 1100cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if line[:2] == '##': 1101cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = line[2:] 1102cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif line[:1] == '#': 1103cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = line[1:] 1104cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser lines[pos] = line 1105cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_region(head, tail, chars, lines) 1106cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1107cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def tabify_region_event(self, event): 1108cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head, tail, chars, lines = self.get_region() 1109cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser tabwidth = self._asktabwidth() 1110cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for pos in range(len(lines)): 1111cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = lines[pos] 1112cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if line: 1113cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw, effective = classifyws(line, tabwidth) 1114cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser ntabs, nspaces = divmod(effective, tabwidth) 1115cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:] 1116cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_region(head, tail, chars, lines) 1117cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1118cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def untabify_region_event(self, event): 1119cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head, tail, chars, lines = self.get_region() 1120cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser tabwidth = self._asktabwidth() 1121cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for pos in range(len(lines)): 11221b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser lines[pos] = lines[pos].expandtabs(tabwidth) 1123cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_region(head, tail, chars, lines) 1124cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1125cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def toggle_tabs_event(self, event): 1126cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if self.askyesno( 1127cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser "Toggle tabs", 1128cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser "Turn tabs " + ("on", "off")[self.usetabs] + "?", 1129cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser parent=self.text): 1130cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.usetabs = not self.usetabs 1131cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1132cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1133cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # XXX this isn't bound to anything -- see class tabwidth comments 1134cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def change_tabwidth_event(self, event): 1135cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser new = self._asktabwidth() 1136cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if new != self.tabwidth: 1137cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.tabwidth = new 1138cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_indentation_params(0, guess=0) 1139cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1140cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1141cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def change_indentwidth_event(self, event): 1142cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser new = self.askinteger( 1143cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser "Indent width", 1144cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser "New indent width (2-16)", 1145cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser parent=self.text, 1146cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser initialvalue=self.indentwidth, 1147cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser minvalue=2, 1148cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser maxvalue=16) 1149cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if new and new != self.indentwidth: 1150cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.indentwidth = new 1151cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1152cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1153cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def get_region(self): 1154cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text = self.text 1155cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser first, last = self.get_selection_indices() 1156cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if first and last: 1157cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head = text.index(first + " linestart") 1158cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser tail = text.index(last + "-1c lineend +1c") 1159cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 1160cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head = text.index("insert linestart") 1161cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser tail = text.index("insert lineend +1c") 1162cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser chars = text.get(head, tail) 11631b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser lines = chars.split("\n") 1164cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return head, tail, chars, lines 1165cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1166cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def set_region(self, head, tail, chars, lines): 1167cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text = self.text 11681b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser newchars = "\n".join(lines) 1169cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if newchars == chars: 1170cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bell() 1171cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return 1172cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.tag_remove("sel", "1.0", "end") 1173cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.mark_set("insert", head) 1174cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_start() 1175cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete(head, tail) 1176cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert(head, newchars) 1177cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_stop() 1178cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.tag_add("sel", head, "insert") 1179cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1180cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Make string that displays as n leading blanks. 1181cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1182cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def _make_blanks(self, n): 1183cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if self.usetabs: 1184cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser ntabs, nspaces = divmod(n, self.tabwidth) 1185cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return '\t' * ntabs + ' ' * nspaces 1186cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 1187cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return ' ' * n 1188cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1189cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Delete from beginning of line to insert point, then reinsert 1190cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # column logical (meaning use tabs if appropriate) spaces. 1191cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1192cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def reindent_to(self, column): 1193cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text = self.text 1194cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_start() 1195cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if text.compare("insert linestart", "!=", "insert"): 1196cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete("insert linestart", "insert") 1197cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if column: 1198cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert", self._make_blanks(column)) 1199cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_stop() 1200cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1201cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def _asktabwidth(self): 1202cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return self.askinteger( 1203cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser "Tab width", 1204cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser "Spaces per tab? (2-16)", 1205cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser parent=self.text, 1206cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser initialvalue=self.indentwidth, 1207cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser minvalue=2, 1208cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser maxvalue=16) or self.tabwidth 1209cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1210cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Guess indentwidth from text content. 1211cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Return guessed indentwidth. This should not be believed unless 1212cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # it's in a reasonable range (e.g., it will be 0 if no indented 1213cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # blocks are found). 1214cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1215cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def guess_indent(self): 1216cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser opener, indented = IndentSearcher(self.text, self.tabwidth).run() 1217cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if opener and indented: 1218cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw, indentsmall = classifyws(opener, self.tabwidth) 1219cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw, indentlarge = classifyws(indented, self.tabwidth) 1220cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 1221cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser indentsmall = indentlarge = 0 1222cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return indentlarge - indentsmall 1223cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1224cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser# "line.col" -> line, as an int 1225cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserdef index2line(index): 1226cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return int(float(index)) 1227cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1228cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser# Look at the leading whitespace in s. 1229cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser# Return pair (# of leading ws characters, 1230cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser# effective # of leading blanks after expanding 1231cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser# tabs to width tabwidth) 1232cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1233cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserdef classifyws(s, tabwidth): 1234cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw = effective = 0 1235cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for ch in s: 1236cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if ch == ' ': 1237cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw = raw + 1 1238cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser effective = effective + 1 1239cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif ch == '\t': 1240cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw = raw + 1 1241cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser effective = (effective // tabwidth + 1) * tabwidth 1242cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 1243cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser break 1244cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return raw, effective 1245cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1246cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserimport tokenize 1247cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser_tokenize = tokenize 1248cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserdel tokenize 1249cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1250cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserclass IndentSearcher: 1251cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1252cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # .run() chews over the Text widget, looking for a block opener 1253cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # and the stmt following it. Returns a pair, 1254cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # (line containing block opener, line containing stmt) 1255cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Either or both may be None. 1256cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1257cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def __init__(self, text, tabwidth): 1258cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.text = text 1259cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.tabwidth = tabwidth 1260cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.i = self.finished = 0 1261cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.blkopenline = self.indentedline = None 1262cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1263cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def readline(self): 1264cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if self.finished: 1265cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "" 1266cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser i = self.i = self.i + 1 1267cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser mark = `i` + ".0" 1268cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if self.text.compare(mark, ">=", "end"): 1269cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "" 1270cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return self.text.get(mark, mark + " lineend+1c") 1271cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1272cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def tokeneater(self, type, token, start, end, line, 1273cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser INDENT=_tokenize.INDENT, 1274cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser NAME=_tokenize.NAME, 1275cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser OPENERS=('class', 'def', 'for', 'if', 'try', 'while')): 1276cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if self.finished: 1277cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser pass 1278cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif type == NAME and token in OPENERS: 1279cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.blkopenline = line 1280cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif type == INDENT and self.blkopenline: 1281cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.indentedline = line 1282cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.finished = 1 1283cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1284cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def run(self): 1285cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser save_tabsize = _tokenize.tabsize 1286cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser _tokenize.tabsize = self.tabwidth 1287cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser try: 1288cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser try: 1289cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser _tokenize.tokenize(self.readline, self.tokeneater) 1290cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser except _tokenize.TokenError: 1291cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # since we cut off the tokenizer early, we can trigger 1292cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # spurious errors 1293cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser pass 1294cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser finally: 1295cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser _tokenize.tabsize = save_tabsize 1296cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return self.blkopenline, self.indentedline 1297cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1298cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser### end autoindent code ### 1299cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 13007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef prepstr(s): 13017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Helper to extract the underscore from a string, e.g. 13027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # prepstr("Co_py") returns (2, "Copy"). 13037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer i = string.find(s, '_') 13047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if i >= 0: 13057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = s[:i] + s[i+1:] 13067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return i, s 13077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 13087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 13097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererkeynames = { 13107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 'bracketleft': '[', 13117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 'bracketright': ']', 13127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 'slash': '/', 13137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer} 13147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 13157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef get_accelerator(keydefs, event): 13167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer keylist = keydefs.get(event) 13177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not keylist: 13187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return "" 13197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = keylist[0] 13207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub(r"-[a-z]\b", lambda m: string.upper(m.group()), s) 13217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s) 13227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub("Key-", "", s) 13237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub("Cancel","Ctrl-Break",s) # dscherer@cmu.edu 13247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub("Control-", "Ctrl-", s) 13257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub("-", "+", s) 13267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub("><", " ", s) 13277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub("<", "", s) 13287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub(">", "", s) 13297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return s 13307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 13317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 13327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef fixwordbreaks(root): 13337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Make sure that Tk's double-click and next/previous word 13347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # operations use our definition of a word (i.e. an identifier) 13357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tk = root.tk 13367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded 13377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_]') 13387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]') 13397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 13407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 13417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef test(): 13427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer root = Tk() 13437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer fixwordbreaks(root) 13447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer root.withdraw() 13457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if sys.argv[1:]: 13467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer filename = sys.argv[1] 13477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 13487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer filename = None 13497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer edit = EditorWindow(root=root, filename=filename) 13507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer edit.set_close_hook(root.quit) 13517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer root.mainloop() 13527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer root.destroy() 13537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 13547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererif __name__ == '__main__': 13557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer test() 1356