summaryrefslogtreecommitdiffstats
path: root/Lib/idlelib/EditorWindow.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/idlelib/EditorWindow.py')
-rw-r--r--Lib/idlelib/EditorWindow.py198
1 files changed, 92 insertions, 106 deletions
diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py
index 4bf1111..b5868be 100644
--- a/Lib/idlelib/EditorWindow.py
+++ b/Lib/idlelib/EditorWindow.py
@@ -1,7 +1,8 @@
import importlib
import importlib.abc
+import importlib.util
import os
-from platform import python_version
+import platform
import re
import string
import sys
@@ -12,7 +13,6 @@ import traceback
import webbrowser
from idlelib.MultiCall import MultiCallCreator
-from idlelib import idlever
from idlelib import WindowList
from idlelib import SearchDialog
from idlelib import GrepDialog
@@ -21,10 +21,13 @@ from idlelib import PyParse
from idlelib.configHandler import idleConf
from idlelib import aboutDialog, textView, configDialog
from idlelib import macosxSupport
+from idlelib import help
# The default tab setting for a Text widget, in average-width characters.
TK_TABWIDTH_DEFAULT = 8
+_py_version = ' (%s)' % platform.python_version()
+
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
@@ -51,6 +54,11 @@ class HelpDialog(object):
near - a Toplevel widget (e.g. EditorWindow or PyShell)
to use as a reference for placing the help window
"""
+ import warnings as w
+ w.warn("EditorWindow.HelpDialog is no longer used by Idle.\n"
+ "It will be removed in 3.6 or later.\n"
+ "It has been replaced by private help.HelpWindow\n",
+ DeprecationWarning, stacklevel=2)
if self.dlg is None:
self.show_dialog(parent)
if near:
@@ -77,7 +85,7 @@ class HelpDialog(object):
self.dlg = None
self.parent = None
-helpDialog = HelpDialog() # singleton instance
+helpDialog = HelpDialog() # singleton instance, no longer used
class EditorWindow(object):
@@ -108,8 +116,8 @@ class EditorWindow(object):
'Python%s.chm' % _sphinx_version())
if os.path.isfile(chmfile):
dochome = chmfile
- elif macosxSupport.runningAsOSXApp():
- # documentation is stored inside the python framework
+ elif sys.platform == 'darwin':
+ # documentation may be stored inside a python framework
dochome = os.path.join(sys.base_prefix,
'Resources/English.lproj/Documentation/index.html')
dochome = os.path.normpath(dochome)
@@ -119,8 +127,7 @@ class EditorWindow(object):
# Safari requires real file:-URLs
EditorWindow.help_url = 'file://' + EditorWindow.help_url
else:
- EditorWindow.help_url = "http://docs.python.org/%d.%d" % sys.version_info[:2]
- currentTheme=idleConf.CurrentTheme()
+ EditorWindow.help_url = "https://docs.python.org/%d.%d/" % sys.version_info[:2]
self.flist = flist
root = root or flist.root
self.root = root
@@ -149,6 +156,7 @@ class EditorWindow(object):
'name': 'text',
'padx': 5,
'wrap': 'none',
+ 'highlightthickness': 0,
'width': self.width,
'height': idleConf.GetOption('main', 'EditorWindow',
'height', type='int')}
@@ -165,16 +173,16 @@ class EditorWindow(object):
self.top.protocol("WM_DELETE_WINDOW", self.close)
self.top.bind("<<close-window>>", self.close_event)
- if macosxSupport.runningAsOSXApp():
+ if macosxSupport.isAquaTk():
# Command-W on editorwindows doesn't work without this.
text.bind('<<close-window>>', self.close_event)
- # Some OS X systems have only one mouse button,
- # so use control-click for pulldown menus there.
- # (Note, AquaTk defines <2> as the right button if
- # present and the Tk Text widget already binds <2>.)
+ # Some OS X systems have only one mouse button, so use
+ # control-click for popup context menus there. For two
+ # buttons, AquaTk defines <2> as the right button, not <3>.
text.bind("<Control-Button-1>",self.right_menu_event)
+ text.bind("<2>", self.right_menu_event)
else:
- # Elsewhere, use right-click for pulldown menus.
+ # Elsewhere, use right-click for popup menus.
text.bind("<3>",self.right_menu_event)
text.bind("<<cut>>", self.cut)
text.bind("<<copy>>", self.copy)
@@ -219,18 +227,13 @@ class EditorWindow(object):
text.bind("<<close-all-windows>>", self.flist.close_all_callback)
text.bind("<<open-class-browser>>", self.open_class_browser)
text.bind("<<open-path-browser>>", self.open_path_browser)
+ text.bind("<<open-turtle-demo>>", self.open_turtle_demo)
self.set_status_bar()
vbar['command'] = text.yview
vbar.pack(side=RIGHT, fill=Y)
text['yscrollcommand'] = vbar.set
- fontWeight = 'normal'
- if idleConf.GetOption('main', 'EditorWindow', 'font-bold', type='bool'):
- fontWeight='bold'
- text.config(font=(idleConf.GetOption('main', 'EditorWindow', 'font'),
- idleConf.GetOption('main', 'EditorWindow',
- 'font-size', type='int'),
- fontWeight))
+ text['font'] = idleConf.GetFont(self.root, 'main', 'EditorWindow')
text_frame.pack(side=LEFT, fill=BOTH, expand=1)
text.pack(side=TOP, fill=BOTH, expand=1)
text.focus_set()
@@ -313,50 +316,20 @@ 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:
- return filename
- else:
+ """Return filename as BMP unicode so diplayable in Tk."""
+ # Decode bytes to unicode.
+ if isinstance(filename, bytes):
try:
- return filename.decode(self.filesystemencoding)
+ filename = filename.decode(self.filesystemencoding)
except UnicodeDecodeError:
- # XXX
try:
- return filename.decode(self.encoding)
+ filename = filename.decode(self.encoding)
except UnicodeDecodeError:
# byte-to-byte conversion
- return filename.decode('iso8859-1')
+ filename = filename.decode('iso8859-1')
+ # Replace non-BMP char with diamond questionmark.
+ return re.sub('[\U00010000-\U0010FFFF]', '\ufffd', filename)
def new_callback(self, event):
dirname, basename = self.io.defaultfilename()
@@ -408,13 +381,15 @@ class EditorWindow(object):
def set_status_bar(self):
self.status_bar = self.MultiStatusBar(self.top)
- if macosxSupport.runningAsOSXApp():
+ sep = Frame(self.top, height=1, borderwidth=1, background='grey75')
+ if sys.platform == "darwin":
# Insert some padding to avoid obscuring some of the statusbar
# by the resize widget.
self.status_bar.set_label('_padding1', ' ', side=RIGHT)
self.status_bar.set_label('column', 'Col: ?', side=RIGHT)
self.status_bar.set_label('line', 'Ln: ?', side=RIGHT)
self.status_bar.pack(side=BOTTOM, fill=X)
+ sep.pack(side=BOTTOM, fill=X)
self.text.bind("<<set-line-and-column>>", self.set_line_and_column)
self.text.event_add("<<set-line-and-column>>",
"<KeyRelease>", "<ButtonRelease>")
@@ -431,27 +406,25 @@ class EditorWindow(object):
("format", "F_ormat"),
("run", "_Run"),
("options", "_Options"),
- ("windows", "_Windows"),
+ ("windows", "_Window"),
("help", "_Help"),
]
- if macosxSupport.runningAsOSXApp():
- menu_specs[-2] = ("windows", "_Window")
-
def createmenubar(self):
mbar = self.menubar
self.menudict = menudict = {}
for name, label in self.menu_specs:
underline, label = prepstr(label)
- menudict[name] = menu = Menu(mbar, name=name)
+ menudict[name] = menu = Menu(mbar, name=name, tearoff=0)
mbar.add_cascade(label=label, menu=menu, underline=underline)
- if macosxSupport.isCarbonAquaTk(self.root):
+ if macosxSupport.isCarbonTk():
# Insert the application menu
- menudict['application'] = menu = Menu(mbar, name='apple')
+ menudict['application'] = menu = Menu(mbar, name='apple',
+ tearoff=0)
mbar.add_cascade(label='IDLE', menu=menu)
self.fill_menus()
- self.recent_files_menu = Menu(self.menubar)
+ self.recent_files_menu = Menu(self.menubar, tearoff=0)
self.menudict['file'].insert_cascade(3, label='Recent Files',
underline=0,
menu=self.recent_files_menu)
@@ -533,23 +506,29 @@ class EditorWindow(object):
return 'normal'
def about_dialog(self, event=None):
+ "Handle Help 'About IDLE' event."
+ # Synchronize with macosxSupport.overrideRootMenu.about_dialog.
aboutDialog.AboutDialog(self.top,'About IDLE')
def config_dialog(self, event=None):
+ "Handle Options 'Configure IDLE' event."
+ # Synchronize with macosxSupport.overrideRootMenu.config_dialog.
configDialog.ConfigDialog(self.top,'Settings')
def help_dialog(self, event=None):
+ "Handle Help 'IDLE Help' event."
+ # Synchronize with macosxSupport.overrideRootMenu.help_dialog.
if self.root:
parent = self.root
else:
parent = self.top
- helpDialog.display(parent, near=self.top)
+ help.show_idlehelp(parent)
def python_docs(self, event=None):
if sys.platform[:3] == 'win':
try:
os.startfile(self.help_url)
- except WindowsError as why:
+ except OSError as why:
tkMessageBox.showerror(title='Document Start Failure',
message=str(why), parent=self.text)
else:
@@ -660,20 +639,20 @@ class EditorWindow(object):
return
# XXX Ought to insert current file's directory in front of path
try:
- loader = importlib.find_loader(name)
+ spec = importlib.util.find_spec(name)
except (ValueError, ImportError) as msg:
tkMessageBox.showerror("Import error", str(msg), parent=self.text)
return
- if loader is None:
+ if spec is None:
tkMessageBox.showerror("Import error", "module not found",
parent=self.text)
return
- if not isinstance(loader, importlib.abc.SourceLoader):
+ if not isinstance(spec.loader, importlib.abc.SourceLoader):
tkMessageBox.showerror("Import error", "not a source-based module",
parent=self.text)
return
try:
- file_path = loader.get_filename(name)
+ file_path = spec.loader.get_filename(name)
except AttributeError:
tkMessageBox.showerror("Import error",
"loader does not support get_filename",
@@ -683,16 +662,15 @@ class EditorWindow(object):
self.flist.open(file_path)
else:
self.io.loadfile(file_path)
+ return file_path
def open_class_browser(self, event=None):
filename = self.io.filename
- if not filename:
- tkMessageBox.showerror(
- "No filename",
- "This buffer has no associated filename",
- master=self.text)
- self.text.focus_set()
- return None
+ if not (self.__class__.__name__ == 'PyShellEditorWindow'
+ and filename):
+ filename = self.open_module()
+ if filename is None:
+ return
head, tail = os.path.split(filename)
base, ext = os.path.splitext(tail)
from idlelib import ClassBrowser
@@ -702,6 +680,14 @@ class EditorWindow(object):
from idlelib import PathBrowser
PathBrowser.PathBrowser(self.flist)
+ def open_turtle_demo(self, event = None):
+ import subprocess
+
+ cmd = [sys.executable,
+ '-c',
+ 'from turtledemo.__main__ import main; main()']
+ subprocess.Popen(cmd, shell=False)
+
def gotoline(self, lineno):
if lineno is not None and lineno > 0:
self.text.mark_set("insert", "%d.0" % lineno)
@@ -752,11 +738,11 @@ class EditorWindow(object):
self.color = None
def ResetColorizer(self):
- "Update the colour theme"
+ "Update the color theme"
# Called from self.filename_change_hook and from configDialog.py
self._rmcolorizer()
self._addcolorizer()
- theme = idleConf.GetOption('main','Theme','name')
+ theme = idleConf.CurrentTheme()
normal_colors = idleConf.GetHighlight(theme, 'normal')
cursor_color = idleConf.GetHighlight(theme, 'cursor', fgBg='fg')
select_colors = idleConf.GetHighlight(theme, 'hilite')
@@ -767,6 +753,9 @@ class EditorWindow(object):
selectforeground=select_colors['foreground'],
selectbackground=select_colors['background'],
)
+ if TkVersion >= 8.5:
+ self.text.config(
+ inactiveselectbackground=select_colors['background'])
IDENTCHARS = string.ascii_letters + string.digits + "_"
@@ -784,13 +773,8 @@ class EditorWindow(object):
def ResetFont(self):
"Update the text widgets' font if it is changed"
# Called from configDialog.py
- fontWeight='normal'
- if idleConf.GetOption('main','EditorWindow','font-bold',type='bool'):
- fontWeight='bold'
- self.text.config(font=(idleConf.GetOption('main','EditorWindow','font'),
- idleConf.GetOption('main','EditorWindow','font-size',
- type='int'),
- fontWeight))
+
+ self.text['font'] = idleConf.GetFont(self.root, 'main','EditorWindow')
def RemoveKeybindings(self):
"Remove the keybindings before they are changed."
@@ -872,7 +856,7 @@ class EditorWindow(object):
if sys.platform[:3] == 'win':
try:
os.startfile(helpfile)
- except WindowsError as why:
+ except OSError as why:
tkMessageBox.showerror(title='Document Start Failure',
message=str(why), parent=self.text)
else:
@@ -906,9 +890,11 @@ class EditorWindow(object):
except OSError as err:
if not getattr(self.root, "recentfilelist_error_displayed", False):
self.root.recentfilelist_error_displayed = True
- tkMessageBox.showerror(title='IDLE Error',
- message='Unable to update Recent Files list:\n%s'
- % str(err),
+ tkMessageBox.showwarning(title='IDLE Warning',
+ message="Cannot update File menu Recent Files list. "
+ "Your operating system says:\n%s\n"
+ "Select OK and IDLE will continue without updating."
+ % self._filename_to_unicode(str(err)),
parent=self.text)
# for each edit window instance, construct the recent files menu
for instance in self.top.instance_dict:
@@ -932,7 +918,7 @@ class EditorWindow(object):
short = self.short_title()
long = self.long_title()
if short and long:
- title = short + " - " + long
+ title = short + " - " + long + _py_version
elif short:
title = short
elif long:
@@ -956,14 +942,13 @@ 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 pyversion + self._filename_to_unicode(filename)
+ return self._filename_to_unicode(filename)
def long_title(self):
# return unicode string to display non-ASCII chars correctly
@@ -1063,7 +1048,7 @@ class EditorWindow(object):
try:
try:
mod = importlib.import_module('.' + name, package=__package__)
- except ImportError:
+ except (ImportError, TypeError):
mod = importlib.import_module(name)
except ImportError:
print("\nFailed to import extension: ", name)
@@ -1397,7 +1382,7 @@ class EditorWindow(object):
text.see("insert")
text.undo_block_stop()
- # Our editwin provides a is_char_in_string function that works
+ # Our editwin provides an is_char_in_string function that works
# with a Tk text index, but PyParse only knows about offsets into
# a string. This builds a function for PyParse that accepts an
# offset.
@@ -1672,7 +1657,7 @@ def get_accelerator(keydefs, eventname):
keylist = keydefs.get(eventname)
# issue10940: temporary workaround to prevent hang with OS X Cocoa Tk 8.5
# if not keylist:
- if (not keylist) or (macosxSupport.runningAsOSXApp() and eventname in {
+ if (not keylist) or (macosxSupport.isCocoaTk() and eventname in {
"<<open-module>>",
"<<goto-line>>",
"<<change-indentwidth>>"}):
@@ -1699,19 +1684,20 @@ def fixwordbreaks(root):
tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]')
-def test():
- root = Tk()
+def _editor_window(parent): # htest #
+ # error if close master window first - timer event, after script
+ root = parent
fixwordbreaks(root)
- root.withdraw()
if sys.argv[1:]:
filename = sys.argv[1]
else:
filename = None
+ macosxSupport.setupApp(root, None)
edit = EditorWindow(root=root, filename=filename)
- edit.set_close_hook(root.quit)
edit.text.bind("<<close-all-windows>>", edit.close_event)
- root.mainloop()
- root.destroy()
+ # Does not stop error, neither does following
+ # edit.text.bind("<<close-window>>", edit.close_event)
if __name__ == '__main__':
- test()
+ from idlelib.idle_test.htest import run
+ run(_editor_window)