Exemple #1
0
    def __init__(self, master=None, **kwargs):
        """
        Constructor.

        Get default settings from user's IDLE configuration.
        """
        currentTheme = idleConf.CurrentTheme()
        textcf = {
            'padx': 5,
            'wrap': 'word',
            'undo': 'True',
            'foreground': idleConf.GetHighlight(
                currentTheme, 'normal', fgBg='fg'),
            'background': idleConf.GetHighlight(
                currentTheme, 'normal', fgBg='bg'),
            'highlightcolor': idleConf.GetHighlight(
                currentTheme, 'hilite', fgBg='fg'),
            'highlightbackground': idleConf.GetHighlight(
                currentTheme, 'hilite', fgBg='bg'),
            'insertbackground': idleConf.GetHighlight(
                currentTheme, 'cursor', fgBg='fg'),
            'width': idleConf.GetOption('main', 'EditorWindow', 'width'),
            'height': idleConf.GetOption('main', 'EditorWindow', 'height'),
        }
        fontWeight = 'normal'
        if idleConf.GetOption('main', 'EditorWindow', 'font-bold', type='bool'):
            fontWeight = 'bold'
        textcf['font'] = (idleConf.GetOption('main', 'EditorWindow', 'font'),
                          idleConf.GetOption('main', 'EditorWindow',
                                             'font-size'),
                          fontWeight)
        # override defaults with any user-specified settings
        textcf.update(kwargs)
        ScrolledText.__init__(self, master, **textcf)
Exemple #2
0
 def __init__(self, master=None, **kwargs):
     # get default settings from user's IDLE configuration
     currentTheme = idleConf.CurrentTheme()
     textcf = dict(padx=5,
                   wrap='word',
                   undo='True',
                   foreground=idleConf.GetHighlight(currentTheme,
                                                    'normal',
                                                    fgBg='fg'),
                   background=idleConf.GetHighlight(currentTheme,
                                                    'normal',
                                                    fgBg='bg'),
                   highlightcolor=idleConf.GetHighlight(currentTheme,
                                                        'hilite',
                                                        fgBg='fg'),
                   highlightbackground=idleConf.GetHighlight(currentTheme,
                                                             'hilite',
                                                             fgBg='bg'),
                   insertbackground=idleConf.GetHighlight(currentTheme,
                                                          'cursor',
                                                          fgBg='fg'),
                   width=idleConf.GetOption('main', 'EditorWindow',
                                            'width'),
                   height=idleConf.GetOption('main', 'EditorWindow',
                                             'height'))
     fontWeight = 'normal'
     if idleConf.GetOption('main', 'EditorWindow', 'font-bold',
                           type='bool'):
         fontWeight = 'bold'
     textcf['font'] = (idleConf.GetOption('main', 'EditorWindow', 'font'),
                       idleConf.GetOption('main', 'EditorWindow',
                                          'font-size'), fontWeight)
     # override defaults with any user-specified settings
     textcf.update(kwargs)
     ScrolledText.__init__(self, master, **textcf)
