Tim Peters:

Smarter logic for finding a parse synch point.

Does a half to a fifth the work in normal cases; don't notice the speedup,
but makes  more breathing room for other extensions.

Speeds terrible cases by at least a factor of 10. "Terrible" == e.g. you put
""" at the start of Tkinter.py, undo it, zoom to the bottom, and start
typing in code.  Used to take about 8 seconds for ENTER to respond, now some
large fraction of a second.  The new code gets indented correctly, despite
that it all remains "string colored" until the colorizer catches up (after
which, ENTER appears instantaneous again).
diff --git a/Tools/idle/PyParse.py b/Tools/idle/PyParse.py
index 43e10b3..9c3ae5c 100644
--- a/Tools/idle/PyParse.py
+++ b/Tools/idle/PyParse.py
@@ -14,7 +14,22 @@
 _synchre = re.compile(r"""
     ^
     [ \t]*
-    (?: if | else | elif | while | def | class )
+    (?: if
+    |   for
+    |   while
+    |   else
+    |   def
+    |   return
+    |   assert
+    |   break
+    |   class
+    |   continue
+    |   elif
+    |   try
+    |   except
+    |   raise
+    |   import
+    )
     \b
 """, re.VERBOSE | re.MULTILINE).search
 
@@ -105,11 +120,14 @@
 
     # Return index of a good place to begin parsing, as close to the
     # end of the string as possible.  This will be the start of some
-    # popular stmt like "if" or "def".  Return None if none found.
+    # popular stmt like "if" or "def".  Return None if none found:
+    # the caller should pass more prior context then, if possible, or
+    # if not (the entire program text up until the point of interest
+    # has already been tried) pass 0 to set_lo.
     #
     # This will be reliable iff given a reliable is_char_in_string
-    # function, meaning that when it says "no", it's absolutely guaranteed
-    # that the char is not in a string.
+    # function, meaning that when it says "no", it's absolutely
+    # guaranteed that the char is not in a string.
     #
     # Ack, hack: in the shell window this kills us, because there's
     # no way to tell the differences between output, >>> etc and
@@ -117,28 +135,66 @@
     # look like it's in an unclosed paren!:
     # Python 1.5.2 (#0, Apr 13 1999, ...
 
-    def find_good_parse_start(self, use_ps1,
-                              is_char_in_string=None,
+    def find_good_parse_start(self, use_ps1, is_char_in_string=None,
+                              _rfind=string.rfind,
                               _synchre=_synchre):
         str, pos = self.str, None
         if use_ps1:
-            # hack for shell window
+            # shell window
             ps1 = '\n' + sys.ps1
-            i = string.rfind(str, ps1)
+            i = _rfind(str, ps1)
             if i >= 0:
                 pos = i + len(ps1)
+                # make it look like there's a newline instead
+                # of ps1 at the start -- hacking here once avoids
+                # repeated hackery later
                 self.str = str[:pos-1] + '\n' + str[pos:]
-        elif is_char_in_string:
-            # otherwise we can't be sure, so leave pos at None
-            i = 0
-            while 1:
-                m = _synchre(str, i)
-                if m:
-                    s, i = m.span()
-                    if not is_char_in_string(s):
-                        pos = s
-                else:
-                    break
+            return pos
+
+        # File window -- real work.
+        if not is_char_in_string:
+            # no clue -- make the caller pass everything
+            return None
+
+        # Peek back from the end for a good place to start,
+        # but don't try too often; pos will be left None, or
+        # bumped to a legitimate synch point.
+        limit = len(str)
+        for tries in range(5):
+            i = _rfind(str, ":\n", 0, limit)
+            if i < 0:
+                break
+            i = _rfind(str, '\n', 0, i) + 1  # start of colon line
+            m = _synchre(str, i, limit)
+            if m and not is_char_in_string(m.start()):
+                pos = m.start()
+                break
+            limit = i
+        if pos is None:
+            # Nothing looks like a block-opener, or stuff does
+            # but is_char_in_string keeps returning true; most likely
+            # we're in or near a giant string, the colorizer hasn't
+            # caught up enough to be helpful, or there simply *aren't*
+            # any interesting stmts.  In any of these cases we're
+            # going to have to parse the whole thing to be sure, so
+            # give it one last try from the start, but stop wasting
+            # time here regardless of the outcome.
+            m = _synchre(str)
+            if m and not is_char_in_string(m.start()):
+                pos = m.start()
+            return pos
+
+        # Peeking back worked; look forward until _synchre no longer
+        # matches.
+        i = pos + 1
+        while 1:
+            m = _synchre(str, i)
+            if m:
+                s, i = m.span()
+                if not is_char_in_string(s):
+                    pos = s
+            else:
+                break
         return pos
 
     # Throw away the start of the string.  Intended to be called with