[Python-checkins] bpo-35208: Fix IDLE Squeezer line counting (GH-10449)

Tal Einat webhook-mailer at python.org
Mon Dec 24 07:05:54 EST 2018


https://github.com/python/cpython/commit/44a79cc5b3d1fb0c03c99077aa26def85ec26c67
commit: 44a79cc5b3d1fb0c03c99077aa26def85ec26c67
branch: master
author: Tal Einat <taleinat+github at gmail.com>
committer: GitHub <noreply at github.com>
date: 2018-12-24T14:05:51+02:00
summary:

bpo-35208: Fix IDLE Squeezer line counting (GH-10449)

files:
A Misc/NEWS.d/next/IDLE/2018-12-23-17-42-11.bpo-35208.J5NOg7.rst
M Lib/idlelib/NEWS.txt
M Lib/idlelib/idle_test/test_squeezer.py
M Lib/idlelib/squeezer.py

diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt
index 68862891f6af..3d93e91d3147 100644
--- a/Lib/idlelib/NEWS.txt
+++ b/Lib/idlelib/NEWS.txt
@@ -3,6 +3,8 @@ Released on 2019-10-20?
 ======================================
 
 
+bpo-35208: Squeezer now counts wrapped lines before newlines.
+
 bpo-35555: Gray out Code Context menu entry when it's not applicable.
 
 bpo-22703: Improve the Code Context and Zoom Height menu labels.
diff --git a/Lib/idlelib/idle_test/test_squeezer.py b/Lib/idlelib/idle_test/test_squeezer.py
index ca8b674cc236..da2c2dd50c65 100644
--- a/Lib/idlelib/idle_test/test_squeezer.py
+++ b/Lib/idlelib/idle_test/test_squeezer.py
@@ -1,4 +1,5 @@
 from collections import namedtuple
+from textwrap import dedent
 from tkinter import Text, Tk
 import unittest
 from unittest.mock import Mock, NonCallableMagicMock, patch, sentinel, ANY
@@ -77,6 +78,28 @@ def test_tab_width(self):
         self.check(expected=3, text='\t' * 6, linewidth=11, tabwidth=4)
         self.check(expected=2, text='\t' * 6, linewidth=13, tabwidth=4)
 
+    def test_empty_lines(self):
+        self.check(expected=1, text='\n', linewidth=80, tabwidth=8)
+        self.check(expected=2, text='\n\n', linewidth=80, tabwidth=8)
+        self.check(expected=10, text='\n' * 10, linewidth=80, tabwidth=8)
+
+    def test_long_line(self):
+        self.check(expected=3, text='a' * 200, linewidth=80, tabwidth=8)
+        self.check(expected=3, text='a' * 200 + '\n', linewidth=80, tabwidth=8)
+
+    def test_several_lines_different_lengths(self):
+        text = dedent("""\
+            13 characters
+            43 is the number of characters on this line
+
+            7 chars
+            13 characters""")
+        self.check(expected=5, text=text, linewidth=80, tabwidth=8)
+        self.check(expected=5, text=text + '\n', linewidth=80, tabwidth=8)
+        self.check(expected=6, text=text, linewidth=40, tabwidth=8)
+        self.check(expected=7, text=text, linewidth=20, tabwidth=8)
+        self.check(expected=11, text=text, linewidth=10, tabwidth=8)
+
 
 class SqueezerTest(unittest.TestCase):
     """Tests for the Squeezer class."""
diff --git a/Lib/idlelib/squeezer.py b/Lib/idlelib/squeezer.py
index f5aac813a159..8960356799a4 100644
--- a/Lib/idlelib/squeezer.py
+++ b/Lib/idlelib/squeezer.py
@@ -46,6 +46,14 @@ def count_lines_with_wrapping(s, linewidth=80, tabwidth=8):
 
         # deal with tab or newline
         if s[pos] == '\n':
+            # Avoid the `current_column == 0` edge-case, and while we're at it,
+            # don't bother adding 0.
+            if current_column > linewidth:
+                # If the current column was exactly linewidth, divmod would give
+                # (1,0), even though a new line hadn't yet been started. The same
+                # is true if length is any exact multiple of linewidth. Therefore,
+                # subtract 1 before dividing a non-empty line.
+                linecount += (current_column - 1) // linewidth
             linecount += 1
             current_column = 0
         else:
@@ -60,17 +68,6 @@ def count_lines_with_wrapping(s, linewidth=80, tabwidth=8):
 
         pos += 1 # after the tab or newline
 
-        # avoid divmod(-1, linewidth)
-        if current_column > 0:
-            # If the length was exactly linewidth, divmod would give (1,0),
-            # even though a new line hadn't yet been started. The same is true
-            # if length is any exact multiple of linewidth. Therefore, subtract
-            # 1 before doing divmod, and later add 1 to the column to
-            # compensate.
-            lines, column = divmod(current_column - 1, linewidth)
-            linecount += lines
-            current_column = column + 1
-
     # process remaining chars (no more tabs or newlines)
     current_column += len(s) - pos
     # avoid divmod(-1, linewidth)
@@ -106,7 +103,8 @@ def __init__(self, s, tags, numoflines, squeezer):
         # before the iomark
         self.base_text = editwin.per.bottom
 
-        button_text = "Squeezed text (%d lines)." % self.numoflines
+        line_plurality = "lines" if numoflines != 1 else "line"
+        button_text = f"Squeezed text ({numoflines} {line_plurality})."
         tk.Button.__init__(self, text, text=button_text,
                            background="#FFFFC0", activebackground="#FFFFE0")
 
diff --git a/Misc/NEWS.d/next/IDLE/2018-12-23-17-42-11.bpo-35208.J5NOg7.rst b/Misc/NEWS.d/next/IDLE/2018-12-23-17-42-11.bpo-35208.J5NOg7.rst
new file mode 100644
index 000000000000..d47806f62f46
--- /dev/null
+++ b/Misc/NEWS.d/next/IDLE/2018-12-23-17-42-11.bpo-35208.J5NOg7.rst
@@ -0,0 +1 @@
+Squeezer now properly counts wrapped lines before newlines.



More information about the Python-checkins mailing list