Exemple #3
0
 def drawtext(self):
     textx = self.x+20-1
     texty = self.y-1
     labeltext = self.item.GetLabelText()
     if labeltext:
         id = self.canvas.create_text(textx, texty, anchor="nw",
                                      text=labeltext)
         self.canvas.tag_bind(id, "<1>", self.select)
         self.canvas.tag_bind(id, "<Double-1>", self.flip)
         x0, y0, x1, y1 = self.canvas.bbox(id)
         textx = max(x1, 200) + 10
     text = self.item.GetText() or "<no text>"
     try:
         self.entry
     except AttributeError:
         pass
     else:
         self.edit_finish()
     try:
         label = self.label
     except AttributeError:
         # padding carefully selected (on Windows) to match Entry widget:
         self.label = Label(self.canvas, text=text, bd=0, padx=2, pady=2)
     theme = idleConf.GetOption('main','Theme','name')
     if self.selected:
         self.label.configure(idleConf.GetHighlight(theme, 'hilite'))
     else:
         self.label.configure(idleConf.GetHighlight(theme, 'normal'))
     id = self.canvas.create_window(textx, texty,
                                    anchor="nw", window=self.label)
     self.label.bind("<1>", self.select_or_edit)
     self.label.bind("<Double-1>", self.flip)
     self.text_id = id
 def LoadTagDefs(self):
     ColorDelegator.LoadTagDefs(self)
     theme = idleConf.GetOption('main', 'Theme', 'name')
     self.tagdefs.update({'stdin': {'background': None,'foreground': None},'stdout': idleConf.GetHighlight(theme, 'stdout'),
        'stderr': idleConf.GetHighlight(theme, 'stderr'),
        'console': idleConf.GetHighlight(theme, 'console')
        })
     return
 def ResetColorizer(self):
     """Update the colour theme"""
     self._rmcolorizer()
     self._addcolorizer()
     theme = idleConf.GetOption('main', 'Theme', 'name')
     normal_colors = idleConf.GetHighlight(theme, 'normal')
     cursor_color = idleConf.GetHighlight(theme, 'cursor', fgBg='fg')
     select_colors = idleConf.GetHighlight(theme, 'hilite')
     self.text.config(foreground=normal_colors['foreground'], background=normal_colors['background'], insertbackground=cursor_color, selectforeground=select_colors['foreground'], selectbackground=select_colors['background'])
 def LoadTagDefs(self):
     ColorDelegator.LoadTagDefs(self)
     theme = idleConf.GetOption('main','Theme','name')
     self.tagdefs.update({
         "stdin": {'background':None,'foreground':None},
         "stdout": idleConf.GetHighlight(theme, "stdout"),
         "stderr": idleConf.GetHighlight(theme, "stderr"),
         "console": idleConf.GetHighlight(theme, "console"),
     })
    def show_find_marks(self):
        # Get the highlight colors for 'hit'
        # Do this here (and not in __init__) for color config changes to take
        # effect immediately
        currentTheme = idleConf.CurrentTheme()
        mark_fg = idleConf.GetHighlight(currentTheme, 'hit', fgBg='fg')
        mark_bg = idleConf.GetHighlight(currentTheme, 'hit', fgBg='bg')

        self.text.tag_configure("findmark",
                                foreground=mark_fg,
                                background=mark_bg)
Exemple #8
0
 def init(self, flist):
     self.flist = flist
     # reset pyclbr
     pyclbr._modules.clear()
     # create top
     # NOTE: later we will be passed in container, rather than creating it
     self.top = top = flist.new_container(own_window=True)
     self.top.add_component(self)
     top.top.bind("<Escape>", self.close)
     if self._htest:  # place dialog below parent if running htest
         top.top.geometry(
             "+%d+%d" %
             (flist.root.winfo_rootx(), flist.root.winfo_rooty() + 200))
     top.top.focus_set()
     # create scrolled canvas
     theme = idleConf.CurrentTheme()
     background = idleConf.GetHighlight(theme, 'normal')['background']
     sc = ScrolledCanvas(top.w,
                         bg=background,
                         highlightthickness=0,
                         takefocus=1)
     sc.frame.pack(expand=1, fill="both")
     item = self.rootnode()
     self.node = node = TreeNode(sc.canvas, None, item)
     node.update()
     node.expand()
Exemple #9
0
 def init(self, flist):
     self.flist = flist
     # reset pyclbr
     pyclbr._modules.clear()
     # create top
     self.top = top = ListedToplevel(flist.root)
     top.protocol("WM_DELETE_WINDOW", self.close)
     top.bind("<Escape>", self.close)
     if self._htest:  # place dialog below parent if running htest
         top.geometry(
             "+%d+%d" %
             (flist.root.winfo_rootx(), flist.root.winfo_rooty() + 200))
     self.settitle()
     top.focus_set()
     # create scrolled canvas
     theme = idleConf.GetOption('main', 'Theme', 'name')
     background = idleConf.GetHighlight(theme, 'normal')['background']
     sc = ScrolledCanvas(top,
                         bg=background,
                         highlightthickness=0,
                         takefocus=1)
     sc.frame.pack(expand=1, fill="both")
     item = self.rootnode()
     self.node = node = TreeNode(sc.canvas, None, item)
     node.update()
     node.expand()
    def PaintThemeSample(self):
        if self.themeIsBuiltin.get():
            theme = self.builtinTheme.get()
        else:
            theme = self.customTheme.get()
        for elementTitle in self.themeElements.keys():
            element = self.themeElements[elementTitle][0]
            colours = idleConf.GetHighlight(theme, element)
            if element == 'cursor':
                colours['background'] = idleConf.GetHighlight(theme, 'normal', fgBg='bg')
            if theme in self.changedItems['highlight'].keys():
                themeDict = self.changedItems['highlight'][theme]
                if element + '-foreground' in themeDict:
                    colours['foreground'] = themeDict[element + '-foreground']
                if element + '-background' in themeDict:
                    colours['background'] = themeDict[element + '-background']
            self.textHighlightSample.tag_config(element, **colours)

        self.SetColourSample()
