diff options
Diffstat (limited to 'Lib/idlelib/EditorWindow.py')
-rw-r--r-- | Lib/idlelib/EditorWindow.py | 147 |
1 files changed, 77 insertions, 70 deletions
diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py index 0a01c9ec305..16f63c52a40 100644 --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -1,10 +1,12 @@ import sys import os import re +import string import imp -from Tkinter import * -import tkSimpleDialog -import tkMessageBox +from tkinter import * +import tkinter.simpledialog as tkSimpleDialog +import tkinter.messagebox as tkMessageBox +import traceback import webbrowser from idlelib.MultiCall import MultiCallCreator @@ -47,7 +49,7 @@ def _find_module(fullname, path=None): try: path = module.__path__ except AttributeError: - raise ImportError, 'No source for module ' + module.__name__ + raise ImportError('No source for module ' + module.__name__) if descr[2] != imp.PY_SOURCE: # If all of the above fails and didn't raise an exception,fallback # to a straight import which can find __init__.py in a package. @@ -58,11 +60,7 @@ def _find_module(fullname, path=None): pass else: file = None - base, ext = os.path.splitext(filename) - if ext == '.pyc': - ext = '.py' - filename = base + ext - descr = filename, None, imp.PY_SOURCE + descr = os.path.splitext(filename)[1], None, imp.PY_SOURCE return file, filename, descr @@ -115,7 +113,7 @@ class EditorWindow(object): from idlelib.UndoDelegator import UndoDelegator from idlelib.IOBinding import IOBinding, filesystemencoding, encoding from idlelib import Bindings - from Tkinter import Toplevel + from tkinter import Toplevel from idlelib.MultiStatusBar import MultiStatusBar help_url = None @@ -172,13 +170,15 @@ class EditorWindow(object): 'recent-files.lst') self.text_frame = text_frame = Frame(top) self.vbar = vbar = Scrollbar(text_frame, name='vbar') - self.width = idleConf.GetOption('main','EditorWindow','width', type='int') + self.width = idleConf.GetOption('main', 'EditorWindow', + 'width', type='int') text_options = { 'name': 'text', 'padx': 5, 'wrap': 'none', 'width': self.width, - 'height': idleConf.GetOption('main', 'EditorWindow', 'height', type='int')} + 'height': idleConf.GetOption('main', 'EditorWindow', + 'height', type='int')} if TkVersion >= 8.5: # Starting with tk 8.5 we have to set the new tabstyle option # to 'wordprocessor' to achieve the same display of tabs as in @@ -271,7 +271,8 @@ class EditorWindow(object): # Although use-spaces=0 can be configured manually in config-main.def, # configuration of tabs v. spaces is not supported in the configuration # dialog. IDLE promotes the preferred Python indentation: use spaces! - usespaces = idleConf.GetOption('main', 'Indent', 'use-spaces', type='bool') + usespaces = idleConf.GetOption('main', 'Indent', + 'use-spaces', type='bool') self.usetabs = not usespaces # tabwidth is the display width of a literal tab character. @@ -297,39 +298,33 @@ class EditorWindow(object): # conceivable file). # Making the initial values larger slows things down more often. self.num_context_lines = 50, 500, 5000000 - self.per = per = self.Percolator(text) - self.undo = undo = self.UndoDelegator() per.insertfilter(undo) text.undo_block_start = undo.undo_block_start text.undo_block_stop = undo.undo_block_stop undo.set_saved_change_hook(self.saved_change_hook) - # IOBinding implements file I/O and printing functionality self.io = io = self.IOBinding(self) io.set_filename_change_hook(self.filename_change_hook) - - # Create the recent files submenu - self.recent_files_menu = Menu(self.menubar) - self.menudict['file'].insert_cascade(3, label='Recent Files', - underline=0, - menu=self.recent_files_menu) - self.update_recent_files_list() - + self.good_load = False + self.set_indentation_params(False) self.color = None # initialized below in self.ResetColorizer if filename: if os.path.exists(filename) and not os.path.isdir(filename): - io.loadfile(filename) + if io.loadfile(filename): + self.good_load = True + is_py_src = self.ispythonsource(filename) + self.set_indentation_params(is_py_src) + if is_py_src: + self.color = color = self.ColorDelegator() + per.insertfilter(color) else: io.set_filename(filename) self.ResetColorizer() self.saved_change_hook() - - self.set_indentation_params(self.ispythonsource(filename)) - + self.update_recent_files_list() self.load_extensions() - menu = self.menudict.get('windows') if menu: end = menu.index("end") @@ -348,7 +343,7 @@ class EditorWindow(object): def _filename_to_unicode(self, filename): """convert filename to unicode in order to display it in Tk""" - if isinstance(filename, unicode) or not filename: + if isinstance(filename, str) or not filename: return filename else: try: @@ -377,7 +372,7 @@ class EditorWindow(object): insertpt = int(self.text.index("iomark").split(".")[1]) else: line = self.text.get("insert linestart", "insert lineend") - for insertpt in xrange(len(line)): + for insertpt in range(len(line)): if line[insertpt] not in (' ','\t'): break else: @@ -391,9 +386,11 @@ class EditorWindow(object): self.text.tag_remove("sel", "1.0", "end") else: if not self.text.index("sel.first"): - self.text.mark_set("my_anchor", "insert") # there was no previous selection + # there was no previous selection + self.text.mark_set("my_anchor", "insert") else: - if self.text.compare(self.text.index("sel.first"), "<", self.text.index("insert")): + if self.text.compare(self.text.index("sel.first"), "<", + self.text.index("insert")): self.text.mark_set("my_anchor", "sel.first") # extend back else: self.text.mark_set("my_anchor", "sel.last") # extend forward @@ -448,13 +445,15 @@ class EditorWindow(object): underline, label = prepstr(label) menudict[name] = menu = Menu(mbar, name=name) mbar.add_cascade(label=label, menu=menu, underline=underline) - if macosxSupport.isCarbonAquaTk(self.root): # Insert the application menu menudict['application'] = menu = Menu(mbar, name='apple') mbar.add_cascade(label='IDLE', menu=menu) - self.fill_menus() + self.recent_files_menu = Menu(self.menubar) + self.menudict['file'].insert_cascade(3, label='Recent Files', + underline=0, + menu=self.recent_files_menu) self.base_helpmenu_length = self.menudict['help'].index(END) self.reset_help_menu_entries() @@ -486,6 +485,7 @@ class EditorWindow(object): state = getattr(self, verify_state)() rmenu.entryconfigure(label, state=state) + rmenu.tk_popup(event.x_root, event.y_root) if iswin: self.text.config(cursor="ibeam") @@ -636,7 +636,7 @@ class EditorWindow(object): text.see("insert") def open_module(self, event=None): - # XXX Shouldn't this be in IOBinding or in FileList? + # XXX Shouldn't this be in IOBinding? try: name = self.text.get("sel.first", "sel.last") except TclError: @@ -654,7 +654,7 @@ class EditorWindow(object): # XXX Ought to insert current file's directory in front of path try: (f, file, (suffix, mode, type)) = _find_module(name) - except (NameError, ImportError), msg: + except (NameError, ImportError) as msg: tkMessageBox.showerror("Import error", str(msg), parent=self.text) return if type != imp.PY_SOURCE: @@ -699,13 +699,8 @@ class EditorWindow(object): base, ext = os.path.splitext(os.path.basename(filename)) if os.path.normcase(ext) in (".py", ".pyw"): return True - try: - f = open(filename) - line = f.readline() - f.close() - except IOError: - return False - return line.startswith('#!') and line.find('python') >= 0 + line = self.text.get('1.0', '1.0 lineend') + return line.startswith('#!') and 'python' in line def close_hook(self): if self.flist: @@ -757,6 +752,19 @@ class EditorWindow(object): selectbackground=select_colors['background'], ) + IDENTCHARS = string.ascii_letters + string.digits + "_" + + def colorize_syntax_error(self, text, pos): + text.tag_add("ERROR", pos) + char = text.get(pos) + if char and char in self.IDENTCHARS: + text.tag_add("ERROR", pos + " wordstart", pos) + if '\n' == text.get(pos): # error at line end + text.mark_set("insert", pos) + else: + text.mark_set("insert", pos + "+1c") + text.see(pos) + def ResetFont(self): "Update the text widgets' font if it is changed" # Called from configDialog.py @@ -796,7 +804,7 @@ class EditorWindow(object): for item in menu[1]: if item: menuEventDict[menu[0]][prepstr(item[0])[1]] = item[1] - for menubarItem in self.menudict.keys(): + for menubarItem in self.menudict: menu = self.menudict[menubarItem] end = menu.index(END) + 1 for index in range(0, end): @@ -855,7 +863,8 @@ class EditorWindow(object): "Load and update the recent files list and menus" rf_list = [] if os.path.exists(self.recent_files_path): - rf_list_file = open(self.recent_files_path,'r') + rf_list_file = open(self.recent_files_path,'r', + encoding='utf_8', errors='replace') try: rf_list = rf_list_file.readlines() finally: @@ -874,7 +883,8 @@ class EditorWindow(object): ulchars = "1234567890ABCDEFGHIJK" rf_list = rf_list[0:len(ulchars)] try: - with open(self.recent_files_path, 'w') as rf_file: + with open(self.recent_files_path, 'w', + encoding='utf_8', errors='replace') as rf_file: rf_file.writelines(rf_list) except IOError as err: if not getattr(self.root, "recentfilelist_error_displayed", False): @@ -884,7 +894,7 @@ class EditorWindow(object): % str(err), parent=self.text) # for each edit window instance, construct the recent files menu - for instance in self.top.instance_dict.keys(): + for instance in self.top.instance_dict: menu = instance.recent_files_menu menu.delete(0, END) # clear, and rebuild: for i, file_name in enumerate(rf_list): @@ -968,8 +978,7 @@ class EditorWindow(object): "Return (width, height, x, y)" geom = self.top.wm_geometry() m = re.match(r"(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geom) - tuple = (map(int, m.groups())) - return tuple + return list(map(int, m.groups())) def close_event(self, event): self.close() @@ -1014,7 +1023,7 @@ class EditorWindow(object): self.load_standard_extensions() def unload_extensions(self): - for ins in self.extensions.values(): + for ins in list(self.extensions.values()): if hasattr(ins, "close"): ins.close() self.extensions = {} @@ -1024,8 +1033,7 @@ class EditorWindow(object): try: self.load_extension(name) except: - print "Failed to load extension", repr(name) - import traceback + print("Failed to load extension", repr(name)) traceback.print_exc() def get_standard_extension_names(self): @@ -1035,8 +1043,8 @@ class EditorWindow(object): try: mod = __import__(name, globals(), locals(), []) except ImportError: - print "\nFailed to import extension: ", name - return + print("\nFailed to import extension: ", name) + raise cls = getattr(mod, name) keydefs = idleConf.GetExtensionBindings(name) if hasattr(cls, "menudefs"): @@ -1045,7 +1053,7 @@ class EditorWindow(object): self.extensions[name] = ins if keydefs: self.apply_bindings(keydefs) - for vevent in keydefs.keys(): + for vevent in keydefs: methodname = vevent.replace("-", "_") while methodname[:1] == '<': methodname = methodname[1:] @@ -1107,14 +1115,14 @@ class EditorWindow(object): value = var.get() return value else: - raise NameError, name + raise NameError(name) def setvar(self, name, value, vartype=None): var = self.get_var_obj(name, vartype) if var: var.set(value) else: - raise NameError, name + raise NameError(name) def get_var_obj(self, name, vartype=None): var = self.tkinter_vars.get(name) @@ -1155,34 +1163,31 @@ class EditorWindow(object): # Return the text widget's current view of what a tab stop means # (equivalent width in spaces). - def get_tabwidth(self): + def get_tk_tabwidth(self): current = self.text['tabs'] or TK_TABWIDTH_DEFAULT return int(current) # Set the text widget's current view of what a tab stop means. - def set_tabwidth(self, newtabwidth): + def set_tk_tabwidth(self, newtabwidth): text = self.text - if self.get_tabwidth() != newtabwidth: + if self.get_tk_tabwidth() != newtabwidth: + # Set text widget tab width pixels = text.tk.call("font", "measure", text["font"], "-displayof", text.master, "n" * newtabwidth) text.configure(tabs=pixels) - # If ispythonsource and guess are true, guess a good value for - # indentwidth based on file content (if possible), and if - # indentwidth != tabwidth set usetabs false. - # In any case, adjust the Text widget's view of what a tab - # character means. +### begin autoindent code ### (configuration was moved to beginning of class) - def set_indentation_params(self, ispythonsource, guess=True): - if guess and ispythonsource: + def set_indentation_params(self, is_py_src, guess=True): + if is_py_src and guess: i = self.guess_indent() if 2 <= i <= 8: self.indentwidth = i if self.indentwidth != self.tabwidth: self.usetabs = False - self.set_tabwidth(self.tabwidth) + self.set_tk_tabwidth(self.tabwidth) def smart_backspace_event(self, event): text = self.text @@ -1610,7 +1615,9 @@ class IndentSearcher(object): _tokenize.tabsize = self.tabwidth try: try: - _tokenize.tokenize(self.readline, self.tokeneater) + tokens = _tokenize.generate_tokens(self.readline) + for token in tokens: + self.tokeneater(*token) except (_tokenize.TokenError, SyntaxError): # since we cut off the tokenizer early, we can trigger # spurious errors |