diff options
Diffstat (limited to 'Lib/idlelib/EditorWindow.py')
-rw-r--r-- | Lib/idlelib/EditorWindow.py | 145 |
1 files changed, 85 insertions, 60 deletions
diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py index 16f63c52a4..4bf1111482 100644 --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -1,8 +1,10 @@ -import sys +import importlib +import importlib.abc import os +from platform import python_version import re import string -import imp +import sys from tkinter import * import tkinter.simpledialog as tkSimpleDialog import tkinter.messagebox as tkMessageBox @@ -27,42 +29,13 @@ def _sphinx_version(): "Format sys.version_info to produce the Sphinx version string used to install the chm docs" major, minor, micro, level, serial = sys.version_info release = '%s%s' % (major, minor) - if micro: - release += '%s' % (micro,) + release += '%s' % (micro,) if level == 'candidate': release += 'rc%s' % (serial,) elif level != 'final': release += '%s%s' % (level[0], serial) return release -def _find_module(fullname, path=None): - """Version of imp.find_module() that handles hierarchical module names""" - - file = None - for tgt in fullname.split('.'): - if file is not None: - file.close() # close intermediate files - (file, filename, descr) = imp.find_module(tgt, path) - if descr[2] == imp.PY_SOURCE: - break # find but not load the source file - module = imp.load_module(tgt, file, filename, descr) - try: - path = module.__path__ - except AttributeError: - 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. - m = __import__(fullname) - try: - filename = m.__file__ - except AttributeError: - pass - else: - file = None - descr = os.path.splitext(filename)[1], None, imp.PY_SOURCE - return file, filename, descr - class HelpDialog(object): @@ -120,7 +93,7 @@ class EditorWindow(object): def __init__(self, flist=None, filename=None, key=None, root=None): if EditorWindow.help_url is None: - dochome = os.path.join(sys.prefix, 'Doc', 'index.html') + dochome = os.path.join(sys.base_prefix, 'Doc', 'index.html') if sys.platform.count('linux'): # look for html docs in a couple of standard places pyver = 'python-docs-' + '%s.%s.%s' % sys.version_info[:3] @@ -131,13 +104,13 @@ class EditorWindow(object): dochome = os.path.join(basepath, pyver, 'Doc', 'index.html') elif sys.platform[:3] == 'win': - chmfile = os.path.join(sys.prefix, 'Doc', + chmfile = os.path.join(sys.base_prefix, 'Doc', 'Python%s.chm' % _sphinx_version()) if os.path.isfile(chmfile): dochome = chmfile elif macosxSupport.runningAsOSXApp(): # documentation is stored inside the python framework - dochome = os.path.join(sys.prefix, + dochome = os.path.join(sys.base_prefix, 'Resources/English.lproj/Documentation/index.html') dochome = os.path.normpath(dochome) if os.path.isfile(dochome): @@ -316,11 +289,10 @@ class EditorWindow(object): 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.good_load = True + self.ResetColorizer() self.saved_change_hook() self.update_recent_files_list() @@ -341,6 +313,36 @@ class EditorWindow(object): self.askinteger = tkSimpleDialog.askinteger self.showerror = tkMessageBox.showerror + self._highlight_workaround() # Fix selection tags on Windows + + def _highlight_workaround(self): + # On Windows, Tk removes painting of the selection + # tags which is different behavior than on Linux and Mac. + # See issue14146 for more information. + if not sys.platform.startswith('win'): + return + + text = self.text + text.event_add("<<Highlight-FocusOut>>", "<FocusOut>") + text.event_add("<<Highlight-FocusIn>>", "<FocusIn>") + def highlight_fix(focus): + sel_range = text.tag_ranges("sel") + if sel_range: + if focus == 'out': + HILITE_CONFIG = idleConf.GetHighlight( + idleConf.CurrentTheme(), 'hilite') + text.tag_config("sel_fix", HILITE_CONFIG) + text.tag_raise("sel_fix") + text.tag_add("sel_fix", *sel_range) + elif focus == 'in': + text.tag_remove("sel_fix", "1.0", "end") + + text.bind("<<Highlight-FocusOut>>", + lambda ev: highlight_fix("out")) + text.bind("<<Highlight-FocusIn>>", + lambda ev: highlight_fix("in")) + + def _filename_to_unicode(self, filename): """convert filename to unicode in order to display it in Tk""" if isinstance(filename, str) or not filename: @@ -434,7 +436,6 @@ class EditorWindow(object): ] if macosxSupport.runningAsOSXApp(): - del menu_specs[-3] menu_specs[-2] = ("windows", "_Window") @@ -479,7 +480,12 @@ class EditorWindow(object): if iswin: self.text.config(cursor="arrow") - for label, eventname, verify_state in self.rmenu_specs: + for item in self.rmenu_specs: + try: + label, eventname, verify_state = item + except ValueError: # see issue1207589 + continue + if verify_state is None: continue state = getattr(self, verify_state)() @@ -497,7 +503,8 @@ class EditorWindow(object): def make_rmenu(self): rmenu = Menu(self.text, tearoff=0) - for label, eventname, _ in self.rmenu_specs: + for item in self.rmenu_specs: + label, eventname = item[0], item[1] if label is not None: def command(text=self.text, eventname=eventname): text.event_generate(eventname) @@ -653,20 +660,29 @@ class EditorWindow(object): return # XXX Ought to insert current file's directory in front of path try: - (f, file, (suffix, mode, type)) = _find_module(name) - except (NameError, ImportError) as msg: + loader = importlib.find_loader(name) + except (ValueError, ImportError) as msg: tkMessageBox.showerror("Import error", str(msg), parent=self.text) return - if type != imp.PY_SOURCE: - tkMessageBox.showerror("Unsupported type", - "%s is not a source module" % name, parent=self.text) + if loader is None: + tkMessageBox.showerror("Import error", "module not found", + parent=self.text) + return + if not isinstance(loader, importlib.abc.SourceLoader): + tkMessageBox.showerror("Import error", "not a source-based module", + parent=self.text) + return + try: + file_path = loader.get_filename(name) + except AttributeError: + tkMessageBox.showerror("Import error", + "loader does not support get_filename", + parent=self.text) return - if f: - f.close() if self.flist: - self.flist.open(file) + self.flist.open(file_path) else: - self.io.loadfile(file) + self.io.loadfile(file_path) def open_class_browser(self, event=None): filename = self.io.filename @@ -806,7 +822,11 @@ class EditorWindow(object): menuEventDict[menu[0]][prepstr(item[0])[1]] = item[1] for menubarItem in self.menudict: menu = self.menudict[menubarItem] - end = menu.index(END) + 1 + end = menu.index(END) + if end is None: + # Skip empty menus + continue + end += 1 for index in range(0, end): if menu.type(index) == 'command': accel = menu.entrycget(index, 'accelerator') @@ -863,12 +883,9 @@ 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', - encoding='utf_8', errors='replace') - try: + with open(self.recent_files_path, 'r', + encoding='utf_8', errors='replace') as rf_list_file: rf_list = rf_list_file.readlines() - finally: - rf_list_file.close() if new_file: new_file = os.path.abspath(new_file) + '\n' if new_file in rf_list: @@ -886,7 +903,7 @@ class EditorWindow(object): with open(self.recent_files_path, 'w', encoding='utf_8', errors='replace') as rf_file: rf_file.writelines(rf_list) - except IOError as err: + except OSError as err: if not getattr(self.root, "recentfilelist_error_displayed", False): self.root.recentfilelist_error_displayed = True tkMessageBox.showerror(title='IDLE Error', @@ -939,11 +956,14 @@ class EditorWindow(object): self.undo.reset_undo() def short_title(self): + pyversion = "Python " + python_version() + ": " filename = self.io.filename if filename: filename = os.path.basename(filename) + else: + filename = "Untitled" # return unicode string to display non-ASCII chars correctly - return self._filename_to_unicode(filename) + return pyversion + self._filename_to_unicode(filename) def long_title(self): # return unicode string to display non-ASCII chars correctly @@ -1041,7 +1061,10 @@ class EditorWindow(object): def load_extension(self, name): try: - mod = __import__(name, globals(), locals(), []) + try: + mod = importlib.import_module('.' + name, package=__package__) + except ImportError: + mod = importlib.import_module(name) except ImportError: print("\nFailed to import extension: ", name) raise @@ -1430,6 +1453,7 @@ class EditorWindow(object): def tabify_region_event(self, event): head, tail, chars, lines = self.get_region() tabwidth = self._asktabwidth() + if tabwidth is None: return for pos in range(len(lines)): line = lines[pos] if line: @@ -1441,6 +1465,7 @@ class EditorWindow(object): def untabify_region_event(self, event): head, tail, chars, lines = self.get_region() tabwidth = self._asktabwidth() + if tabwidth is None: return for pos in range(len(lines)): lines[pos] = lines[pos].expandtabs(tabwidth) self.set_region(head, tail, chars, lines) @@ -1534,7 +1559,7 @@ class EditorWindow(object): parent=self.text, initialvalue=self.indentwidth, minvalue=2, - maxvalue=16) or self.tabwidth + maxvalue=16) # Guess indentwidth from text content. # Return guessed indentwidth. This should not be believed unless |