Exemple #11
0
def color_config(text):  # Called from htest, Editor, and Turtle Demo.
    '''Set color opitons of Text widget.

    Should be called whenever ColorDelegator is called.
    '''
    # Not automatic because ColorDelegator does not know 'text'.
    theme = idleConf.CurrentTheme()
    normal_colors = idleConf.GetHighlight(theme, 'normal')
    cursor_color = idleConf.GetHighlight(theme, 'cursor', fgBg='fg')
    select_colors = idleConf.GetHighlight(theme, 'hilite')
    text.config(
        foreground=normal_colors['foreground'],
        background=normal_colors['background'],
        insertbackground=cursor_color,
        selectforeground=select_colors['foreground'],
        selectbackground=select_colors['background'],
    )
    if TkVersion >= 8.5:
        text.config(inactiveselectbackground=select_colors['background'])
    def set_subcode_colors(self):
        # This is a HACK to allow for sane coloring with other
        # color themes. Patches are welcome!
        from . import SubCode
        theme = idleConf.GetOption('main', 'Theme', 'name')
        normal_colors = idleConf.GetHighlight(theme, 'normal')
        background = normal_colors['background']

        def rgb_h2d(c):
            # Take a '#RRGGBB' and convert to integer tuple
            R = c[1:3]
            G = c[3:5]
            B = c[5:7]
            return tuple([int(x, 16) for x in (R, G, B)])

        def rgb_d2h(c):
            # (R, B, G) -> '#RRGGBB'
            c = [min((255, int(x))) for x in c]
            c = [max((0, int(x))) for x in c]
            return '#%02X%02X%02X' % tuple(c)

        def colorhack(rgb, target):
            # apply some DC offset and "gamma" correction
            R, G, B = map(float, rgb)
            mR, mG, mB = target
            m = lambda x, y: (x + y[0])**y[1] if x < 128 else (x - y[0])**(
                1 / y[1])
            R = m(R, mR)
            G = m(G, mG)
            B = m(B, mB)
            return (R, G, B)

        def average(a, b):
            return [(x[0] + x[1]) / 2.0 for x in zip(a, b)]

        BACK = rgb_h2d(background)

        a = (10, 1.03)
        SubCode.SUBCODE_BACKGROUND = rgb_d2h(colorhack(BACK, (a, a, a)))

        a = (10, 1.019)
        b = (10, .98)
        c = colorhack(BACK, (a, b, a))
        HL = rgb_d2h(c)
        SubCode.SUBCODE_HIGHLIGHT = HL

        d = average(BACK, c)
        SubCode.SUBCODE_HIGHLIGHT_OUT = rgb_d2h(d)

        self.tag_config('ACTIVE', background=SUBCODE_HIGHLIGHT)
 def remote_stack_viewer(self):
     from idlelib import RemoteObjectBrowser
     oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
     if oid is None:
         self.tkconsole.root.bell()
         return
     item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
     from idlelib.TreeWidget import ScrolledCanvas, TreeNode
     top = Toplevel(self.tkconsole.root)
     theme = idleConf.GetOption('main','Theme','name')
     background = idleConf.GetHighlight(theme, 'normal')['background']
     sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
     sc.frame.pack(expand=1, fill="both")
     node = TreeNode(sc.canvas, None, item)
     node.expand()
