EditorWindow.py revision 247327a27e622a344787464fea404dd73bc71c50
17aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport sys 27aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport os 37aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport re 47aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport imp 56634bf2919d855ccd821e878b8cc00c7209f1cbeGeorg Brandlfrom Tkinter import * 66634bf2919d855ccd821e878b8cc00c7209f1cbeGeorg Brandlimport tkSimpleDialog 76634bf2919d855ccd821e878b8cc00c7209f1cbeGeorg Brandlimport tkMessageBox 8fd182cd9d36adefba00d86542eb3134119cdc804Kurt B. Kaiserimport webbrowser 9d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xicluna 10d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xiclunafrom idlelib.MultiCall import MultiCallCreator 11d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xiclunafrom idlelib import idlever 12d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xiclunafrom idlelib import WindowList 13d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xiclunafrom idlelib import SearchDialog 14d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xiclunafrom idlelib import GrepDialog 15d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xiclunafrom idlelib import ReplaceDialog 16d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xiclunafrom idlelib import PyParse 17d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xiclunafrom idlelib.configHandler import idleConf 18d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xiclunafrom idlelib import aboutDialog, textView, configDialog 19d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xiclunafrom idlelib import macosxSupport 207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer# The default tab setting for a Text widget, in average-width characters. 227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David SchererTK_TABWIDTH_DEFAULT = 8 237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 24f13447f3f75c7b56eec6a602b0b72a48fbbc5486Kurt B. Kaiserdef _sphinx_version(): 25f13447f3f75c7b56eec6a602b0b72a48fbbc5486Kurt B. Kaiser "Format sys.version_info to produce the Sphinx version string used to install the chm docs" 26f13447f3f75c7b56eec6a602b0b72a48fbbc5486Kurt B. Kaiser major, minor, micro, level, serial = sys.version_info 27f13447f3f75c7b56eec6a602b0b72a48fbbc5486Kurt B. Kaiser release = '%s%s' % (major, minor) 28f13447f3f75c7b56eec6a602b0b72a48fbbc5486Kurt B. Kaiser if micro: 29fb23463139a173062031df9c258ac772b56ae08dBenjamin Peterson release += '%s' % (micro,) 30fb23463139a173062031df9c258ac772b56ae08dBenjamin Peterson if level == 'candidate': 31fb23463139a173062031df9c258ac772b56ae08dBenjamin Peterson release += 'rc%s' % (serial,) 32fb23463139a173062031df9c258ac772b56ae08dBenjamin Peterson elif level != 'final': 33f13447f3f75c7b56eec6a602b0b72a48fbbc5486Kurt B. Kaiser release += '%s%s' % (level[0], serial) 34f13447f3f75c7b56eec6a602b0b72a48fbbc5486Kurt B. Kaiser return release 35f13447f3f75c7b56eec6a602b0b72a48fbbc5486Kurt B. Kaiser 36220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiserdef _find_module(fullname, path=None): 37220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser """Version of imp.find_module() that handles hierarchical module names""" 38220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser 39220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser file = None 40220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser for tgt in fullname.split('.'): 41220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser if file is not None: 42220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser file.close() # close intermediate files 43220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser (file, filename, descr) = imp.find_module(tgt, path) 44220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser if descr[2] == imp.PY_SOURCE: 45220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser break # find but not load the source file 46220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser module = imp.load_module(tgt, file, filename, descr) 4769e8afcc9fcd8a41a1035893d60893d51fae62f1Kurt B. Kaiser try: 4869e8afcc9fcd8a41a1035893d60893d51fae62f1Kurt B. Kaiser path = module.__path__ 4969e8afcc9fcd8a41a1035893d60893d51fae62f1Kurt B. Kaiser except AttributeError: 5069e8afcc9fcd8a41a1035893d60893d51fae62f1Kurt B. Kaiser raise ImportError, 'No source for module ' + module.__name__ 51220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser return file, filename, descr 52220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser 53dcba6622f52efafa28104a07db9d5ba2b1a8d628Kurt B. Kaiserclass EditorWindow(object): 54d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xicluna from idlelib.Percolator import Percolator 55d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xicluna from idlelib.ColorDelegator import ColorDelegator 56d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xicluna from idlelib.UndoDelegator import UndoDelegator 57d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xicluna from idlelib.IOBinding import IOBinding, filesystemencoding, encoding 58d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xicluna from idlelib import Bindings 596634bf2919d855ccd821e878b8cc00c7209f1cbeGeorg Brandl from Tkinter import Toplevel 60d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xicluna from idlelib.MultiStatusBar import MultiStatusBar 617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 62114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser help_url = None 637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def __init__(self, flist=None, filename=None, key=None, root=None): 65114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser if EditorWindow.help_url is None: 6684ef153c74decf0b036042b5ca3f5cb3cd785eddThomas Heller dochome = os.path.join(sys.prefix, 'Doc', 'index.html') 67114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser if sys.platform.count('linux'): 68114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser # look for html docs in a couple of standard places 69114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser pyver = 'python-docs-' + '%s.%s.%s' % sys.version_info[:3] 70114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser if os.path.isdir('/var/www/html/python/'): # "python2" rpm 71114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser dochome = '/var/www/html/python/index.html' 72114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser else: 73114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser basepath = '/usr/share/doc/' # standard location 74114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser dochome = os.path.join(basepath, pyver, 75114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser 'Doc', 'index.html') 768aa23927e339ca13459dd408751546352d81fefaKurt B. Kaiser elif sys.platform[:3] == 'win': 77090e636add33907d196b9899eb0f019654a055e8Kurt B. Kaiser chmfile = os.path.join(sys.prefix, 'Doc', 78f13447f3f75c7b56eec6a602b0b72a48fbbc5486Kurt B. Kaiser 'Python%s.chm' % _sphinx_version()) 7984ef153c74decf0b036042b5ca3f5cb3cd785eddThomas Heller if os.path.isfile(chmfile): 8084ef153c74decf0b036042b5ca3f5cb3cd785eddThomas Heller dochome = chmfile 8119302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren elif macosxSupport.runningAsOSXApp(): 8219302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren # documentation is stored inside the python framework 8319302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren dochome = os.path.join(sys.prefix, 8419302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren 'Resources/English.lproj/Documentation/index.html') 85114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser dochome = os.path.normpath(dochome) 86114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser if os.path.isfile(dochome): 87114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser EditorWindow.help_url = dochome 8819302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren if sys.platform == 'darwin': 8919302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren # Safari requires real file:-URLs 9019302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren EditorWindow.help_url = 'file://' + EditorWindow.help_url 91114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser else: 927b4c2beda6b54c28070a04467e22e03f90b43450Raymond Hettinger EditorWindow.help_url = "http://docs.python.org/%d.%d" % sys.version_info[:2] 93dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava currentTheme=idleConf.CurrentTheme() 947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.flist = flist 957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer root = root or flist.root 967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.root = root 97b3c4d16e688d073dae92f272d66b6efa4b70a734Kurt B. Kaiser try: 98b3c4d16e688d073dae92f272d66b6efa4b70a734Kurt B. Kaiser sys.ps1 99b3c4d16e688d073dae92f272d66b6efa4b70a734Kurt B. Kaiser except AttributeError: 100b3c4d16e688d073dae92f272d66b6efa4b70a734Kurt B. Kaiser sys.ps1 = '>>> ' 1017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.menubar = Menu(root) 102183403a271977a26c0b77dbcf62e19395c007288Kurt B. Kaiser self.top = top = WindowList.ListedToplevel(root, menu=self.menubar) 1030c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava if flist: 104610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser self.tkinter_vars = flist.vars 105cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser #self.top.instance_dict makes flist.inversedict avalable to 1060c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava #configDialog.py so it can access all EditorWindow instaces 107a2946a437ee7886e6192b9e02725b8a04cdc80aeKurt B. Kaiser self.top.instance_dict = flist.inversedict 108610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser else: 109610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser self.tkinter_vars = {} # keys: Tkinter event names 110610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser # values: Tkinter variable instances 111a2946a437ee7886e6192b9e02725b8a04cdc80aeKurt B. Kaiser self.top.instance_dict = {} 112a2946a437ee7886e6192b9e02725b8a04cdc80aeKurt B. Kaiser self.recent_files_path = os.path.join(idleConf.GetUserCfgDir(), 1131d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava 'recent-files.lst') 1147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text_frame = text_frame = Frame(top) 1154ebbefe677f47a8e4f624737338f22e714a7e5bcMartin v. Löwis self.vbar = vbar = Scrollbar(text_frame, name='vbar') 1161061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser self.width = idleConf.GetOption('main','EditorWindow','width') 117ce46511957740aa9963b95db80c764b6c346fb1dKurt B. Kaiser text_options = { 118ce46511957740aa9963b95db80c764b6c346fb1dKurt B. Kaiser 'name': 'text', 119ce46511957740aa9963b95db80c764b6c346fb1dKurt B. Kaiser 'padx': 5, 120ce46511957740aa9963b95db80c764b6c346fb1dKurt B. Kaiser 'wrap': 'none', 121ce46511957740aa9963b95db80c764b6c346fb1dKurt B. Kaiser 'width': self.width, 122ce46511957740aa9963b95db80c764b6c346fb1dKurt B. Kaiser 'height': idleConf.GetOption('main', 'EditorWindow', 'height')} 123ce46511957740aa9963b95db80c764b6c346fb1dKurt B. Kaiser if TkVersion >= 8.5: 124ce46511957740aa9963b95db80c764b6c346fb1dKurt B. Kaiser # Starting with tk 8.5 we have to set the new tabstyle option 125ce46511957740aa9963b95db80c764b6c346fb1dKurt B. Kaiser # to 'wordprocessor' to achieve the same display of tabs as in 126ce46511957740aa9963b95db80c764b6c346fb1dKurt B. Kaiser # older tk versions. 127ce46511957740aa9963b95db80c764b6c346fb1dKurt B. Kaiser text_options['tabstyle'] = 'wordprocessor' 128ce46511957740aa9963b95db80c764b6c346fb1dKurt B. Kaiser self.text = text = MultiCallCreator(Text)(text_frame, **text_options) 129183403a271977a26c0b77dbcf62e19395c007288Kurt B. Kaiser self.top.focused_widget = self.text 1307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 1317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.createmenubar() 1327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.apply_bindings() 1337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 1347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.top.protocol("WM_DELETE_WINDOW", self.close) 1357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.top.bind("<<close-window>>", self.close_event) 13617db495445ba1f6c9d360ade62471d49ceb05cfeRonald Oussoren if macosxSupport.runningAsOSXApp(): 13717db495445ba1f6c9d360ade62471d49ceb05cfeRonald Oussoren # Command-W on editorwindows doesn't work without this. 1383075e16c516e3975b61e4356a6d64def9cc5110eRonald Oussoren text.bind('<<close-window>>', self.close_event) 1393f752ab22e369bd664bbce395099f263e3cff784R. David Murray # Some OS X systems have only one mouse button, 1403f752ab22e369bd664bbce395099f263e3cff784R. David Murray # so use control-click for pulldown menus there. 1413f752ab22e369bd664bbce395099f263e3cff784R. David Murray # (Note, AquaTk defines <2> as the right button if 1423f752ab22e369bd664bbce395099f263e3cff784R. David Murray # present and the Tk Text widget already binds <2>.) 1433f752ab22e369bd664bbce395099f263e3cff784R. David Murray text.bind("<Control-Button-1>",self.right_menu_event) 1443f752ab22e369bd664bbce395099f263e3cff784R. David Murray else: 1453f752ab22e369bd664bbce395099f263e3cff784R. David Murray # Elsewhere, use right-click for pulldown menus. 1463f752ab22e369bd664bbce395099f263e3cff784R. David Murray text.bind("<3>",self.right_menu_event) 14784f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser text.bind("<<cut>>", self.cut) 14884f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser text.bind("<<copy>>", self.copy) 14984f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser text.bind("<<paste>>", self.paste) 1507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<center-insert>>", self.center_insert_event) 1517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<help>>", self.help_dialog) 1527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<python-docs>>", self.python_docs) 1537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<about-idle>>", self.about_dialog) 1543b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gava text.bind("<<open-config-dialog>>", self.config_dialog) 1557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<open-module>>", self.open_module) 1567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<do-nothing>>", lambda event: "break") 1577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<select-all>>", self.select_all) 1587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<remove-selection>>", self.remove_selection) 159c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.bind("<<find>>", self.find_event) 160c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.bind("<<find-again>>", self.find_again_event) 161c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.bind("<<find-in-files>>", self.find_in_files_event) 162c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.bind("<<find-selection>>", self.find_selection_event) 163c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.bind("<<replace>>", self.replace_event) 164c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.bind("<<goto-line>>", self.goto_line_event) 165cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<smart-backspace>>",self.smart_backspace_event) 166cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<newline-and-indent>>",self.newline_and_indent_event) 167cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<smart-indent>>",self.smart_indent_event) 168cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<indent-region>>",self.indent_region_event) 169cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<dedent-region>>",self.dedent_region_event) 170cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<comment-region>>",self.comment_region_event) 171cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<uncomment-region>>",self.uncomment_region_event) 172cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<tabify-region>>",self.tabify_region_event) 173cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<untabify-region>>",self.untabify_region_event) 174cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<toggle-tabs>>",self.toggle_tabs_event) 175cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bind("<<change-indentwidth>>",self.change_indentwidth_event) 1765ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser text.bind("<Left>", self.move_at_edge_if_selection(0)) 1775ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser text.bind("<Right>", self.move_at_edge_if_selection(1)) 1783069dbb8ec9c287c2ff6b3a1c8bfde83af81c11bKurt B. Kaiser text.bind("<<del-word-left>>", self.del_word_left) 1793069dbb8ec9c287c2ff6b3a1c8bfde83af81c11bKurt B. Kaiser text.bind("<<del-word-right>>", self.del_word_right) 18093cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser text.bind("<<beginning-of-line>>", self.home_callback) 1816655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser 1827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if flist: 1837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer flist.inversedict[self] = key 1847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if key: 1857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer flist.dict[key] = self 186d2f4861a0b52a2af5ea3395267a5c56541352f8fKurt B. Kaiser text.bind("<<open-new-window>>", self.new_callback) 1877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<close-all-windows>>", self.flist.close_all_callback) 1887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<open-class-browser>>", self.open_class_browser) 1897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.bind("<<open-path-browser>>", self.open_path_browser) 1907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 191898a365c276951ab2471afe2e24bbc910666d361Steven M. Gava self.set_status_bar() 1927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer vbar['command'] = text.yview 1937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer vbar.pack(side=RIGHT, fill=Y) 1947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text['yscrollcommand'] = vbar.set 195acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser fontWeight = 'normal' 196acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser if idleConf.GetOption('main', 'EditorWindow', 'font-bold', type='bool'): 197b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava fontWeight='bold' 198acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser text.config(font=(idleConf.GetOption('main', 'EditorWindow', 'font'), 199acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser idleConf.GetOption('main', 'EditorWindow', 'font-size'), 200acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser fontWeight)) 2017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text_frame.pack(side=LEFT, fill=BOTH, expand=1) 2027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.pack(side=TOP, fill=BOTH, expand=1) 2037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.focus_set() 2047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 2056af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # usetabs true -> literal tab characters are used by indent and 2066af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # dedent cmds, possibly mixed with spaces if 2076af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # indentwidth is not a multiple of tabwidth, 2086af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # which will cause Tabnanny to nag! 2096af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # false -> tab characters are converted to spaces by indent 2106af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # and dedent cmds, and ditto TAB keystrokes 211acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser # Although use-spaces=0 can be configured manually in config-main.def, 212acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser # configuration of tabs v. spaces is not supported in the configuration 213acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser # dialog. IDLE promotes the preferred Python indentation: use spaces! 214acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser usespaces = idleConf.GetOption('main', 'Indent', 'use-spaces', type='bool') 215acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser self.usetabs = not usespaces 2166af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser 2176af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # tabwidth is the display width of a literal tab character. 2186af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # CAUTION: telling Tk to use anything other than its default 2196af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # tab setting causes it to use an entirely different tabbing algorithm, 2206af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # treating tab stops as fixed distances from the left margin. 2216af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # Nobody expects this, so for now tabwidth should never be changed. 222acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser self.tabwidth = 8 # must remain 8 until Tk is fixed. 223acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser 224acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser # indentwidth is the number of screen characters per indent level. 225acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser # The recommended Python indentation is four spaces. 226acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser self.indentwidth = self.tabwidth 227acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser self.set_notabs_indentwidth() 2286af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser 2296af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # If context_use_ps1 is true, parsing searches back for a ps1 line; 2306af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # else searches for a popular (if, def, ...) Python stmt. 2316af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser self.context_use_ps1 = False 2326af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser 2336af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # When searching backwards for a reliable place to begin parsing, 2346af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # first start num_context_lines[0] lines back, then 2356af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # num_context_lines[1] lines back if that didn't work, and so on. 2366af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # The last value should be huge (larger than the # of lines in a 2376af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # conceivable file). 2386af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # Making the initial values larger slows things down more often. 2396af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser self.num_context_lines = 50, 500, 5000000 2406af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser 2417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.per = per = self.Percolator(text) 242dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser 243dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser self.undo = undo = self.UndoDelegator() 244dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser per.insertfilter(undo) 245dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser text.undo_block_start = undo.undo_block_start 246dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser text.undo_block_stop = undo.undo_block_stop 247dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser undo.set_saved_change_hook(self.saved_change_hook) 248dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser 249dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser # IOBinding implements file I/O and printing functionality 2507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.io = io = self.IOBinding(self) 251dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser io.set_filename_change_hook(self.filename_change_hook) 252dc1e70987f49aa23bf1d07f32c476edeba0cec30Kurt B. Kaiser 253cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser # Create the recent files submenu 254cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser self.recent_files_menu = Menu(self.menubar) 255cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser self.menudict['file'].insert_cascade(3, label='Recent Files', 256cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser underline=0, 257cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser menu=self.recent_files_menu) 258cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser self.update_recent_files_list() 2597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 260f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser self.color = None # initialized below in self.ResetColorizer 2617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if filename: 262d2f4861a0b52a2af5ea3395267a5c56541352f8fKurt B. Kaiser if os.path.exists(filename) and not os.path.isdir(filename): 2637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer io.loadfile(filename) 2647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 2657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer io.set_filename(filename) 266f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser self.ResetColorizer() 2677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.saved_change_hook() 2687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 2696af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser self.set_indentation_params(self.ispythonsource(filename)) 2706af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser 2717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.load_extensions() 2727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 2737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu = self.menudict.get('windows') 2747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if menu: 2757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer end = menu.index("end") 2767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if end is None: 2777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer end = -1 2787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if end >= 0: 2797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu.add_separator() 2807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer end = end + 1 2817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.wmenu_end = end 2827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer WindowList.register_callback(self.postwindowsmenu) 2837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 2847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Some abstractions so IDLE extensions are cross-IDE 2857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.askyesno = tkMessageBox.askyesno 2867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.askinteger = tkSimpleDialog.askinteger 2877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.showerror = tkMessageBox.showerror 2887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 289307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis def _filename_to_unicode(self, filename): 290307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis """convert filename to unicode in order to display it in Tk""" 291307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis if isinstance(filename, unicode) or not filename: 292307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis return filename 293307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis else: 294307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis try: 295307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis return filename.decode(self.filesystemencoding) 296307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis except UnicodeDecodeError: 297307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis # XXX 298307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis try: 299307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis return filename.decode(self.encoding) 300307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis except UnicodeDecodeError: 301307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis # byte-to-byte conversion 302307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis return filename.decode('iso8859-1') 303307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis 304d2f4861a0b52a2af5ea3395267a5c56541352f8fKurt B. Kaiser def new_callback(self, event): 305d2f4861a0b52a2af5ea3395267a5c56541352f8fKurt B. Kaiser dirname, basename = self.io.defaultfilename() 306d2f4861a0b52a2af5ea3395267a5c56541352f8fKurt B. Kaiser self.flist.new(dirname) 307d2f4861a0b52a2af5ea3395267a5c56541352f8fKurt B. Kaiser return "break" 308d2f4861a0b52a2af5ea3395267a5c56541352f8fKurt B. Kaiser 30993cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser def home_callback(self, event): 31093cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser if (event.state & 12) != 0 and event.keysym == "Home": 31193cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser # state&1==shift, state&4==control, state&8==alt 31293cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser return # <Modifier-Home>; fall back to class binding 31393cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser 31493cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser if self.text.index("iomark") and \ 31593cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser self.text.compare("iomark", "<=", "insert lineend") and \ 31693cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser self.text.compare("insert linestart", "<=", "iomark"): 31793cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser insertpt = int(self.text.index("iomark").split(".")[1]) 31893cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser else: 31993cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser line = self.text.get("insert linestart", "insert lineend") 32093cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser for insertpt in xrange(len(line)): 32193cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser if line[insertpt] not in (' ','\t'): 32293cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser break 32393cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser else: 32493cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser insertpt=len(line) 32593cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser 32693cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser lineat = int(self.text.index("insert").split('.')[1]) 32793cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser 32893cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser if insertpt == lineat: 32993cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser insertpt = 0 33093cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser 33193cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser dest = "insert linestart+"+str(insertpt)+"c" 33293cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser 33393cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser if (event.state&1) == 0: 33493cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser # shift not pressed 33593cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser self.text.tag_remove("sel", "1.0", "end") 33693cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser else: 33793cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser if not self.text.index("sel.first"): 33893cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser self.text.mark_set("anchor","insert") 33993cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser 34093cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser first = self.text.index(dest) 34193cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser last = self.text.index("anchor") 34293cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser 34393cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser if self.text.compare(first,">",last): 34493cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser first,last = last,first 34593cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser 34693cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser self.text.tag_remove("sel", "1.0", "end") 34793cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser self.text.tag_add("sel", first, last) 34893cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser 34993cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser self.text.mark_set("insert", dest) 35093cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser self.text.see("insert") 35193cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser return "break" 35293cdae5f814292da17c38374d0cfa314b96fd3beKurt B. Kaiser 3537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def set_status_bar(self): 354898a365c276951ab2471afe2e24bbc910666d361Steven M. Gava self.status_bar = self.MultiStatusBar(self.top) 35519302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren if macosxSupport.runningAsOSXApp(): 35619302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren # Insert some padding to avoid obscuring some of the statusbar 35719302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren # by the resize widget. 35819302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren self.status_bar.set_label('_padding1', ' ', side=RIGHT) 3597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.status_bar.set_label('column', 'Col: ?', side=RIGHT) 3607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.status_bar.set_label('line', 'Ln: ?', side=RIGHT) 3617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.status_bar.pack(side=BOTTOM, fill=X) 362b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser self.text.bind("<<set-line-and-column>>", self.set_line_and_column) 363b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser self.text.event_add("<<set-line-and-column>>", 364b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser "<KeyRelease>", "<ButtonRelease>") 3657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.after_idle(self.set_line_and_column) 3667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 3677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def set_line_and_column(self, event=None): 368220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser line, column = self.text.index(INSERT).split('.') 3697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.status_bar.set_label('column', 'Col: %s' % column) 3707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.status_bar.set_label('line', 'Ln: %s' % line) 3717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 3727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu_specs = [ 3737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ("file", "_File"), 3747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ("edit", "_Edit"), 3757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ("format", "F_ormat"), 3767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ("run", "_Run"), 3771061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser ("options", "_Options"), 3787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ("windows", "_Windows"), 3797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ("help", "_Help"), 3807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ] 3817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 38219302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren if macosxSupport.runningAsOSXApp(): 38319302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren del menu_specs[-3] 38419302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren menu_specs[-2] = ("windows", "_Window") 38519302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren 38619302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren 3877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def createmenubar(self): 3887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer mbar = self.menubar 3897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.menudict = menudict = {} 3907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer for name, label in self.menu_specs: 3917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer underline, label = prepstr(label) 3927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menudict[name] = menu = Menu(mbar, name=name) 3937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer mbar.add_cascade(label=label, menu=menu, underline=underline) 39419302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren 395a97063a1086266e774586765b3c3e65ed2a4a1ebRonald Oussoren if macosxSupport.runningAsOSXApp(): 39619302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren # Insert the application menu 39719302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren menudict['application'] = menu = Menu(mbar, name='apple') 39819302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren mbar.add_cascade(label='IDLE', menu=menu) 39919302d927e6688e02553df16177e4867e2d0e3b3Ronald Oussoren 4007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.fill_menus() 4018e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser self.base_helpmenu_length = self.menudict['help'].index(END) 4028e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser self.reset_help_menu_entries() 4037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 4047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def postwindowsmenu(self): 4057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Only called when Windows menu exists 4067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu = self.menudict['windows'] 4077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer end = menu.index("end") 4087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if end is None: 4097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer end = -1 4107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if end > self.wmenu_end: 4117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu.delete(self.wmenu_end+1, end) 4127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer WindowList.add_windows_to_menu(menu) 4137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 4147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer rmenu = None 4157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 4167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def right_menu_event(self, event): 4177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.tag_remove("sel", "1.0", "end") 4187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.mark_set("insert", "@%d,%d" % (event.x, event.y)) 4197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not self.rmenu: 4207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.make_rmenu() 4217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer rmenu = self.rmenu 4227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.event = event 4237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer iswin = sys.platform[:3] == 'win' 4247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if iswin: 4257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.config(cursor="arrow") 4267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer rmenu.tk_popup(event.x_root, event.y_root) 4277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if iswin: 4287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.config(cursor="ibeam") 4297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 4307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer rmenu_specs = [ 4317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # ("Label", "<<virtual-event>>"), ... 4327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ("Close", "<<close-window>>"), # Example 4337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ] 4347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 4357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def make_rmenu(self): 4367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer rmenu = Menu(self.text, tearoff=0) 4377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer for label, eventname in self.rmenu_specs: 4387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def command(text=self.text, eventname=eventname): 4397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.event_generate(eventname) 4407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer rmenu.add_command(label=label, command=command) 4417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.rmenu = rmenu 4427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 4437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def about_dialog(self, event=None): 444d78b23025c9c9f6288e14112411d83f44bcf85a8Kurt B. Kaiser aboutDialog.AboutDialog(self.top,'About IDLE') 4456655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser 4463b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gava def config_dialog(self, event=None): 4473b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gava configDialog.ConfigDialog(self.top,'Settings') 4486655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser 4497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def help_dialog(self, event=None): 450b9d07b5a8b8b70268ffa520895e7843ab594a486Steven M. Gava fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'help.txt') 451d5f4910afdd95d86f51ed53a932a4c2fd181bd43Kurt B. Kaiser textView.view_file(self.top,'Help',fn) 4526655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser 453114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser def python_docs(self, event=None): 4548aa23927e339ca13459dd408751546352d81fefaKurt B. Kaiser if sys.platform[:3] == 'win': 455247327a27e622a344787464fea404dd73bc71c50Terry Reedy try: 456247327a27e622a344787464fea404dd73bc71c50Terry Reedy os.startfile(self.help_url) 457247327a27e622a344787464fea404dd73bc71c50Terry Reedy except WindowsError as why: 458247327a27e622a344787464fea404dd73bc71c50Terry Reedy tkMessageBox.showerror(title='Document Start Failure', 459247327a27e622a344787464fea404dd73bc71c50Terry Reedy message=str(why), parent=self.text) 460114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser else: 461114713d19451e893dc7dabea9b96d396baf7ecafKurt B. Kaiser webbrowser.open(self.help_url) 4628aa23927e339ca13459dd408751546352d81fefaKurt B. Kaiser return "break" 4637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 46484f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser def cut(self,event): 46584f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser self.text.event_generate("<<Cut>>") 46684f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser return "break" 46784f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser 46884f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser def copy(self,event): 469b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser if not self.text.tag_ranges("sel"): 470b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser # There is no selection, so do nothing and maybe interrupt. 471b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser return 47284f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser self.text.event_generate("<<Copy>>") 47384f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser return "break" 47484f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser 47584f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser def paste(self,event): 47684f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser self.text.event_generate("<<Paste>>") 477631fee62351397e940e4616ef48f03788962c3ebKurt B. Kaiser self.text.see("insert") 47884f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser return "break" 47984f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser 4807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def select_all(self, event=None): 4817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.tag_add("sel", "1.0", "end-1c") 4827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.mark_set("insert", "1.0") 4837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.see("insert") 4847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return "break" 4857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 4867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def remove_selection(self, event=None): 4877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.tag_remove("sel", "1.0", "end") 4887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.see("insert") 4897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 4905ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser def move_at_edge_if_selection(self, edge_index): 4915ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser """Cursor move begins at start or end of selection 4925ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser 4935ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser When a left/right cursor key is pressed create and return to Tkinter a 4945ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser function which causes a cursor move from the associated edge of the 4955ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser selection. 4965ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser 4975ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser """ 4985ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser self_text_index = self.text.index 4995ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser self_text_mark_set = self.text.mark_set 5005ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser edges_table = ("sel.first+1c", "sel.last-1c") 5015ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser def move_at_edge(event): 5025ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser if (event.state & 5) == 0: # no shift(==1) or control(==4) pressed 5035ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser try: 5045ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser self_text_index("sel.first") 5055ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser self_text_mark_set("insert", edges_table[edge_index]) 5065ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser except TclError: 5075ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser pass 5085ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser return move_at_edge 5095ec186b1cbf06cf66262882fb5b6f54a893e48a5Kurt B. Kaiser 5103069dbb8ec9c287c2ff6b3a1c8bfde83af81c11bKurt B. Kaiser def del_word_left(self, event): 5113069dbb8ec9c287c2ff6b3a1c8bfde83af81c11bKurt B. Kaiser self.text.event_generate('<Meta-Delete>') 5123069dbb8ec9c287c2ff6b3a1c8bfde83af81c11bKurt B. Kaiser return "break" 5133069dbb8ec9c287c2ff6b3a1c8bfde83af81c11bKurt B. Kaiser 5143069dbb8ec9c287c2ff6b3a1c8bfde83af81c11bKurt B. Kaiser def del_word_right(self, event): 5153069dbb8ec9c287c2ff6b3a1c8bfde83af81c11bKurt B. Kaiser self.text.event_generate('<Meta-d>') 5163069dbb8ec9c287c2ff6b3a1c8bfde83af81c11bKurt B. Kaiser return "break" 5173069dbb8ec9c287c2ff6b3a1c8bfde83af81c11bKurt B. Kaiser 518c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava def find_event(self, event): 519c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava SearchDialog.find(self.text) 520c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava return "break" 521c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava 522c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava def find_again_event(self, event): 523c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava SearchDialog.find_again(self.text) 524c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava return "break" 525c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava 526c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava def find_selection_event(self, event): 527c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava SearchDialog.find_selection(self.text) 528c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava return "break" 529c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava 530c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava def find_in_files_event(self, event): 531c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava GrepDialog.grep(self.text, self.io, self.flist) 532c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava return "break" 533c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava 534c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava def replace_event(self, event): 535c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava ReplaceDialog.replace(self.text) 536c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava return "break" 537c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava 538c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava def goto_line_event(self, event): 539c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text = self.text 540c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava lineno = tkSimpleDialog.askinteger("Goto", 541c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava "Go to line number:",parent=text) 542c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava if lineno is None: 543c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava return "break" 544c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava if lineno <= 0: 545c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.bell() 546c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava return "break" 547c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.mark_set("insert", "%d.0" % lineno) 548c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava text.see("insert") 549c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava 5507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def open_module(self, event=None): 5517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # XXX Shouldn't this be in IOBinding or in FileList? 5527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer try: 5537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer name = self.text.get("sel.first", "sel.last") 5547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer except TclError: 5557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer name = "" 5567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 557220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser name = name.strip() 558852f35bbeb23d898fb0d16489effb1197ee3fe02Guido van Rossum name = tkSimpleDialog.askstring("Module", 559852f35bbeb23d898fb0d16489effb1197ee3fe02Guido van Rossum "Enter the name of a Python module\n" 560852f35bbeb23d898fb0d16489effb1197ee3fe02Guido van Rossum "to search on sys.path and open:", 561852f35bbeb23d898fb0d16489effb1197ee3fe02Guido van Rossum parent=self.text, initialvalue=name) 562852f35bbeb23d898fb0d16489effb1197ee3fe02Guido van Rossum if name: 563852f35bbeb23d898fb0d16489effb1197ee3fe02Guido van Rossum name = name.strip() 5647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not name: 565852f35bbeb23d898fb0d16489effb1197ee3fe02Guido van Rossum return 5667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # XXX Ought to insert current file's directory in front of path 5677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer try: 568220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser (f, file, (suffix, mode, type)) = _find_module(name) 5697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer except (NameError, ImportError), msg: 5707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tkMessageBox.showerror("Import error", str(msg), parent=self.text) 5717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return 5727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if type != imp.PY_SOURCE: 5737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tkMessageBox.showerror("Unsupported type", 5747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer "%s is not a source module" % name, parent=self.text) 5757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return 5767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if f: 5777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer f.close() 5787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.flist: 5797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.flist.open(file) 5807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 5817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.io.loadfile(file) 5827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 5837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def open_class_browser(self, event=None): 5847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer filename = self.io.filename 5857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not filename: 5867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tkMessageBox.showerror( 5877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer "No filename", 5887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer "This buffer has no associated filename", 5897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer master=self.text) 5907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.focus_set() 5917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return None 5927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer head, tail = os.path.split(filename) 5937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer base, ext = os.path.splitext(tail) 594d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xicluna from idlelib import ClassBrowser 5957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ClassBrowser.ClassBrowser(self.flist, base, [head]) 5967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 5977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def open_path_browser(self, event=None): 598d630c04ab1ab35e2ec6eeeaba9bdcb9f8e730e78Florent Xicluna from idlelib import PathBrowser 5997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer PathBrowser.PathBrowser(self.flist) 6007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def gotoline(self, lineno): 6027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if lineno is not None and lineno > 0: 6037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.mark_set("insert", "%d.0" % lineno) 6047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.tag_remove("sel", "1.0", "end") 6057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.tag_add("sel", "insert", "insert +1l") 6067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.center() 6077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def ispythonsource(self, filename): 609df506ea98b1c9424634c6063e90a664ac9127164Kurt B. Kaiser if not filename or os.path.isdir(filename): 610220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser return True 6117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer base, ext = os.path.splitext(os.path.basename(filename)) 6127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if os.path.normcase(ext) in (".py", ".pyw"): 613220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser return True 6147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer try: 6157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer f = open(filename) 6167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer line = f.readline() 6177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer f.close() 6187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer except IOError: 619220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser return False 62083a3560527f9e62bce6adbc12b8ff6b57be8b1acKurt B. Kaiser return line.startswith('#!') and line.find('python') >= 0 6217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def close_hook(self): 6237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.flist: 6240b634efcbcd10d9364796e9b048f18cd4a08b88bKurt B. Kaiser self.flist.unregister_maybe_terminate(self) 6250b634efcbcd10d9364796e9b048f18cd4a08b88bKurt B. Kaiser self.flist = None 6267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def set_close_hook(self, close_hook): 6287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.close_hook = close_hook 6297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 6307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def filename_change_hook(self): 6317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.flist: 6327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.flist.filename_changed_edit(self) 6337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.saved_change_hook() 634260cb9034c861fa159f26fba8679ac265af47109Kurt B. Kaiser self.top.update_windowlist_registry(self) 635f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser self.ResetColorizer() 6367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 637f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser def _addcolorizer(self): 6387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.color: 6397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return 640f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser if self.ispythonsource(self.io.filename): 641f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser self.color = self.ColorDelegator() 642f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser # can add more colorizers here... 643f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser if self.color: 644f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser self.per.removefilter(self.undo) 645f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser self.per.insertfilter(self.color) 646f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser self.per.insertfilter(self.undo) 6477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 648f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser def _rmcolorizer(self): 6497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not self.color: 6507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return 651df506ea98b1c9424634c6063e90a664ac9127164Kurt B. Kaiser self.color.removecolors() 6527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.per.removefilter(self.color) 6537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.color = None 6546655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser 655b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava def ResetColorizer(self): 656f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser "Update the colour theme" 657f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser # Called from self.filename_change_hook and from configDialog.py 658f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser self._rmcolorizer() 659f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser self._addcolorizer() 66073360a3e61274ffcc4c9fc3d09746bd6603e92a5Kurt B. Kaiser theme = idleConf.GetOption('main','Theme','name') 661f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser normal_colors = idleConf.GetHighlight(theme, 'normal') 662f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser cursor_color = idleConf.GetHighlight(theme, 'cursor', fgBg='fg') 663f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser select_colors = idleConf.GetHighlight(theme, 'hilite') 664f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser self.text.config( 665f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser foreground=normal_colors['foreground'], 666f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser background=normal_colors['background'], 667f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser insertbackground=cursor_color, 668f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser selectforeground=select_colors['foreground'], 669f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser selectbackground=select_colors['background'], 670f05fa33a6c42bc21ffdfe7a20226a2b9a83ac3c2Kurt B. Kaiser ) 6717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 672b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava def ResetFont(self): 6736655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser "Update the text widgets' font if it is changed" 67483118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser # Called from configDialog.py 675b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava fontWeight='normal' 676b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava if idleConf.GetOption('main','EditorWindow','font-bold',type='bool'): 677b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava fontWeight='bold' 678b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava self.text.config(font=(idleConf.GetOption('main','EditorWindow','font'), 679b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava idleConf.GetOption('main','EditorWindow','font-size'), 680b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava fontWeight)) 681b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava 682b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser def RemoveKeybindings(self): 683b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser "Remove the keybindings before they are changed." 68483118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser # Called from configDialog.py 6855a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser self.Bindings.default_keydefs = keydefs = idleConf.GetCurrentKeySet() 686dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava for event, keylist in keydefs.items(): 687b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser self.text.event_delete(event, *keylist) 688b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser for extensionName in self.get_standard_extension_names(): 6895a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser xkeydefs = idleConf.GetExtensionBindings(extensionName) 6905a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser if xkeydefs: 6915a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser for event, keylist in xkeydefs.items(): 692b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser self.text.event_delete(event, *keylist) 693b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser 694b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser def ApplyKeybindings(self): 695b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser "Update the keybindings after they are changed" 696b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser # Called from configDialog.py 6975a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser self.Bindings.default_keydefs = keydefs = idleConf.GetCurrentKeySet() 698dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava self.apply_bindings() 699b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser for extensionName in self.get_standard_extension_names(): 7005a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser xkeydefs = idleConf.GetExtensionBindings(extensionName) 7015a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser if xkeydefs: 7025a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser self.apply_bindings(xkeydefs) 703dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava #update menu accelerators 7045a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser menuEventDict = {} 705dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava for menu in self.Bindings.menudefs: 7065a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser menuEventDict[menu[0]] = {} 707dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava for item in menu[1]: 708dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava if item: 7095a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser menuEventDict[menu[0]][prepstr(item[0])[1]] = item[1] 710dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava for menubarItem in self.menudict.keys(): 7115a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser menu = self.menudict[menubarItem] 7125a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser end = menu.index(END) + 1 7135a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser for index in range(0, end): 7145a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser if menu.type(index) == 'command': 7155a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser accel = menu.entrycget(index, 'accelerator') 716dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava if accel: 7175a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser itemName = menu.entrycget(index, 'label') 7185a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser event = '' 7196e3dbbdf39f3b4eb6f18c0165e446df17218b7dcBenjamin Peterson if menubarItem in menuEventDict: 7206e3dbbdf39f3b4eb6f18c0165e446df17218b7dcBenjamin Peterson if itemName in menuEventDict[menubarItem]: 7215a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser event = menuEventDict[menubarItem][itemName] 722dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava if event: 7235a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser accel = get_accelerator(keydefs, event) 7245a67f9b815fdd34617395c6ec5d9a679361b76eaKurt B. Kaiser menu.entryconfig(index, accelerator=accel) 725dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava 726acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser def set_notabs_indentwidth(self): 727acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser "Update the indentwidth if changed and not using tabs in this window" 728acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser # Called from configDialog.py 729acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser if not self.usetabs: 730acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser self.indentwidth = idleConf.GetOption('main', 'Indent','num-spaces', 731acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser type='int') 732acdef858a51f32d2b2c82f3d47025cb26c2a63eeKurt B. Kaiser 7338e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser def reset_help_menu_entries(self): 7348e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser "Update the additional help entries on the Help menu" 7358e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser help_list = idleConf.GetAllExtraHelpSourcesList() 7368e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser helpmenu = self.menudict['help'] 7378e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser # first delete the extra help entries, if any 7388e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser helpmenu_length = helpmenu.index(END) 7398e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser if helpmenu_length > self.base_helpmenu_length: 7408e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser helpmenu.delete((self.base_helpmenu_length + 1), helpmenu_length) 7418e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser # then rebuild them 7428e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser if help_list: 7438e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser helpmenu.add_separator() 7448e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser for entry in help_list: 7458e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser cmd = self.__extra_help_callback(entry[1]) 7468e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser helpmenu.add_command(label=entry[0], command=cmd) 7478e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser # and update the menu dictionary 7488e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser self.menudict['help'] = helpmenu 7498e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser 7508e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser def __extra_help_callback(self, helpfile): 7518e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser "Create a callback with the helpfile value frozen at definition time" 7528e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser def display_extra_help(helpfile=helpfile): 753b2afe855e5d75a570707d6bf0e32206e4b7b1c4dGeorg Brandl if not helpfile.startswith(('www', 'http')): 754247327a27e622a344787464fea404dd73bc71c50Terry Reedy helpfile = os.path.normpath(helpfile) 7558aa23927e339ca13459dd408751546352d81fefaKurt B. Kaiser if sys.platform[:3] == 'win': 756247327a27e622a344787464fea404dd73bc71c50Terry Reedy try: 757247327a27e622a344787464fea404dd73bc71c50Terry Reedy os.startfile(helpfile) 758247327a27e622a344787464fea404dd73bc71c50Terry Reedy except WindowsError as why: 759247327a27e622a344787464fea404dd73bc71c50Terry Reedy tkMessageBox.showerror(title='Document Start Failure', 760247327a27e622a344787464fea404dd73bc71c50Terry Reedy message=str(why), parent=self.text) 7618aa23927e339ca13459dd408751546352d81fefaKurt B. Kaiser else: 7628aa23927e339ca13459dd408751546352d81fefaKurt B. Kaiser webbrowser.open(helpfile) 7638e92bf7699ac3617d3a0a9a55a38f642f5a6ecc6Kurt B. Kaiser return display_extra_help 7646655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser 765cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser def update_recent_files_list(self, new_file=None): 766cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser "Load and update the recent files list and menus" 767cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser rf_list = [] 768cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser if os.path.exists(self.recent_files_path): 769cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser rf_list_file = open(self.recent_files_path,'r') 7701d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava try: 771cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser rf_list = rf_list_file.readlines() 7721d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava finally: 773cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser rf_list_file.close() 774cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser if new_file: 775cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser new_file = os.path.abspath(new_file) + '\n' 776cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser if new_file in rf_list: 777cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser rf_list.remove(new_file) # move to top 778cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser rf_list.insert(0, new_file) 779cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser # clean and save the recent files list 780cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser bad_paths = [] 781cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser for path in rf_list: 782cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser if '\0' in path or not os.path.exists(path[0:-1]): 783cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser bad_paths.append(path) 784cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser rf_list = [path for path in rf_list if path not in bad_paths] 785cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser ulchars = "1234567890ABCDEFGHIJK" 786cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser rf_list = rf_list[0:len(ulchars)] 787cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser rf_file = open(self.recent_files_path, 'w') 7881d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava try: 789cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser rf_file.writelines(rf_list) 7901d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava finally: 791cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser rf_file.close() 792cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser # for each edit window instance, construct the recent files menu 793cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser for instance in self.top.instance_dict.keys(): 794cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser menu = instance.recent_files_menu 795cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser menu.delete(1, END) # clear, and rebuild: 79686b882f3a6978cf359dfedcf1193bd930f024780Guilherme Polo for i, file_name in enumerate(rf_list): 79786b882f3a6978cf359dfedcf1193bd930f024780Guilherme Polo file_name = file_name.rstrip() # zap \n 798307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis # make unicode string to display non-ASCII chars correctly 799307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis ufile_name = self._filename_to_unicode(file_name) 800cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser callback = instance.__recent_file_callback(file_name) 801307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis menu.add_command(label=ulchars[i] + " " + ufile_name, 802cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser command=callback, 803cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser underline=0) 804cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser 805cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser def __recent_file_callback(self, file_name): 806cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser def open_recent_file(fn_closure=file_name): 807cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser self.io.open(editFile=fn_closure) 808cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser return open_recent_file 8096655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser 8107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def saved_change_hook(self): 8117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer short = self.short_title() 8127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer long = self.long_title() 8137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if short and long: 8147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer title = short + " - " + long 8157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer elif short: 8167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer title = short 8177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer elif long: 8187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer title = long 8197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 8207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer title = "Untitled" 8217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer icon = short or long or title 8227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not self.get_saved(): 8237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer title = "*%s*" % title 8247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer icon = "*%s" % icon 8257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.top.wm_title(title) 8267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.top.wm_iconname(icon) 8277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def get_saved(self): 8297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return self.undo.get_saved() 8307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def set_saved(self, flag): 8327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.undo.set_saved(flag) 8337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def reset_undo(self): 8357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.undo.reset_undo() 8367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def short_title(self): 8387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer filename = self.io.filename 8397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if filename: 8407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer filename = os.path.basename(filename) 841307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis # return unicode string to display non-ASCII chars correctly 842307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis return self._filename_to_unicode(filename) 8437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def long_title(self): 845307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis # return unicode string to display non-ASCII chars correctly 846307021f40b227d2bf114b536c37cc41e03fc2affMartin v. Löwis return self._filename_to_unicode(self.io.filename or "") 8477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def center_insert_event(self, event): 8497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.center() 8507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def center(self, mark="insert"): 8527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text = self.text 8537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer top, bot = self.getwindowlines() 8547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer lineno = self.getlineno(mark) 8557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer height = bot - top 856220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser newtop = max(1, lineno - height//2) 8577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.yview(float(newtop)) 8587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def getwindowlines(self): 8607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text = self.text 8617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer top = self.getlineno("@0,0") 8627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer bot = self.getlineno("@0,65535") 8637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if top == bot and text.winfo_height() == 1: 8647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Geometry manager hasn't run yet 8657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer height = int(text['height']) 8667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer bot = top + height - 1 8677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return top, bot 8687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def getlineno(self, mark="insert"): 8707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text = self.text 8717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return int(float(text.index(mark))) 8727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8731061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser def get_geometry(self): 8741061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser "Return (width, height, x, y)" 8751061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser geom = self.top.wm_geometry() 8761061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser m = re.match(r"(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geom) 8771061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser tuple = (map(int, m.groups())) 8781061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser return tuple 8791061e7270b13a0e632c5a28791a46e38b48a39a0Kurt B. Kaiser 8807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def close_event(self, event): 8817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.close() 8827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def maybesave(self): 8847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.io: 88567716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava if not self.get_saved(): 8866655e4bc2752f1114a2e1f9a63ffd4191fa50d0dKurt B. Kaiser if self.top.state()!='normal': 88767716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava self.top.deiconify() 88867716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava self.top.lower() 88967716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava self.top.lift() 8907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return self.io.maybesave() 8917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def close(self): 8937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer reply = self.maybesave() 894a398e2d0592464b6594bac0e4ee3ef091cce5159Matthias Klose if str(reply) != "cancel": 8957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self._close() 8967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return reply 8977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 8987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def _close(self): 8991d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava if self.io.filename: 900cf6f1b69eb5f491dd3cba6c5c90bcb344d4b3a96Kurt B. Kaiser self.update_recent_files_list(new_file=self.io.filename) 9017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer WindowList.unregister_callback(self.postwindowsmenu) 9027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.unload_extensions() 9030b634efcbcd10d9364796e9b048f18cd4a08b88bKurt B. Kaiser self.io.close() 9040b634efcbcd10d9364796e9b048f18cd4a08b88bKurt B. Kaiser self.io = None 9050b634efcbcd10d9364796e9b048f18cd4a08b88bKurt B. Kaiser self.undo = None 9067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.color: 9070b634efcbcd10d9364796e9b048f18cd4a08b88bKurt B. Kaiser self.color.close(False) 9080b634efcbcd10d9364796e9b048f18cd4a08b88bKurt B. Kaiser self.color = None 9097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text = None 910610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser self.tkinter_vars = None 9110b634efcbcd10d9364796e9b048f18cd4a08b88bKurt B. Kaiser self.per.close() 9120b634efcbcd10d9364796e9b048f18cd4a08b88bKurt B. Kaiser self.per = None 9130b634efcbcd10d9364796e9b048f18cd4a08b88bKurt B. Kaiser self.top.destroy() 9140b634efcbcd10d9364796e9b048f18cd4a08b88bKurt B. Kaiser if self.close_hook: 9150b634efcbcd10d9364796e9b048f18cd4a08b88bKurt B. Kaiser # unless override: unregister from flist, terminate if last window 9160b634efcbcd10d9364796e9b048f18cd4a08b88bKurt B. Kaiser self.close_hook() 9177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 9187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def load_extensions(self): 9197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.extensions = {} 9207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.load_standard_extensions() 9217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 9227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def unload_extensions(self): 9237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer for ins in self.extensions.values(): 9247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if hasattr(ins, "close"): 9257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ins.close() 9267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.extensions = {} 9277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 9287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def load_standard_extensions(self): 9297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer for name in self.get_standard_extension_names(): 9307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer try: 9317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.load_extension(name) 9327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer except: 93370a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald print "Failed to load extension", repr(name) 9347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer import traceback 9357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer traceback.print_exc() 9367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 9377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def get_standard_extension_names(self): 9384d5bc6031ca883201f87e0e3c94e5746f9f91439Kurt B. Kaiser return idleConf.GetExtensions(editor_only=True) 9397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 9407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def load_extension(self, name): 941b00e89faab0d69feb040118bbc5ea6149e91867fKurt B. Kaiser try: 942b00e89faab0d69feb040118bbc5ea6149e91867fKurt B. Kaiser mod = __import__(name, globals(), locals(), []) 943b00e89faab0d69feb040118bbc5ea6149e91867fKurt B. Kaiser except ImportError: 944b00e89faab0d69feb040118bbc5ea6149e91867fKurt B. Kaiser print "\nFailed to import extension: ", name 945b00e89faab0d69feb040118bbc5ea6149e91867fKurt B. Kaiser return 9467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer cls = getattr(mod, name) 9474d5bc6031ca883201f87e0e3c94e5746f9f91439Kurt B. Kaiser keydefs = idleConf.GetExtensionBindings(name) 9484d5bc6031ca883201f87e0e3c94e5746f9f91439Kurt B. Kaiser if hasattr(cls, "menudefs"): 9494d5bc6031ca883201f87e0e3c94e5746f9f91439Kurt B. Kaiser self.fill_menus(cls.menudefs, keydefs) 9507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer ins = cls(self) 9517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.extensions[name] = ins 9527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if keydefs: 9537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.apply_bindings(keydefs) 9547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer for vevent in keydefs.keys(): 955220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser methodname = vevent.replace("-", "_") 9567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer while methodname[:1] == '<': 9577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer methodname = methodname[1:] 9587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer while methodname[-1:] == '>': 9597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer methodname = methodname[:-1] 9607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer methodname = methodname + "_event" 9617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if hasattr(ins, methodname): 9627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer self.text.bind(vevent, getattr(ins, methodname)) 9637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 9647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def apply_bindings(self, keydefs=None): 9657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if keydefs is None: 9667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer keydefs = self.Bindings.default_keydefs 9677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text = self.text 9687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.keydefs = keydefs 9697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer for event, keylist in keydefs.items(): 9707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if keylist: 971931237e2e66975c54e2ac6c5e503ee2992a22bcfRaymond Hettinger text.event_add(event, *keylist) 9727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 973610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser def fill_menus(self, menudefs=None, keydefs=None): 97483118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser """Add appropriate entries to the menus and submenus 97583118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser 97683118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser Menus that are absent or None in self.menudict are ignored. 97783118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser """ 978610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser if menudefs is None: 979610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser menudefs = self.Bindings.menudefs 9807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if keydefs is None: 9817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer keydefs = self.Bindings.default_keydefs 9827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menudict = self.menudict 9837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text = self.text 984610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser for mname, entrylist in menudefs: 9857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu = menudict.get(mname) 9867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not menu: 9877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer continue 988610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser for entry in entrylist: 989610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser if not entry: 9907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu.add_separator() 9917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 992610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser label, eventname = entry 9937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer checkbutton = (label[:1] == '!') 9947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if checkbutton: 9957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer label = label[1:] 9967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer underline, label = prepstr(label) 997610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser accelerator = get_accelerator(keydefs, eventname) 998610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser def command(text=text, eventname=eventname): 999610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser text.event_generate(eventname) 10007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if checkbutton: 1001610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser var = self.get_var_obj(eventname, BooleanVar) 10027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu.add_checkbutton(label=label, underline=underline, 10037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer command=command, accelerator=accelerator, 10047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer variable=var) 10057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 10067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer menu.add_command(label=label, underline=underline, 100784f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser command=command, 100884f4803f4f7ccf40cd777d1e9627528c30bc9053Kurt B. Kaiser accelerator=accelerator) 10097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 10107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def getvar(self, name): 1011610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser var = self.get_var_obj(name) 10127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if var: 1013610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser value = var.get() 1014610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser return value 1015610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser else: 1016610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser raise NameError, name 10177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 10187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def setvar(self, name, value, vartype=None): 1019610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser var = self.get_var_obj(name, vartype) 10207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if var: 10217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer var.set(value) 1022610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser else: 1023610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser raise NameError, name 10247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 1025610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser def get_var_obj(self, name, vartype=None): 1026610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser var = self.tkinter_vars.get(name) 10277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not var and vartype: 1028610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser # create a Tkinter variable object with self.text as master: 1029610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser self.tkinter_vars[name] = var = vartype(self.text) 10307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return var 10317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 10327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Tk implementations of "virtual text methods" -- each platform 10337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # reusing IDLE's support code needs to define these for its GUI's 10347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # flavor of widget. 10357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 10367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Is character at text_index in a Python string? Return 0 for 10377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # "guaranteed no", true for anything else. This info is expensive 10387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # to compute ab initio, but is probably already known by the 10397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # platform's colorizer. 10407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 10417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def is_char_in_string(self, text_index): 10427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.color: 10437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Return true iff colorizer hasn't (re)gotten this far 10447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # yet, or the character is tagged as being in a string 10457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return self.text.tag_prevrange("TODO", text_index) or \ 10467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer "STRING" in self.text.tag_names(text_index) 10477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 10487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # The colorizer is missing: assume the worst 10497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return 1 10507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 10517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # If a selection is defined in the text widget, return (start, 10527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # end) as Tkinter text indices, otherwise return (None, None) 10537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def get_selection_indices(self): 10547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer try: 10557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer first = self.text.index("sel.first") 10567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer last = self.text.index("sel.last") 10577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return first, last 10587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer except TclError: 10597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return None, None 10607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 10617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Return the text widget's current view of what a tab stop means 10627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # (equivalent width in spaces). 10637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 10647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def get_tabwidth(self): 10657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer current = self.text['tabs'] or TK_TABWIDTH_DEFAULT 10667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return int(current) 10677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 10687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Set the text widget's current view of what a tab stop means. 10697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 10707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer def set_tabwidth(self, newtabwidth): 10717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text = self.text 10727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if self.get_tabwidth() != newtabwidth: 10737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer pixels = text.tk.call("font", "measure", text["font"], 10747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer "-displayof", text.master, 1075afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser "n" * newtabwidth) 10767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer text.configure(tabs=pixels) 10777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 1078cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # If ispythonsource and guess are true, guess a good value for 1079cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # indentwidth based on file content (if possible), and if 1080cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # indentwidth != tabwidth set usetabs false. 1081cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # In any case, adjust the Text widget's view of what a tab 1082cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # character means. 1083cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 10846af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser def set_indentation_params(self, ispythonsource, guess=True): 1085cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if guess and ispythonsource: 1086cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser i = self.guess_indent() 1087cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if 2 <= i <= 8: 1088cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.indentwidth = i 1089cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if self.indentwidth != self.tabwidth: 10906af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser self.usetabs = False 1091cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_tabwidth(self.tabwidth) 1092cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1093cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def smart_backspace_event(self, event): 1094cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text = self.text 1095cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser first, last = self.get_selection_indices() 1096cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if first and last: 1097cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete(first, last) 1098cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.mark_set("insert", first) 1099cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1100cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Delete whitespace left, until hitting a real char or closest 1101cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # preceding virtual tab stop. 1102cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser chars = text.get("insert linestart", "insert") 1103cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if chars == '': 1104cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if text.compare("insert", ">", "1.0"): 1105cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # easy: delete preceding newline 1106cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete("insert-1c") 1107cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 1108cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bell() # at start of buffer 1109cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1110cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if chars[-1] not in " \t": 1111cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # easy: delete preceding real char 1112cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete("insert-1c") 1113cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1114cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Ick. It may require *inserting* spaces if we back up over a 1115cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # tab character! This is written to be clear, not fast. 11161b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser tabwidth = self.tabwidth 11171b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser have = len(chars.expandtabs(tabwidth)) 1118cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser assert have > 0 1119cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser want = ((have - 1) // self.indentwidth) * self.indentwidth 11204ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser # Debug prompt is multilined.... 11214ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser last_line_of_prompt = sys.ps1.split('\n')[-1] 1122cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser ncharsdeleted = 0 1123cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser while 1: 11244ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser if chars == last_line_of_prompt: 11251bdca5e051a5424aaaaf7968c710d31132a6c335Kurt B. Kaiser break 1126cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser chars = chars[:-1] 1127cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser ncharsdeleted = ncharsdeleted + 1 11281b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser have = len(chars.expandtabs(tabwidth)) 1129cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if have <= want or chars[-1] not in " \t": 1130cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser break 1131cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_start() 1132cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete("insert-%dc" % ncharsdeleted, "insert") 1133cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if have < want: 1134cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert", ' ' * (want - have)) 1135cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_stop() 1136cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1137cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1138cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def smart_indent_event(self, event): 1139cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # if intraline selection: 1140cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # delete it 1141cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # elif multiline selection: 11426af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # do indent-region 11436af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # else: 11446af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # indent one level 1145cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text = self.text 1146cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser first, last = self.get_selection_indices() 1147cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_start() 1148cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser try: 1149cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if first and last: 1150cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if index2line(first) != index2line(last): 1151cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return self.indent_region_event(event) 1152cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete(first, last) 1153cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.mark_set("insert", first) 1154cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser prefix = text.get("insert linestart", "insert") 1155cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw, effective = classifyws(prefix, self.tabwidth) 1156cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if raw == len(prefix): 1157cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # only whitespace to the left 1158cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.reindent_to(effective + self.indentwidth) 1159cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 11606af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # tab to the next 'stop' within or to right of line's text: 1161cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if self.usetabs: 1162cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser pad = '\t' 1163cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 11641b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser effective = len(prefix.expandtabs(self.tabwidth)) 1165cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser n = self.indentwidth 1166cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser pad = ' ' * (n - effective % n) 1167cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert", pad) 1168cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.see("insert") 1169cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1170cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser finally: 1171cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_stop() 1172cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1173cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def newline_and_indent_event(self, event): 1174cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text = self.text 1175cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser first, last = self.get_selection_indices() 1176cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_start() 1177cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser try: 1178cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if first and last: 1179cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete(first, last) 1180cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.mark_set("insert", first) 1181cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = text.get("insert linestart", "insert") 1182cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser i, n = 0, len(line) 1183cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser while i < n and line[i] in " \t": 1184cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser i = i+1 1185cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if i == n: 11864ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser # the cursor is in or at leading indentation in a continuation 11874ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser # line; just inject an empty line at the start 1188cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert linestart", '\n') 1189cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1190cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser indent = line[:i] 11914ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser # strip whitespace before insert point unless it's in the prompt 1192cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser i = 0 11934ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser last_line_of_prompt = sys.ps1.split('\n')[-1] 11944ada7ad3bc9ab269189ed20e57943d9721664debKurt B. Kaiser while line and line[-1] in " \t" and line != last_line_of_prompt: 1195cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = line[:-1] 1196cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser i = i+1 1197cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if i: 1198cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete("insert - %d chars" % i, "insert") 1199cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # strip whitespace after insert point 1200cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser while text.get("insert") in " \t": 1201cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete("insert") 1202cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # start new line 1203cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert", '\n') 1204cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1205cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # adjust indentation for continuations and block 1206cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # open/close first need to find the last stmt 1207cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser lno = index2line(text.index('insert')) 1208cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser y = PyParse.Parser(self.indentwidth, self.tabwidth) 1209b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser if not self.context_use_ps1: 1210b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser for context in self.num_context_lines: 1211b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser startat = max(lno - context, 1) 1212dfd3618422bc19ae48047e74c6320746ee6b610eFlorent Xicluna startatindex = repr(startat) + ".0" 1213b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser rawtext = text.get(startatindex, "insert") 1214b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser y.set_str(rawtext) 1215b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser bod = y.find_good_parse_start( 1216b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser self.context_use_ps1, 1217b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser self._build_char_in_string_func(startatindex)) 1218b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser if bod is not None or startat == 1: 1219b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser break 1220b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser y.set_lo(bod or 0) 1221b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser else: 1222b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser r = text.tag_prevrange("console", "insert") 1223b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser if r: 1224b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser startatindex = r[1] 1225b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser else: 1226b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser startatindex = "1.0" 1227cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser rawtext = text.get(startatindex, "insert") 1228cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser y.set_str(rawtext) 1229b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser y.set_lo(0) 1230b17544551fc8dfd1304d5679c6e444cad4d34d97Kurt B. Kaiser 1231cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser c = y.get_continuation_type() 1232cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if c != PyParse.C_NONE: 1233cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # The current stmt hasn't ended yet. 1234b61602c96821997884e7de08d56404904baa034bKurt B. Kaiser if c == PyParse.C_STRING_FIRST_LINE: 1235b61602c96821997884e7de08d56404904baa034bKurt B. Kaiser # after the first line of a string; do not indent at all 1236b61602c96821997884e7de08d56404904baa034bKurt B. Kaiser pass 1237b61602c96821997884e7de08d56404904baa034bKurt B. Kaiser elif c == PyParse.C_STRING_NEXT_LINES: 1238b61602c96821997884e7de08d56404904baa034bKurt B. Kaiser # inside a string which started before this line; 1239b61602c96821997884e7de08d56404904baa034bKurt B. Kaiser # just mimic the current indent 1240cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert", indent) 1241cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif c == PyParse.C_BRACKET: 1242cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # line up with the first (if any) element of the 1243cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # last open bracket structure; else indent one 1244cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # level beyond the indent of the line with the 1245cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # last open bracket 1246cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.reindent_to(y.compute_bracket_indent()) 1247cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif c == PyParse.C_BACKSLASH: 1248cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # if more than one line in this stmt already, just 1249cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # mimic the current indent; else if initial line 1250cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # has a start on an assignment stmt, indent to 1251cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # beyond leftmost =; else to beyond first chunk of 1252cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # non-whitespace on initial line 1253cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if y.get_num_lines_in_stmt() > 1: 1254cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert", indent) 1255cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 1256cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.reindent_to(y.compute_backslash_indent()) 1257cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 125870a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald assert 0, "bogus continuation type %r" % (c,) 1259cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1260cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1261cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # This line starts a brand new stmt; indent relative to 1262cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # indentation of initial line of closest preceding 1263cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # interesting stmt. 1264cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser indent = y.get_base_indent_string() 1265cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert", indent) 1266cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if y.is_block_opener(): 1267cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.smart_indent_event(event) 1268cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif indent and y.is_block_closer(): 1269cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.smart_backspace_event(event) 1270cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1271cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser finally: 1272cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.see("insert") 1273cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_stop() 1274cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1275cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Our editwin provides a is_char_in_string function that works 1276cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # with a Tk text index, but PyParse only knows about offsets into 1277cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # a string. This builds a function for PyParse that accepts an 1278cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # offset. 1279cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1280cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def _build_char_in_string_func(self, startindex): 1281cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def inner(offset, _startindex=startindex, 1282cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser _icis=self.is_char_in_string): 1283cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return _icis(_startindex + "+%dc" % offset) 1284cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return inner 1285cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1286cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def indent_region_event(self, event): 1287cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head, tail, chars, lines = self.get_region() 1288cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for pos in range(len(lines)): 1289cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = lines[pos] 1290cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if line: 1291cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw, effective = classifyws(line, self.tabwidth) 1292cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser effective = effective + self.indentwidth 1293cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser lines[pos] = self._make_blanks(effective) + line[raw:] 1294cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_region(head, tail, chars, lines) 1295cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1296cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1297cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def dedent_region_event(self, event): 1298cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head, tail, chars, lines = self.get_region() 1299cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for pos in range(len(lines)): 1300cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = lines[pos] 1301cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if line: 1302cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw, effective = classifyws(line, self.tabwidth) 1303cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser effective = max(effective - self.indentwidth, 0) 1304cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser lines[pos] = self._make_blanks(effective) + line[raw:] 1305cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_region(head, tail, chars, lines) 1306cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1307cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1308cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def comment_region_event(self, event): 1309cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head, tail, chars, lines = self.get_region() 1310cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for pos in range(len(lines) - 1): 1311cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = lines[pos] 1312cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser lines[pos] = '##' + line 1313cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_region(head, tail, chars, lines) 1314cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1315cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def uncomment_region_event(self, event): 1316cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head, tail, chars, lines = self.get_region() 1317cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for pos in range(len(lines)): 1318cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = lines[pos] 1319cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if not line: 1320cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser continue 1321cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if line[:2] == '##': 1322cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = line[2:] 1323cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif line[:1] == '#': 1324cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = line[1:] 1325cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser lines[pos] = line 1326cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_region(head, tail, chars, lines) 1327cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1328cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def tabify_region_event(self, event): 1329cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head, tail, chars, lines = self.get_region() 1330cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser tabwidth = self._asktabwidth() 1331cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for pos in range(len(lines)): 1332cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser line = lines[pos] 1333cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if line: 1334cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw, effective = classifyws(line, tabwidth) 1335cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser ntabs, nspaces = divmod(effective, tabwidth) 1336cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:] 1337cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_region(head, tail, chars, lines) 1338cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1339cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def untabify_region_event(self, event): 1340cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head, tail, chars, lines = self.get_region() 1341cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser tabwidth = self._asktabwidth() 1342cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for pos in range(len(lines)): 13431b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser lines[pos] = lines[pos].expandtabs(tabwidth) 1344cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.set_region(head, tail, chars, lines) 1345cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1346cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def toggle_tabs_event(self, event): 1347cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if self.askyesno( 1348cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser "Toggle tabs", 13496af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser "Turn tabs " + ("on", "off")[self.usetabs] + 13506af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser "?\nIndent width " + 135153f2b5fab2f525342dbb69f6f2d5eed978c7883fKurt B. Kaiser ("will be", "remains at")[self.usetabs] + " 8." + 135253f2b5fab2f525342dbb69f6f2d5eed978c7883fKurt B. Kaiser "\n Note: a tab is always 8 columns", 1353cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser parent=self.text): 1354cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.usetabs = not self.usetabs 135553f2b5fab2f525342dbb69f6f2d5eed978c7883fKurt B. Kaiser # Try to prevent inconsistent indentation. 135653f2b5fab2f525342dbb69f6f2d5eed978c7883fKurt B. Kaiser # User must change indent width manually after using tabs. 135753f2b5fab2f525342dbb69f6f2d5eed978c7883fKurt B. Kaiser self.indentwidth = 8 1358cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1359cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 13606af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser # XXX this isn't bound to anything -- see tabwidth comments 13616af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser## def change_tabwidth_event(self, event): 13626af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser## new = self._asktabwidth() 13636af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser## if new != self.tabwidth: 13646af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser## self.tabwidth = new 13656af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser## self.set_indentation_params(0, guess=0) 13666af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser## return "break" 1367cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1368cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def change_indentwidth_event(self, event): 1369cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser new = self.askinteger( 1370cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser "Indent width", 13716af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser "New indent width (2-16)\n(Always use 8 when using tabs)", 1372cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser parent=self.text, 1373cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser initialvalue=self.indentwidth, 1374cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser minvalue=2, 1375cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser maxvalue=16) 13766af44986029c84c4c5df62a64c60a6ed978a3693Kurt B. Kaiser if new and new != self.indentwidth and not self.usetabs: 1377cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.indentwidth = new 1378cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "break" 1379cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1380cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def get_region(self): 1381cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text = self.text 1382cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser first, last = self.get_selection_indices() 1383cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if first and last: 1384cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head = text.index(first + " linestart") 1385cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser tail = text.index(last + "-1c lineend +1c") 1386cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 1387cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser head = text.index("insert linestart") 1388cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser tail = text.index("insert lineend +1c") 1389cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser chars = text.get(head, tail) 13901b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser lines = chars.split("\n") 1391cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return head, tail, chars, lines 1392cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1393cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def set_region(self, head, tail, chars, lines): 1394cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text = self.text 13951b3c26998e0f8b6975f7bbccf043c0afe398f151Kurt B. Kaiser newchars = "\n".join(lines) 1396cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if newchars == chars: 1397cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.bell() 1398cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return 1399cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.tag_remove("sel", "1.0", "end") 1400cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.mark_set("insert", head) 1401cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_start() 1402cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete(head, tail) 1403cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert(head, newchars) 1404cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_stop() 1405cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.tag_add("sel", head, "insert") 1406cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1407cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Make string that displays as n leading blanks. 1408cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1409cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def _make_blanks(self, n): 1410cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if self.usetabs: 1411cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser ntabs, nspaces = divmod(n, self.tabwidth) 1412cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return '\t' * ntabs + ' ' * nspaces 1413cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 1414cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return ' ' * n 1415cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1416cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Delete from beginning of line to insert point, then reinsert 1417cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # column logical (meaning use tabs if appropriate) spaces. 1418cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1419cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def reindent_to(self, column): 1420cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text = self.text 1421cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_start() 1422cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if text.compare("insert linestart", "!=", "insert"): 1423cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.delete("insert linestart", "insert") 1424cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if column: 1425cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.insert("insert", self._make_blanks(column)) 1426cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser text.undo_block_stop() 1427cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1428cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def _asktabwidth(self): 1429cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return self.askinteger( 1430cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser "Tab width", 1431ca7329c9c124080b817ceb67b4e3ee7963b81d41Kurt B. Kaiser "Columns per tab? (2-16)", 1432cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser parent=self.text, 1433cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser initialvalue=self.indentwidth, 1434cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser minvalue=2, 1435cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser maxvalue=16) or self.tabwidth 1436cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1437cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Guess indentwidth from text content. 1438cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Return guessed indentwidth. This should not be believed unless 1439cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # it's in a reasonable range (e.g., it will be 0 if no indented 1440cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # blocks are found). 1441cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1442cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def guess_indent(self): 1443cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser opener, indented = IndentSearcher(self.text, self.tabwidth).run() 1444cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if opener and indented: 1445cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw, indentsmall = classifyws(opener, self.tabwidth) 1446cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw, indentlarge = classifyws(indented, self.tabwidth) 1447cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 1448cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser indentsmall = indentlarge = 0 1449cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return indentlarge - indentsmall 1450cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1451cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser# "line.col" -> line, as an int 1452cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserdef index2line(index): 1453cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return int(float(index)) 1454cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1455cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser# Look at the leading whitespace in s. 1456cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser# Return pair (# of leading ws characters, 1457cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser# effective # of leading blanks after expanding 1458cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser# tabs to width tabwidth) 1459cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1460cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserdef classifyws(s, tabwidth): 1461cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw = effective = 0 1462cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser for ch in s: 1463cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if ch == ' ': 1464cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw = raw + 1 1465cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser effective = effective + 1 1466cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif ch == '\t': 1467cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser raw = raw + 1 1468cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser effective = (effective // tabwidth + 1) * tabwidth 1469cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser else: 1470cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser break 1471cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return raw, effective 1472cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1473cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserimport tokenize 1474cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser_tokenize = tokenize 1475cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiserdel tokenize 1476cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1477dcba6622f52efafa28104a07db9d5ba2b1a8d628Kurt B. Kaiserclass IndentSearcher(object): 1478cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1479cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # .run() chews over the Text widget, looking for a block opener 1480cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # and the stmt following it. Returns a pair, 1481cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # (line containing block opener, line containing stmt) 1482cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # Either or both may be None. 1483cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1484cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def __init__(self, text, tabwidth): 1485cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.text = text 1486cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.tabwidth = tabwidth 1487cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.i = self.finished = 0 1488cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.blkopenline = self.indentedline = None 1489cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1490cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def readline(self): 1491cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if self.finished: 1492cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "" 1493cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser i = self.i = self.i + 1 149470a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald mark = repr(i) + ".0" 1495cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if self.text.compare(mark, ">=", "end"): 1496cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return "" 1497cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return self.text.get(mark, mark + " lineend+1c") 1498cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1499cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def tokeneater(self, type, token, start, end, line, 1500cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser INDENT=_tokenize.INDENT, 1501cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser NAME=_tokenize.NAME, 1502cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser OPENERS=('class', 'def', 'for', 'if', 'try', 'while')): 1503cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser if self.finished: 1504cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser pass 1505cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif type == NAME and token in OPENERS: 1506cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.blkopenline = line 1507cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser elif type == INDENT and self.blkopenline: 1508cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.indentedline = line 1509cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser self.finished = 1 1510cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1511cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser def run(self): 1512cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser save_tabsize = _tokenize.tabsize 1513cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser _tokenize.tabsize = self.tabwidth 1514cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser try: 1515cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser try: 1516cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser _tokenize.tokenize(self.readline, self.tokeneater) 1517cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser except _tokenize.TokenError: 1518cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # since we cut off the tokenizer early, we can trigger 1519cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser # spurious errors 1520cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser pass 1521cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser finally: 1522cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser _tokenize.tabsize = save_tabsize 1523cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser return self.blkopenline, self.indentedline 1524cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 1525cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser### end autoindent code ### 1526cb7a383bad7e7085f1bd6067865516aa9244cf23Kurt B. Kaiser 15277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef prepstr(s): 15287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Helper to extract the underscore from a string, e.g. 15297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # prepstr("Co_py") returns (2, "Copy"). 1530220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser i = s.find('_') 15317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if i >= 0: 15327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = s[:i] + s[i+1:] 15337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return i, s 15347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 15357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 15367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererkeynames = { 15377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 'bracketleft': '[', 15387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 'bracketright': ']', 15397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 'slash': '/', 15407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer} 15417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 1542610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiserdef get_accelerator(keydefs, eventname): 1543610c7e07f3e41e1f4baf7303edc8124269c01250Kurt B. Kaiser keylist = keydefs.get(eventname) 15447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if not keylist: 15457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return "" 15467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = keylist[0] 1547220ecbc731bf600fe977e1721f2f5c1aec7b033cKurt B. Kaiser s = re.sub(r"-[a-z]\b", lambda m: m.group().upper(), s) 15487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s) 15497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub("Key-", "", s) 15507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub("Cancel","Ctrl-Break",s) # dscherer@cmu.edu 15517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub("Control-", "Ctrl-", s) 15527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub("-", "+", s) 15537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub("><", " ", s) 15547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub("<", "", s) 15557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer s = re.sub(">", "", s) 15567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer return s 15577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 15587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 15597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef fixwordbreaks(root): 15607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # Make sure that Tk's double-click and next/previous word 15617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer # operations use our definition of a word (i.e. an identifier) 15627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tk = root.tk 15637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded 15647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_]') 15657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]') 15667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 15677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 15687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef test(): 15697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer root = Tk() 15707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer fixwordbreaks(root) 15717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer root.withdraw() 15727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer if sys.argv[1:]: 15737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer filename = sys.argv[1] 15747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer else: 15757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer filename = None 15767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer edit = EditorWindow(root=root, filename=filename) 15777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer edit.set_close_hook(root.quit) 15780b634efcbcd10d9364796e9b048f18cd4a08b88bKurt B. Kaiser edit.text.bind("<<close-all-windows>>", edit.close_event) 15797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer root.mainloop() 15807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer root.destroy() 15817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 15827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererif __name__ == '__main__': 15837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer test() 1584