]> granicus.if.org Git - python/commitdiff
Issue #13051: Fixed recursion errors in large or resized curses.textpad.Textbox.
authorSerhiy Storchaka <storchaka@gmail.com>
Wed, 28 Dec 2016 08:16:06 +0000 (10:16 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Wed, 28 Dec 2016 08:16:06 +0000 (10:16 +0200)
Based on patch by Tycho Andersen.

Lib/curses/textpad.py
Lib/test/test_curses.py
Misc/ACKS
Misc/NEWS

index 2b4b4cb669f53523b2db42bbb629e91c551ba3be..2079953a06614ba7ffc8f669ed9849f9b4d2ceb4 100644 (file)
@@ -43,16 +43,20 @@ class Textbox:
     def __init__(self, win, insert_mode=False):
         self.win = win
         self.insert_mode = insert_mode
-        (self.maxy, self.maxx) = win.getmaxyx()
-        self.maxy = self.maxy - 1
-        self.maxx = self.maxx - 1
+        self._update_max_yx()
         self.stripspaces = 1
         self.lastcmd = None
         win.keypad(1)
 
+    def _update_max_yx(self):
+        maxy, maxx = self.win.getmaxyx()
+        self.maxy = maxy - 1
+        self.maxx = maxx - 1
+
     def _end_of_line(self, y):
         """Go to the location of the first blank on the given line,
         returning the index of the last non-blank character."""
+        self._update_max_yx()
         last = self.maxx
         while True:
             if curses.ascii.ascii(self.win.inch(y, last)) != curses.ascii.SP:
@@ -64,8 +68,10 @@ class Textbox:
         return last
 
     def _insert_printable_char(self, ch):
+        self._update_max_yx()
         (y, x) = self.win.getyx()
-        if y < self.maxy or x < self.maxx:
+        backyx = None
+        while y < self.maxy or x < self.maxx:
             if self.insert_mode:
                 oldch = self.win.inch()
             # The try-catch ignores the error we trigger from some curses
@@ -75,14 +81,20 @@ class Textbox:
                 self.win.addch(ch)
             except curses.error:
                 pass
-            if self.insert_mode:
-                (backy, backx) = self.win.getyx()
-                if curses.ascii.isprint(oldch):
-                    self._insert_printable_char(oldch)
-                    self.win.move(backy, backx)
+            if not self.insert_mode or not curses.ascii.isprint(oldch):
+                break
+            ch = oldch
+            (y, x) = self.win.getyx()
+            # Remember where to put the cursor back since we are in insert_mode
+            if backyx is None:
+                backyx = y, x
+
+        if backyx is not None:
+            self.win.move(*backyx)
 
     def do_command(self, ch):
         "Process a single editing command."
+        self._update_max_yx()
         (y, x) = self.win.getyx()
         self.lastcmd = ch
         if curses.ascii.isprint(ch):
@@ -148,6 +160,7 @@ class Textbox:
     def gather(self):
         "Collect and return the contents of the window."
         result = ""
+        self._update_max_yx()
         for y in range(self.maxy+1):
             self.win.move(y, 0)
             stop = self._end_of_line(y)
index 25284ad522b6fc53d303a43b5f17d44af684668a..14ba87f8caae9016ca49482a9c99fd3b7e4f6390 100644 (file)
@@ -27,6 +27,7 @@ requires('curses')
 curses = import_module('curses')
 import_module('curses.panel')
 import_module('curses.ascii')
+import_module('curses.textpad')
 
 def requires_curses_func(name):
     return unittest.skipUnless(hasattr(curses, name),
@@ -392,6 +393,14 @@ class TestCurses(unittest.TestCase):
         human_readable_signature = stdscr.addch.__doc__.split("\n")[0]
         self.assertIn("[y, x,]", human_readable_signature)
 
+    def test_issue13051(self):
+        stdscr = self.stdscr
+        box = curses.textpad.Textbox(stdscr, insert_mode=True)
+        lines, cols = stdscr.getmaxyx()
+        stdscr.resize(lines-2, cols-2)
+        # this may cause infinite recursion, leading to a RuntimeError
+        box._insert_printable_char('a')
+
 
 class MiscTests(unittest.TestCase):
 
index 66c36608af78b01f0636b7882d9da86cfbd14642..35b26113acc72d0f215f235bd5e46802544e92a0 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -41,6 +41,7 @@ A. Amoroso
 Mark Anacker
 Shashwat Anand
 Anders Andersen
+Tycho Andersen
 John Anderson
 Pehr Anderson
 Erik Andersén
index 9c972b1e32f890cf75ed284be77d927621dab7c7..11ec5f5811ec094935ac01fc76c77d62a2bf7957 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -140,6 +140,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #13051: Fixed recursion errors in large or resized
+  curses.textpad.Textbox.  Based on patch by Tycho Andersen.
+
 - Issue #9770: curses.ascii predicates now work correctly with negative
   integers.