Exemple #14
0
    def LoadTagDefs(self):
        theme = idleConf.GetOption('main','Theme','name')
        self.tagdefs = {
            "COMMENT": idleConf.GetHighlight(theme, "comment"),
            "KEYWORD": idleConf.GetHighlight(theme, "keyword"),
            "BUILTIN": idleConf.GetHighlight(theme, "builtin"),
            "STRING": idleConf.GetHighlight(theme, "string"),
            "DEFINITION": idleConf.GetHighlight(theme, "definition"),
            "SYNC": {'background':None,'foreground':None},
            "TODO": {'background':None,'foreground':None},
            "BREAK": idleConf.GetHighlight(theme, "break"),
            "ERROR": idleConf.GetHighlight(theme, "error"),
            # The following is used by ReplaceDialog:
            "hit": idleConf.GetHighlight(theme, "hit"),
            }

        if DEBUG: print('tagdefs',self.tagdefs)
    def nearest(self):
        """ Enter ClassDefBrowser """
        # scroll textln to the nearest keyword found in text
        text = self.text
        textln = self.textln

        text_insert, text_col = sp(text.index(INSERT))

        text_end, col = sp(text.index(END))
        text_end -= 1
        text_top = (text.yview()[0] * text_end)
        text_bot = (text.yview()[1] * text_end)

        if text_top <= text_insert <= text_bot:
            pass
        else:
            text_insert = round((text_bot + text_top) / 2.0)
            for i in reversed(self.taglines):
                if i[0] <= text_insert:
                    text_insert = i[0]
                    break

        n = 0
        for n, i in enumerate(self.taglines):
            if i[0] > text_insert:
                target_line = n
                break
        else:
            target_line = n + 1

        textln.tag_add("NEAREST", '%i.0' % target_line,
                       '%i.0' % (target_line + 1))
        theme = idleConf.GetOption('main', 'Theme', 'name')
        hilite = idleConf.GetHighlight(theme, "hilite")
        textln.tag_configure("NEAREST", **hilite)
        textln.tag_raise('NEAREST')

        # place cursor at beginning of line text
        tline = min(target_line - 1, len(self.taglines) - 1)
        if self.taglines:
            origline, txt = self.taglines[tline]
            text_col = txt.find(txt.strip())
            textln.mark_set(INSERT, '%i.%i' % (target_line, text_col))

        offset = text_insert - round(text_top) - 1
        textln.yview(target_line - offset)

        textln.focus_set()
Exemple #16
0
 def init(self, flist):
     self.flist = flist
     pyclbr._modules.clear()
     self.top = top = ListedToplevel(flist.root)
     top.protocol('WM_DELETE_WINDOW', self.close)
     top.bind('<Escape>', self.close)
     self.settitle()
     top.focus_set()
     theme = idleConf.GetOption('main', 'Theme', 'name')
     background = idleConf.GetHighlight(theme, 'normal')['background']
     sc = ScrolledCanvas(top, bg=background, highlightthickness=0, takefocus=1)
     sc.frame.pack(expand=1, fill='both')
     item = self.rootnode()
     self.node = node = TreeNode(sc.canvas, None, item)
     node.update()
     node.expand()
     return
Exemple #17
0
 def LoadTagDefs(self):
     theme = idleConf.GetOption('main', 'Theme', 'name')
     self.tagdefs = {
         'COMMENT': idleConf.GetHighlight(theme, 'comment'),
         'KEYWORD': idleConf.GetHighlight(theme, 'keyword'),
         'BUILTIN': idleConf.GetHighlight(theme, 'builtin'),
         'STRING': idleConf.GetHighlight(theme, 'string'),
         'DEFINITION': idleConf.GetHighlight(theme, 'definition'),
         'SYNC': {
             'background': None,
             'foreground': None
         },
         'TODO': {
             'background': None,
             'foreground': None
         },
         'BREAK': idleConf.GetHighlight(theme, 'break'),
         'ERROR': idleConf.GetHighlight(theme, 'error'),
         'hit': idleConf.GetHighlight(theme, 'hit')
     }
     if DEBUG:
         print 'tagdefs', self.tagdefs
     return
Exemple #18
0
    def LoadTagDefs(self):
        theme = idleConf.CurrentTheme()
        font = idleConf.GetOption('main', 'EditorWindow', 'font')
        self.tagdefs = {
            "COMMENT": idleConf.GetHighlight(theme, "comment"),
            "KEYWORD": idleConf.GetHighlight(theme, "keyword"),
            "BUILTIN": idleConf.GetHighlight(theme, "builtin"),
            "STRING": idleConf.GetHighlight(theme, "string"),
            "DEFINITION": idleConf.GetHighlight(theme, "definition"),
            "SYNC": {
                'background': None,
                'foreground': None
            },
            "TODO": {
                'background': None,
                'foreground': None
            },
            "ERROR": idleConf.GetHighlight(theme, "error"),
            # The following is used by ReplaceDialog:
            "hit": idleConf.GetHighlight(theme, "hit"),
        }

        if DEBUG: print 'tagdefs', self.tagdefs

        try:
            lang = getattr(__import__('languages' + self.ext), self.ext[1:])
            if hasattr(lang, 'append_tags'):
                for key, value in lang.append_tags.items():
                    self.tagdefs[key] = value
        except (ImportError, AttributeError):
            pass

        def _style(string):
            list_ = []
            for c in string:
                if c == 'b':
                    list_.append('bold')
                elif c == 'i':
                    list_.append('italic')
                elif c == 'u':
                    list_.append('underline')
                elif c == 's':
                    list_.append('overstrike')

            return (font, 10, ' '.join(list_))

        try:
            alttag = getattr(__import__('languages.' + theme), theme)
            if hasattr(alttag, 'append_tags'):
                for key, value in alttag.append_tags.items():
                    if 'font' in value:
                        if isinstance(value['font'], str):
                            value['font'] = _style(value['font'])
                    else:
                        value['font'] = (font, 10, '')

                    self.tagdefs[key] = value

            for xtag, atag in ALTERNATE_TAGS.items():
                if xtag not in self.tagdefs:
                    if atag is None:
                        self.tagdefs[xtag] = {
                            'foreground': None,
                            'background': None
                        }
                    else:
                        self.tagdefs[xtag] = dict(self.tagdefs[atag])

            if hasattr(alttag, 'read_twice'):
                self.read_twice = alttag.read_twice
        except (ImportError, AttributeError) as e:
            pass
