bpo-37530: simplify, optimize and clean up IDLE code context (GH-14675)

* Only create CodeContext instances for "real" editors windows, but
  not e.g. shell or output windows.
* Remove configuration update Tk event fired every second, by having
  the editor window ask its code context widget to update when
  necessary, i.e. upon font or highlighting updates.
* When code context isn't being shown, avoid having a Tk event fired
  every 100ms to check whether the code context needs to be updated.
* Use the editor window's getlineno() method where applicable.
* Update font of the code context widget before the main text widget
diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py
index 9b5364f..b972e3d 100644
--- a/Lib/idlelib/editor.py
+++ b/Lib/idlelib/editor.py
@@ -62,6 +62,8 @@
     filesystemencoding = sys.getfilesystemencoding()  # for file names
     help_url = None
 
+    allow_codecontext = True
+
     def __init__(self, flist=None, filename=None, key=None, root=None):
         # Delay import: runscript imports pyshell imports EditorWindow.
         from idlelib.runscript import ScriptBinding
@@ -247,6 +249,7 @@
         self.good_load = False
         self.set_indentation_params(False)
         self.color = None # initialized below in self.ResetColorizer
+        self.codecontext = None
         if filename:
             if os.path.exists(filename) and not os.path.isdir(filename):
                 if io.loadfile(filename):
@@ -312,8 +315,10 @@
         text.bind("<<refresh-calltip>>", ctip.refresh_calltip_event)
         text.bind("<<force-open-calltip>>", ctip.force_open_calltip_event)
         text.bind("<<zoom-height>>", self.ZoomHeight(self).zoom_height_event)
-        text.bind("<<toggle-code-context>>",
-                  self.CodeContext(self).toggle_code_context_event)
+        if self.allow_codecontext:
+            self.codecontext = self.CodeContext(self)
+            text.bind("<<toggle-code-context>>",
+                      self.codecontext.toggle_code_context_event)
 
     def _filename_to_unicode(self, filename):
         """Return filename as BMP unicode so displayable in Tk."""
@@ -773,6 +778,9 @@
         self._addcolorizer()
         EditorWindow.color_config(self.text)
 
+        if self.codecontext is not None:
+            self.codecontext.update_highlight_colors()
+
     IDENTCHARS = string.ascii_letters + string.digits + "_"
 
     def colorize_syntax_error(self, text, pos):
@@ -790,7 +798,12 @@
         "Update the text widgets' font if it is changed"
         # Called from configdialog.py
 
-        self.text['font'] = idleConf.GetFont(self.root, 'main','EditorWindow')
+        new_font = idleConf.GetFont(self.root, 'main', 'EditorWindow')
+        # Update the code context widget first, since its height affects
+        # the height of the text widget.  This avoids double re-rendering.
+        if self.codecontext is not None:
+            self.codecontext.update_font(new_font)
+        self.text['font'] = new_font
 
     def RemoveKeybindings(self):
         "Remove the keybindings before they are changed."