summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/idlelib/editor.py25
-rw-r--r--Lib/idlelib/idle_test/test_squeezer.py17
-rw-r--r--Lib/idlelib/squeezer.py34
-rw-r--r--Misc/NEWS.d/next/IDLE/2019-08-24-22-00-33.bpo-37929.jb7523.rst1
4 files changed, 27 insertions, 50 deletions
diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py
index 35027da..793ed3a 100644
--- a/Lib/idlelib/editor.py
+++ b/Lib/idlelib/editor.py
@@ -10,6 +10,7 @@ import traceback
import webbrowser
from tkinter import *
+from tkinter.font import Font
from tkinter.ttk import Scrollbar
import tkinter.simpledialog as tkSimpleDialog
import tkinter.messagebox as tkMessageBox
@@ -120,14 +121,13 @@ class EditorWindow(object):
self.prompt_last_line = '' # Override in PyShell
self.text_frame = text_frame = Frame(top)
self.vbar = vbar = Scrollbar(text_frame, name='vbar')
- self.width = idleConf.GetOption('main', 'EditorWindow',
- 'width', type='int')
+ width = idleConf.GetOption('main', 'EditorWindow', 'width', type='int')
text_options = {
'name': 'text',
'padx': 5,
'wrap': 'none',
'highlightthickness': 0,
- 'width': self.width,
+ 'width': width,
'tabstyle': 'wordprocessor', # new in 8.5
'height': idleConf.GetOption(
'main', 'EditorWindow', 'height', type='int'),
@@ -154,6 +154,7 @@ class EditorWindow(object):
text.bind('<MouseWheel>', self.mousescroll)
text.bind('<Button-4>', self.mousescroll)
text.bind('<Button-5>', self.mousescroll)
+ text.bind('<Configure>', self.handle_winconfig)
text.bind("<<cut>>", self.cut)
text.bind("<<copy>>", self.copy)
text.bind("<<paste>>", self.paste)
@@ -211,6 +212,7 @@ class EditorWindow(object):
text['font'] = idleConf.GetFont(self.root, 'main', 'EditorWindow')
text.grid(row=1, column=1, sticky=NSEW)
text.focus_set()
+ self.set_width()
# usetabs true -> literal tab characters are used by indent and
# dedent cmds, possibly mixed with spaces if
@@ -338,6 +340,22 @@ class EditorWindow(object):
else:
self.update_menu_state('options', '*Line Numbers', 'disabled')
+ def handle_winconfig(self, event=None):
+ self.set_width()
+
+ def set_width(self):
+ text = self.text
+ inner_padding = sum(map(text.tk.getint, [text.cget('border'),
+ text.cget('padx')]))
+ pixel_width = text.winfo_width() - 2 * inner_padding
+
+ # Divide the width of the Text widget by the font width,
+ # which is taken to be the width of '0' (zero).
+ # http://www.tcl.tk/man/tcl8.6/TkCmd/text.htm#M21
+ zero_char_width = \
+ Font(text, font=text.cget('font')).measure('0')
+ self.width = pixel_width // zero_char_width
+
def _filename_to_unicode(self, filename):
"""Return filename as BMP unicode so displayable in Tk."""
# Decode bytes to unicode.
@@ -830,6 +848,7 @@ class EditorWindow(object):
# Finally, update the main text widget.
new_font = idleConf.GetFont(self.root, 'main', 'EditorWindow')
self.text['font'] = new_font
+ self.set_width()
def RemoveKeybindings(self):
"Remove the keybindings before they are changed."
diff --git a/Lib/idlelib/idle_test/test_squeezer.py b/Lib/idlelib/idle_test/test_squeezer.py
index 4e3da03..1af2ce8 100644
--- a/Lib/idlelib/idle_test/test_squeezer.py
+++ b/Lib/idlelib/idle_test/test_squeezer.py
@@ -82,18 +82,10 @@ class CountLinesTest(unittest.TestCase):
class SqueezerTest(unittest.TestCase):
"""Tests for the Squeezer class."""
- def tearDown(self):
- # Clean up the Squeezer class's reference to its instance,
- # to avoid side-effects from one test case upon another.
- if Squeezer._instance_weakref is not None:
- Squeezer._instance_weakref = None
-
def make_mock_editor_window(self, with_text_widget=False):
"""Create a mock EditorWindow instance."""
editwin = NonCallableMagicMock()
- # isinstance(editwin, PyShell) must be true for Squeezer to enable
- # auto-squeezing; in practice this will always be true.
- editwin.__class__ = PyShell
+ editwin.width = 80
if with_text_widget:
editwin.root = get_test_tk_root(self)
@@ -107,7 +99,6 @@ class SqueezerTest(unittest.TestCase):
if editor_window is None:
editor_window = self.make_mock_editor_window()
squeezer = Squeezer(editor_window)
- squeezer.get_line_width = Mock(return_value=80)
return squeezer
def make_text_widget(self, root=None):
@@ -143,8 +134,8 @@ class SqueezerTest(unittest.TestCase):
line_width=line_width,
expected=expected):
text = eval(text_code)
- squeezer.get_line_width.return_value = line_width
- self.assertEqual(squeezer.count_lines(text), expected)
+ with patch.object(editwin, 'width', line_width):
+ self.assertEqual(squeezer.count_lines(text), expected)
def test_init(self):
"""Test the creation of Squeezer instances."""
@@ -294,7 +285,6 @@ class SqueezerTest(unittest.TestCase):
"""Test the reload() class-method."""
editwin = self.make_mock_editor_window(with_text_widget=True)
squeezer = self.make_squeezer_instance(editwin)
- squeezer.load_font = Mock()
orig_auto_squeeze_min_lines = squeezer.auto_squeeze_min_lines
@@ -307,7 +297,6 @@ class SqueezerTest(unittest.TestCase):
Squeezer.reload()
self.assertEqual(squeezer.auto_squeeze_min_lines,
new_auto_squeeze_min_lines)
- squeezer.load_font.assert_called()
def test_reload_no_squeezer_instances(self):
"""Test that Squeezer.reload() runs without any instances existing."""
diff --git a/Lib/idlelib/squeezer.py b/Lib/idlelib/squeezer.py
index 032401f..be1538a 100644
--- a/Lib/idlelib/squeezer.py
+++ b/Lib/idlelib/squeezer.py
@@ -15,10 +15,8 @@ output written to the standard error stream ("stderr"), such as exception
messages and their tracebacks.
"""
import re
-import weakref
import tkinter as tk
-from tkinter.font import Font
import tkinter.messagebox as tkMessageBox
from idlelib.config import idleConf
@@ -203,8 +201,6 @@ class Squeezer:
This avoids IDLE's shell slowing down considerably, and even becoming
completely unresponsive, when very long outputs are written.
"""
- _instance_weakref = None
-
@classmethod
def reload(cls):
"""Load class variables from config."""
@@ -213,14 +209,6 @@ class Squeezer:
type="int", default=50,
)
- # Loading the font info requires a Tk root. IDLE doesn't rely
- # on Tkinter's "default root", so the instance will reload
- # font info using its editor windows's Tk root.
- if cls._instance_weakref is not None:
- instance = cls._instance_weakref()
- if instance is not None:
- instance.load_font()
-
def __init__(self, editwin):
"""Initialize settings for Squeezer.
@@ -241,9 +229,6 @@ class Squeezer:
# however, needs to make such changes.
self.base_text = editwin.per.bottom
- Squeezer._instance_weakref = weakref.ref(self)
- self.load_font()
-
# Twice the text widget's border width and internal padding;
# pre-calculated here for the get_line_width() method.
self.window_width_delta = 2 * (
@@ -298,24 +283,7 @@ class Squeezer:
Tabs are considered tabwidth characters long.
"""
- linewidth = self.get_line_width()
- return count_lines_with_wrapping(s, linewidth)
-
- def get_line_width(self):
- # The maximum line length in pixels: The width of the text
- # widget, minus twice the border width and internal padding.
- linewidth_pixels = \
- self.base_text.winfo_width() - self.window_width_delta
-
- # Divide the width of the Text widget by the font width,
- # which is taken to be the width of '0' (zero).
- # http://www.tcl.tk/man/tcl8.6/TkCmd/text.htm#M21
- return linewidth_pixels // self.zero_char_width
-
- def load_font(self):
- text = self.base_text
- self.zero_char_width = \
- Font(text, font=text.cget('font')).measure('0')
+ return count_lines_with_wrapping(s, self.editwin.width)
def squeeze_current_text_event(self, event):
"""squeeze-current-text event handler
diff --git a/Misc/NEWS.d/next/IDLE/2019-08-24-22-00-33.bpo-37929.jb7523.rst b/Misc/NEWS.d/next/IDLE/2019-08-24-22-00-33.bpo-37929.jb7523.rst
new file mode 100644
index 0000000..d627b2d
--- /dev/null
+++ b/Misc/NEWS.d/next/IDLE/2019-08-24-22-00-33.bpo-37929.jb7523.rst
@@ -0,0 +1 @@
+IDLE Settings dialog now closes properly when there is no shell window.