class ParenMatch:
    """Highlight matching parentheses

    There are three supported style of paren matching, based loosely
    on the Emacs options.  The style is select based on the
    HILITE_STYLE attribute; it can be changed used the set_style
    method.

    The supported styles are:

    default -- When a right paren is typed, highlight the matching
        left paren for 1/2 sec.

    expression -- When a right paren is typed, highlight the entire
        expression from the left paren to the right paren.

    TODO:
        - extend IDLE with configuration dialog to change options
        - implement rest of Emacs highlight styles (see below)
        - print mismatch warning in IDLE status window

    Note: In Emacs, there are several styles of highlight where the
    matching paren is highlighted whenever the cursor is immediately
    to the right of a right paren.  I don't know how to do that in Tk,
    so I haven't bothered.
    """
    menudefs = [('edit', [
        ("Show surrounding parens", "<<flash-paren>>"),
    ])]
    STYLE = idleConf.GetOption('extensions',
                               'ParenMatch',
                               'style',
                               default='expression')
    FLASH_DELAY = idleConf.GetOption('extensions',
                                     'ParenMatch',
                                     'flash-delay',
                                     type='int',
                                     default=500)
    HILITE_CONFIG = idleConf.GetHighlight(idleConf.CurrentTheme(), 'hilite')
    BELL = idleConf.GetOption('extensions',
                              'ParenMatch',
                              'bell',
                              type='bool',
                              default=1)

    RESTORE_VIRTUAL_EVENT_NAME = "<<parenmatch-check-restore>>"
    # We want the restore event be called before the usual return and
    # backspace events.
    RESTORE_SEQUENCES = ("<KeyPress>", "<ButtonPress>", "<Key-Return>",
                         "<Key-BackSpace>")

    def __init__(self, editwin):
        self.editwin = editwin
        self.text = editwin.text
        # Bind the check-restore event to the function restore_event,
        # so that we can then use activate_restore (which calls event_add)
        # and deactivate_restore (which calls event_delete).
        editwin.text.bind(self.RESTORE_VIRTUAL_EVENT_NAME, self.restore_event)
        self.counter = 0
        self.is_restore_active = 0
        self.set_style(self.STYLE)

    def activate_restore(self):
        if not self.is_restore_active:
            for seq in self.RESTORE_SEQUENCES:
                self.text.event_add(self.RESTORE_VIRTUAL_EVENT_NAME, seq)
            self.is_restore_active = True

    def deactivate_restore(self):
        if self.is_restore_active:
            for seq in self.RESTORE_SEQUENCES:
                self.text.event_delete(self.RESTORE_VIRTUAL_EVENT_NAME, seq)
            self.is_restore_active = False

    def set_style(self, style):
        self.STYLE = style
        if style == "default":
            self.create_tag = self.create_tag_default
            self.set_timeout = self.set_timeout_last
        elif style == "expression":
            self.create_tag = self.create_tag_expression
            self.set_timeout = self.set_timeout_none

    def flash_paren_event(self, event):
        indices = HyperParser(self.editwin,
                              "insert").get_surrounding_brackets()
        if indices is None:
            self.warn_mismatched()
            return
        self.activate_restore()
        self.create_tag(indices)
        self.set_timeout_last()

    def paren_closed_event(self, event):
        # If it was a shortcut and not really a closing paren, quit.
        closer = self.text.get("insert-1c")
        if closer not in _openers:
            return
        hp = HyperParser(self.editwin, "insert-1c")
        if not hp.is_in_code():
            return
        indices = hp.get_surrounding_brackets(_openers[closer], True)
        if indices is None:
            self.warn_mismatched()
            return
        self.activate_restore()
        self.create_tag(indices)
        self.set_timeout()

    def restore_event(self, event=None):
        self.text.tag_delete("paren")
        self.deactivate_restore()
        self.counter += 1  # disable the last timer, if there is one.

    def handle_restore_timer(self, timer_count):
        if timer_count == self.counter:
            self.restore_event()

    def warn_mismatched(self):
        if self.BELL:
            self.text.bell()

    # any one of the create_tag_XXX methods can be used depending on
    # the style

    def create_tag_default(self, indices):
        """Highlight the single paren that matches"""
        self.text.tag_add("paren", indices[0])
        self.text.tag_config("paren", self.HILITE_CONFIG)

    def create_tag_expression(self, indices):
        """Highlight the entire expression"""
        if self.text.get(indices[1]) in (')', ']', '}'):
            rightindex = indices[1] + "+1c"
        else:
            rightindex = indices[1]
        self.text.tag_add("paren", indices[0], rightindex)
        self.text.tag_config("paren", self.HILITE_CONFIG)

    # any one of the set_timeout_XXX methods can be used depending on
    # the style

    def set_timeout_none(self):
        """Highlight will remain until user input turns it off
        or the insert has moved"""
        # After CHECK_DELAY, call a function which disables the "paren" tag
        # if the event is for the most recent timer and the insert has changed,
        # or schedules another call for itself.
        self.counter += 1

        def callme(callme,
                   self=self,
                   c=self.counter,
                   index=self.text.index("insert")):
            if index != self.text.index("insert"):
                self.handle_restore_timer(c)
            else:
                self.editwin.text_frame.after(CHECK_DELAY, callme, callme)

        self.editwin.text_frame.after(CHECK_DELAY, callme, callme)

    def set_timeout_last(self):
        """The last highlight created will be removed after .5 sec"""
        # associate a counter with an event; only disable the "paren"
        # tag if the event is for the most recent timer.
        self.counter += 1
        self.editwin.text_frame.after(self.FLASH_DELAY,
                                      lambda self=self, c=self.counter: \
                                      self.handle_restore_timer(c))
