From a803865b00b8196ceb251b563502a68bad770c47 Mon Sep 17 00:00:00 2001 From: Tal Einat Date: Sat, 10 Nov 2018 09:28:42 +0200 Subject: [PATCH 1/8] bpo-35208: Fix Squeezer line counting logic --- Lib/idlelib/idle_test/test_squeezer.py | 23 +++++++++++++++++++++++ Lib/idlelib/squeezer.py | 8 +++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Lib/idlelib/idle_test/test_squeezer.py b/Lib/idlelib/idle_test/test_squeezer.py index ca8b674cc236dd..da2c2dd50c65ad 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 f5aac813a15933..926115c3d3d2b8 100644 --- a/Lib/idlelib/squeezer.py +++ b/Lib/idlelib/squeezer.py @@ -46,7 +46,13 @@ def count_lines_with_wrapping(s, linewidth=80, tabwidth=8): # deal with tab or newline if s[pos] == '\n': - linecount += 1 + # 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, except if the current column is 0. + linecount += 1 + ( + ((current_column - 1) // linewidth) if current_column > 0 else 0 + ) current_column = 0 else: assert s[pos] == '\t' From 01fa7465f6c5fef004c780aaac28df17dd43db47 Mon Sep 17 00:00:00 2001 From: Tal Einat Date: Sat, 10 Nov 2018 09:31:37 +0200 Subject: [PATCH 2/8] bpo-35208: Fix squeezed text label to "(1 line)" from "(1 lines)" --- Lib/idlelib/squeezer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/idlelib/squeezer.py b/Lib/idlelib/squeezer.py index 926115c3d3d2b8..8a79553ad66ffe 100644 --- a/Lib/idlelib/squeezer.py +++ b/Lib/idlelib/squeezer.py @@ -112,7 +112,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") From 6f888203e963e356c037db23d4be8f57ca07081a Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sun, 23 Dec 2018 17:01:37 -0500 Subject: [PATCH 3/8] Remove useless code skipped after newline and no net effect after tab. All tests continue to pass. --- Lib/idlelib/squeezer.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Lib/idlelib/squeezer.py b/Lib/idlelib/squeezer.py index 8a79553ad66ffe..17c3ba89349b65 100644 --- a/Lib/idlelib/squeezer.py +++ b/Lib/idlelib/squeezer.py @@ -66,17 +66,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) From bd59f461ccf54703eb8cd921b985a8bf88b2150d Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sun, 23 Dec 2018 17:34:01 -0500 Subject: [PATCH 4/8] Only adjust for linewrapping when there are wrapped lines. Tests continue to pass. --- Lib/idlelib/squeezer.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/squeezer.py b/Lib/idlelib/squeezer.py index 17c3ba89349b65..6d96cc32698745 100644 --- a/Lib/idlelib/squeezer.py +++ b/Lib/idlelib/squeezer.py @@ -49,10 +49,10 @@ def count_lines_with_wrapping(s, linewidth=80, tabwidth=8): # 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, except if the current column is 0. - linecount += 1 + ( - ((current_column - 1) // linewidth) if current_column > 0 else 0 - ) + # subtract 1 before dividing a non-empty line. + if current_column > linewidth: # Don't bother adding 0. + linecount += (current_column - 1) // linewidth + linecount += 1 current_column = 0 else: assert s[pos] == '\t' From a75a6d1df7753aeaeea59f26fcde8e6e3a05b981 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sun, 23 Dec 2018 17:42:53 -0500 Subject: [PATCH 5/8] Add blurb. --- Misc/NEWS.d/next/IDLE/2018-12-23-17-42-11.bpo-35208.J5NOg7.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/IDLE/2018-12-23-17-42-11.bpo-35208.J5NOg7.rst 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 00000000000000..3936731bfcfe85 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2018-12-23-17-42-11.bpo-35208.J5NOg7.rst @@ -0,0 +1 @@ +Squeezer now counts wrapped lines before newlines. From 03f04a04c6fb5dbfb50db32946f4eeb2a958b714 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sun, 23 Dec 2018 17:44:00 -0500 Subject: [PATCH 6/8] Add idlelib news item. --- Lib/idlelib/NEWS.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 68862891f6af79..3d93e91d314759 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. From 28e311edbf8bae0181584c68988d797b42319986 Mon Sep 17 00:00:00 2001 From: Tal Einat Date: Mon, 24 Dec 2018 13:31:27 +0200 Subject: [PATCH 7/8] update change description in blurb --- Misc/NEWS.d/next/IDLE/2018-12-23-17-42-11.bpo-35208.J5NOg7.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 3936731bfcfe85..d47806f62f4659 100644 --- 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 @@ -1 +1 @@ -Squeezer now counts wrapped lines before newlines. +Squeezer now properly counts wrapped lines before newlines. From 9a1476431c187ab81d345bd34d2f81426f6d7f0f Mon Sep 17 00:00:00 2001 From: Tal Einat Date: Mon, 24 Dec 2018 13:33:23 +0200 Subject: [PATCH 8/8] improve comments in count_lines_with_wrapping() --- Lib/idlelib/squeezer.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/squeezer.py b/Lib/idlelib/squeezer.py index 6d96cc32698745..8960356799a480 100644 --- a/Lib/idlelib/squeezer.py +++ b/Lib/idlelib/squeezer.py @@ -46,11 +46,13 @@ def count_lines_with_wrapping(s, linewidth=80, tabwidth=8): # deal with tab or newline if s[pos] == '\n': - # 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. - if current_column > linewidth: # Don't bother adding 0. + # 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