class ParenMatch:
    menudefs = [('edit', [('Show surrounding parens', '<<flash-paren>>')])]
    STYLE = idleConf.GetOption('extensions',
                               'ParenMatch',
                               'style',
                               default='expression')
    FLASH_DELAY = idleConf.GetOption('extensions',
                                     'ParenMatch',
                                     'flash-delay',
                                     type='int',
                                     default=500)
    HILITE_CONFIG = idleConf.GetHighlight(idleConf.CurrentTheme(), 'hilite')
    BELL = idleConf.GetOption('extensions',
                              'ParenMatch',
                              'bell',
                              type='bool',
                              default=1)
    RESTORE_VIRTUAL_EVENT_NAME = '<<parenmatch-check-restore>>'
    RESTORE_SEQUENCES = ('<KeyPress>', '<ButtonPress>', '<Key-Return>',
                         '<Key-BackSpace>')

    def __init__(self, editwin):
        self.editwin = editwin
        self.text = editwin.text
        editwin.text.bind(self.RESTORE_VIRTUAL_EVENT_NAME, self.restore_event)
        self.counter = 0
        self.is_restore_active = 0
        self.set_style(self.STYLE)

    def activate_restore(self):
        if not self.is_restore_active:
            for seq in self.RESTORE_SEQUENCES:
                self.text.event_add(self.RESTORE_VIRTUAL_EVENT_NAME, seq)

            self.is_restore_active = True

    def deactivate_restore(self):
        if self.is_restore_active:
            for seq in self.RESTORE_SEQUENCES:
                self.text.event_delete(self.RESTORE_VIRTUAL_EVENT_NAME, seq)

            self.is_restore_active = False

    def set_style(self, style):
        self.STYLE = style
        if style == 'default':
            self.create_tag = self.create_tag_default
            self.set_timeout = self.set_timeout_last
        elif style == 'expression':
            self.create_tag = self.create_tag_expression
            self.set_timeout = self.set_timeout_none

    def flash_paren_event(self, event):
        indices = HyperParser(self.editwin,
                              'insert').get_surrounding_brackets()
        if indices is None:
            self.warn_mismatched()
            return
        else:
            self.activate_restore()
            self.create_tag(indices)
            self.set_timeout_last()
            return

    def paren_closed_event(self, event):
        closer = self.text.get('insert-1c')
        if closer not in _openers:
            return
        else:
            hp = HyperParser(self.editwin, 'insert-1c')
            if not hp.is_in_code():
                return
            indices = hp.get_surrounding_brackets(_openers[closer], True)
            if indices is None:
                self.warn_mismatched()
                return
            self.activate_restore()
            self.create_tag(indices)
            self.set_timeout()
            return

    def restore_event(self, event=None):
        self.text.tag_delete('paren')
        self.deactivate_restore()
        self.counter += 1

    def handle_restore_timer(self, timer_count):
        if timer_count == self.counter:
            self.restore_event()

    def warn_mismatched(self):
        if self.BELL:
            self.text.bell()

    def create_tag_default(self, indices):
        self.text.tag_add('paren', indices[0])
        self.text.tag_config('paren', self.HILITE_CONFIG)

    def create_tag_expression(self, indices):
        if self.text.get(indices[1]) in (')', ']', '}'):
            rightindex = indices[1] + '+1c'
        else:
            rightindex = indices[1]
        self.text.tag_add('paren', indices[0], rightindex)
        self.text.tag_config('paren', self.HILITE_CONFIG)

    def set_timeout_none(self):
        self.counter += 1

        def callme(callme,
                   self=self,
                   c=self.counter,
                   index=self.text.index('insert')):
            if index != self.text.index('insert'):
                self.handle_restore_timer(c)
            else:
                self.editwin.text_frame.after(CHECK_DELAY, callme, callme)

        self.editwin.text_frame.after(CHECK_DELAY, callme, callme)

    def set_timeout_last(self):
        self.counter += 1
        self.editwin.text_frame.after(
            self.FLASH_DELAY,
            lambda self=self, c=self.counter: self.handle_restore_timer(c))
    def show(self, tag_filter=None):

        if self.hidden == False:
            self.hide()
            return

        self.hidden = False

        # add a text widget, left of code text widget
        self.text_frame = text_frame = Frame(self.editwin.text_frame)
        self.vbar = vbar = Scrollbar(text_frame, name='vbar')
        vbar.pack(side=RIGHT, fill=Y)

        theme = idleConf.GetOption('main', 'Theme', 'name')
        normal_colors = idleConf.GetHighlight(theme, 'normal')
        text_options = {
            'padx': 5,
            'wrap': 'none',
            'cursor': 'arrow',
            'wrap': 'none',
            'foreground': normal_colors['foreground'],
            'background': normal_colors['background'],
        }

        self.textln = textln = Text(text_frame, **text_options)
        textln.pack(side='left', fill=BOTH, expand=YES)
        vbar['command'] = textln.yview
        textln['yscrollcommand'] = vbar.set

        # adjust font

        textln.config(
            font=(idleConf.GetOption('main', 'EditorWindow', 'font'),
                  idleConf.GetOption('main', 'EditorWindow', 'font-size')))

        textln.bind("<ButtonRelease>", self.focus_in_event)
        textln.bind("<Return>", self.enter_callback)
        textln.bind("<Escape>", self.escape_callback)
        textln.bind('<FocusOut>', self.focus_out, '+')

        # pass through keybindings for classdefbrowser
        keydefs = idleConf.GetExtensionBindings('CodeBrowser')
        for event, keylist in list(keydefs.items()):
            for k in keylist:

                def passthru(event, evName=event, text=self.text):
                    text.event_generate(evName)

                try:
                    textln.bind(k, passthru)
                except TclError as err:
                    print(err)
                    pass

        # start the line numbers
        self.per = per = Percolator(textln)
        self.color = ColorDelegator()

        self.per.insertfilter(self.color)

        self.line_delegator = LineDelegator()
        per.insertfilter(self.line_delegator)
        textln._insert = self.line_delegator.delegate.insert
        textln._delete = self.line_delegator.delegate.delete

        self.update_display(tag_filter)
        self.textfont = ""
        self.font_timer_event()

        self.nearest()

        text_frame.place(x=0, rely=1, relheight=1, relwidth=1, anchor=SW)
        text_frame.lift()
class ParenMatch:
    """Highlight matching parentheses
    
    There are three supported style of paren matching, based loosely
    on the Emacs options.  The style is select based on the
    HILITE_STYLE attribute; it can be changed used the set_style
    method.
    
    The supported styles are:
    
    default -- When a right paren is typed, highlight the matching
        left paren for 1/2 sec.
    
    expression -- When a right paren is typed, highlight the entire
        expression from the left paren to the right paren.
    
    TODO:
        - extend IDLE with configuration dialog to change options
        - implement rest of Emacs highlight styles (see below)
        - print mismatch warning in IDLE status window
    
    Note: In Emacs, there are several styles of highlight where the
    matching paren is highlighted whenever the cursor is immediately
    to the right of a right paren.  I don't know how to do that in Tk,
    so I haven't bothered.
    """
    menudefs = [('edit', [('Show surrounding parens', '<<flash-paren>>')])]
    STYLE = idleConf.GetOption('extensions',
                               'ParenMatch',
                               'style',
                               default='expression')
    FLASH_DELAY = idleConf.GetOption('extensions',
                                     'ParenMatch',
                                     'flash-delay',
                                     type='int',
                                     default=500)
    HILITE_CONFIG = idleConf.GetHighlight(idleConf.CurrentTheme(), 'hilite')
    BELL = idleConf.GetOption('extensions',
                              'ParenMatch',
                              'bell',
                              type='bool',
                              default=1)
    RESTORE_VIRTUAL_EVENT_NAME = '<<parenmatch-check-restore>>'
    RESTORE_SEQUENCES = ('<KeyPress>', '<ButtonPress>', '<Key-Return>',
                         '<Key-BackSpace>')

    def __init__(self, editwin):
        self.editwin = editwin
        self.text = editwin.text
        editwin.text.bind(self.RESTORE_VIRTUAL_EVENT_NAME, self.restore_event)
        self.counter = 0
        self.is_restore_active = 0
        self.set_style(self.STYLE)

    def activate_restore(self):
        if not self.is_restore_active:
            for seq in self.RESTORE_SEQUENCES:
                self.text.event_add(self.RESTORE_VIRTUAL_EVENT_NAME, seq)

            self.is_restore_active = True

    def deactivate_restore(self):
        if self.is_restore_active:
            for seq in self.RESTORE_SEQUENCES:
                self.text.event_delete(self.RESTORE_VIRTUAL_EVENT_NAME, seq)

            self.is_restore_active = False

    def set_style(self, style):
        self.STYLE = style
        if style == 'default':
            self.create_tag = self.create_tag_default
            self.set_timeout = self.set_timeout_last
        elif style == 'expression':
            self.create_tag = self.create_tag_expression
            self.set_timeout = self.set_timeout_none

    def flash_paren_event(self, event):
        indices = HyperParser(self.editwin,
                              'insert').get_surrounding_brackets()
        if indices is None:
            self.warn_mismatched()
            return
        else:
            self.activate_restore()
            self.create_tag(indices)
            self.set_timeout_last()
            return

    def paren_closed_event(self, event):
        closer = self.text.get('insert-1c')
        if closer not in _openers:
            return
        else:
            hp = HyperParser(self.editwin, 'insert-1c')
            if not hp.is_in_code():
                return
            indices = hp.get_surrounding_brackets(_openers[closer], True)
            if indices is None:
                self.warn_mismatched()
                return
            self.activate_restore()
            self.create_tag(indices)
            self.set_timeout()
            return

    def restore_event(self, event=None):
        self.text.tag_delete('paren')
        self.deactivate_restore()
        self.counter += 1

    def handle_restore_timer(self, timer_count):
        if timer_count == self.counter:
            self.restore_event()

    def warn_mismatched(self):
        if self.BELL:
            self.text.bell()

    def create_tag_default(self, indices):
        """Highlight the single paren that matches"""
        self.text.tag_add('paren', indices[0])
        self.text.tag_config('paren', self.HILITE_CONFIG)

    def create_tag_expression(self, indices):
        """Highlight the entire expression"""
        if self.text.get(indices[1]) in (')', ']', '}'):
            rightindex = indices[1] + '+1c'
        else:
            rightindex = indices[1]
        self.text.tag_add('paren', indices[0], rightindex)
        self.text.tag_config('paren', self.HILITE_CONFIG)

    def set_timeout_none(self):
        """Highlight will remain until user input turns it off
        or the insert has moved"""
        self.counter += 1

        def callme(callme,
                   self=self,
                   c=self.counter,
                   index=self.text.index('insert')):
            if index != self.text.index('insert'):
                self.handle_restore_timer(c)
            else:
                self.editwin.text_frame.after(CHECK_DELAY, callme, callme)

        self.editwin.text_frame.after(CHECK_DELAY, callme, callme)

    def set_timeout_last(self):
        """The last highlight created will be removed after .5 sec"""
        self.counter += 1
        self.editwin.text_frame.after(
            self.FLASH_DELAY,
            lambda self=self, c=self.counter: self.handle_restore_timer(c))