Example #1
0
 def _initialize_config(self, Theme):
     """Fix idleConf.GetHighlight method for different Python releases."""
     config = {
         'padx': 5,
         'wrap': 'word',
         'undo': 'True',
         'width': idleConf.GetOption('main', 'EditorWindow', 'width'),
         'height': idleConf.GetOption('main', 'EditorWindow', 'height'),
     }
     if PYTHON_VERSION >= (3, 7, 4):  # T241216
         config['foreground'] = idleConf.GetHighlight(
             Theme, 'normal')['foreground']
         config['background'] = idleConf.GetHighlight(
             Theme, 'normal')['background']
         config['highlightcolor'] = idleConf.GetHighlight(
             Theme, 'hilite')['foreground']
         config['highlightbackground'] = idleConf.GetHighlight(
             Theme, 'hilite')['background']
         config['insertbackground'] = idleConf.GetHighlight(
             Theme, 'cursor')['foreground']
     else:
         config['foreground'] = idleConf.GetHighlight(
             Theme, 'normal', fgBg='fg')
         config['background'] = idleConf.GetHighlight(
             Theme, 'normal', fgBg='bg')
         config['highlightcolor'] = idleConf.GetHighlight(
             Theme, 'hilite', fgBg='fg')
         config['highlightbackground'] = idleConf.GetHighlight(
             Theme, 'hilite', fgBg='bg')
         config['insertbackground'] = idleConf.GetHighlight(
             Theme, 'cursor', fgBg='fg')
     return config
Example #2
0
    def __init__(self, master=None, **kwargs):
        """
        Initializer.

        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)
Example #3
0
 def drawtext(self):
     textx = self.x+20-1
     texty = self.y-4
     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:
         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.CurrentTheme()
     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.label.bind("<Control-1>", self.select_more)
     self.label.bind("<3>", self.execute_file)
     self.text_id = id
Example #4
0
 def update_colors(self):
     """Update the sidebar text colors, usually after config changes."""
     linenumbers_colors = idleConf.GetHighlight(idleConf.CurrentTheme(),
                                                'linenumber')
     prompt_colors = idleConf.GetHighlight(idleConf.CurrentTheme(),
                                           'console')
     self._update_colors(foreground=prompt_colors['foreground'],
                         background=linenumbers_colors['background'])
Example #5
0
    def update_highlight_colors(self):
        if self.context is not None:
            colors = idleConf.GetHighlight(idleConf.CurrentTheme(), 'context')
            self.context['background'] = colors['background']
            self.context['foreground'] = colors['foreground']

        if self.cell00 is not None:
            line_number_colors = idleConf.GetHighlight(idleConf.CurrentTheme(),
                                                       'linenumber')
            self.cell00.config(bg=line_number_colors['background'])
Example #6
0
    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)
Example #7
0
 def update_colors(self):
     """Update the sidebar text colors, usually after config changes."""
     linenumbers_colors = idleConf.GetHighlight(idleConf.CurrentTheme(),
                                                'linenumber')
     prompt_colors = idleConf.GetHighlight(idleConf.CurrentTheme(),
                                           'console')
     foreground = prompt_colors['foreground']
     background = linenumbers_colors['background']
     self.colors = (foreground, background)
     self.canvas.configure(background=background)
     self.change_callback()
Example #8
0
 def LoadTagDefs(self):
     ColorDelegator.LoadTagDefs(self)
     theme = idleConf.CurrentTheme()
     self.tagdefs.update({
         'stdin': {
             'background': None,
             'foreground': None
         },
         'stdout': idleConf.GetHighlight(theme, 'stdout'),
         'stderr': idleConf.GetHighlight(theme, 'stderr'),
         'console': idleConf.GetHighlight(theme, 'console')
     })
Example #9
0
def color_config(text):
    """Set color opitons of Text widget.

    Should be called whenever ColorDelegator is called.
    """
    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'],
                inactiveselectbackground=select_colors['background'])
Example #10
0
    def init(self):
        "Create browser tkinter widgets, including the tree."
        global file_open
        root = self.master
        flist = (pyshell.flist if not (self._htest or self._utest) else
                 pyshell.PyShellFileList(root))
        file_open = flist.open
        pyclbr._modules.clear()

        # create top
        self.top = top = ListedToplevel(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" %
                         (root.winfo_rootx(), root.winfo_rooty() + 200))
        self.settitle()
        top.focus_set()

        # create scrolled canvas
        theme = idleConf.CurrentTheme()
        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)
        if not self._utest:
            node.update()
            node.expand()
 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.CurrentTheme()
     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()
Example #12
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'],
        inactiveselectbackground=select_colors['background'],  # new in 8.5
    )
Example #13
0
 def reload(cls):
     "Load class variables from config."
     cls.context_depth = idleConf.GetOption("extensions",
                                            "CodeContext",
                                            "maxlines",
                                            type="int",
                                            default=15)
     cls.colors = idleConf.GetHighlight(idleConf.CurrentTheme(), 'context')
Example #14
0
    def toggle_code_context_event(self, event=None):
        """Toggle code context display.

        If self.context doesn't exist, create it to match the size of the editor
        window text (toggle on).  If it does exist, destroy it (toggle off).
        Return 'break' to complete the processing of the binding.
        """
        if self.context is None:
            # Calculate the border width and horizontal padding required to
            # align the context with the text in the main Text widget.
            #
            # All values are passed through getint(), since some
            # values may be pixel objects, which can't simply be added to ints.
            widgets = self.editwin.text, self.editwin.text_frame
            # Calculate the required horizontal padding and border width.
            padx = 0
            border = 0
            for widget in widgets:
                info = (widget.grid_info()
                        if widget is self.editwin.text else widget.pack_info())
                padx += widget.tk.getint(info['padx'])
                padx += widget.tk.getint(widget.cget('padx'))
                border += widget.tk.getint(widget.cget('border'))
            context = self.context = Text(
                self.editwin.text_frame,
                height=1,
                width=1,  # Don't request more than we get.
                highlightthickness=0,
                padx=padx,
                border=border,
                relief=SUNKEN,
                state='disabled')
            self.update_font()
            self.update_highlight_colors()
            context.bind('<ButtonRelease-1>', self.jumptoline)
            # Get the current context and initiate the recurring update event.
            self.timer_event()
            # Grid the context widget above the text widget.
            context.grid(row=0, column=1, sticky=NSEW)

            line_number_colors = idleConf.GetHighlight(idleConf.CurrentTheme(),
                                                       'linenumber')
            self.cell00 = Frame(self.editwin.text_frame,
                                bg=line_number_colors['background'])
            self.cell00.grid(row=0, column=0, sticky=NSEW)
            menu_status = 'Hide'
        else:
            self.context.destroy()
            self.context = None
            self.cell00.destroy()
            self.cell00 = None
            self.text.after_cancel(self.t1)
            self._reset()
            menu_status = 'Show'
        self.editwin.update_menu_label(menu='options',
                                       index='*ode*ontext',
                                       label=f'{menu_status} Code Context')
        return "break"
Example #15
0
 def LoadTagDefs(self):
     "Create dictionary of tag names to text colors."
     theme = idleConf.CurrentTheme()
     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"),
         # "hit" is used by ReplaceDialog to mark matches. It shouldn't be changed by Colorizer, but
         # that currently isn't technically possible. This should be moved elsewhere in the future
         # when fixing the "hit" tag's visibility, or when the replace dialog is replaced with a
         # non-modal alternative.
         "hit": idleConf.GetHighlight(theme, "hit"),
     }
     if DEBUG: print('tagdefs', self.tagdefs)
 def reload(cls):
     cls.STYLE = idleConf.GetOption(
         'extensions','ParenMatch','style', default='opener')
     cls.FLASH_DELAY = idleConf.GetOption(
             'extensions','ParenMatch','flash-delay', type='int',default=500)
     cls.BELL = idleConf.GetOption(
             'extensions','ParenMatch','bell', type='bool', default=1)
     cls.HILITE_CONFIG = idleConf.GetHighlight(idleConf.CurrentTheme(),
                                               'hilite')
Example #17
0
 def color_breakpoint_text(self, color=True):
     """Turn colorizing of breakpoint text on or off"""
     if self.io is None:
         return
     if color:
         theme = idleConf.CurrentTheme()
         cfg = idleConf.GetHighlight(theme, 'break')
     else:
         cfg = {'foreground': '', 'background': ''}
     self.text.tag_config('BREAK', cfg)
Example #18
0
def color_config(text):
    """Set color options of Text widget.

    If ColorDelegator is used, this should be called first.
    """
    # Called from htest, TextFrame, Editor, and Turtledemo.
    # 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'],
        inactiveselectbackground=select_colors['background'],  # new in 8.5
    )
Example #19
0
 def update_colors(self):
     """Update the sidebar text colors, usually after config changes."""
     colors = idleConf.GetHighlight(idleConf.CurrentTheme(), 'linenumber')
     foreground = colors['foreground']
     background = colors['background']
     self.sidebar_text.config(
         fg=foreground,
         bg=background,
         selectforeground=foreground,
         selectbackground=background,
         inactiveselectbackground=background,
     )
Example #20
0
    def create_linenumbers(self):
        """ Create the widget for displaying line numbers. """
        colors = idleConf.GetHighlight(idleConf.CurrentTheme(), 'stdout')
        editwin = self.editwin
        text = self.text
        text_frame = editwin.text_frame
        self.textln = textln = Text(text_frame,
                                    bg=colors['background'],
                                    fg=colors['foreground'],
                                    width=self.width,
                                    height=1,
                                    wrap=NONE,
                                    highlightthickness=0)

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

        textln.bind("<FocusIn>", self.focus_in_event)
        textln.bind('<Button-1>', self.button_ignore)
        textln.bind('<Button-2>', self.button_ignore)
        textln.bind('<Button-3>', self.button_ignore)
        textln.bind('<B1-Motion>', self.button_ignore)
        textln.bind('<B2-Motion>', self.button_ignore)
        textln.bind('<B3-Motion>', self.button_ignore)

        textln.bind("<Button-4>", self.button4)
        textln.bind("<Button-5>", self.button5)

        textln.tag_config('LINE', justify=RIGHT)
        textln.insert(END, '1')
        textln.tag_add('LINE', '1.0', END)

        # start the line numbers
        self.per = per = Percolator(textln)
        self.line_delegator = LineDelegator()
        per.insertfilter(self.line_delegator)
        textln._insert = self.line_delegator.delegate.insert
        textln._delete = self.line_delegator.delegate.delete

        lines = LineNumberDelegator(self)
        if _AFTER_UNDO:
            # idlelib.percolator's .insertfilter should have an
            # "after=" argument
            lines.setdelegate(editwin.undo.delegate)
            editwin.undo.setdelegate(lines)
        else:
            editwin.per.insertfilter(lines)

        editwin.vbar['command'] = self.vbar_split
        editwin.text['yscrollcommand'] = self.yscroll_split
Example #21
0
    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)
Example #22
0
 def remote_stack_viewer(self):
     from idlelib import debugobj_r
     oid = self.rpcclt.remotequeue('exec', 'stackviewer', ('flist', ), {})
     if oid is None:
         self.tkconsole.root.bell()
         return
     item = debugobj_r.StubObjectTreeItem(self.rpcclt, oid)
     from idlelib.tree import ScrolledCanvas, TreeNode
     top = Toplevel(self.tkconsole.root)
     theme = idleConf.CurrentTheme()
     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()
Example #23
0
 def drawtext(self):
     textx = self.x + 20 - 1
     texty = self.y - 4
     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:
         self.label
     except AttributeError:
         self.label = Label(self.canvas, text=text, bd=0, padx=2, pady=2)
     theme = idleConf.CurrentTheme()
     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
Example #24
0
    def LoadTagDefs(self):
        theme = idleConf.CurrentTheme()
        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)
Example #25
0
 def LoadTagDefs(self):
     theme = idleConf.CurrentTheme()
     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'),
         'hit': idleConf.GetHighlight(theme, 'hit')
     }
     if DEBUG:
         print('tagdefs', self.tagdefs)
Example #26
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)
     if self._htest:
         top.geometry(
             '+%d+%d' %
             (flist.root.winfo_rootx(), flist.root.winfo_rooty() + 200))
     self.settitle()
     top.focus_set()
     theme = idleConf.CurrentTheme()
     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()
Example #27
0
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.bell = self.text.bell if self.BELL else lambda: None
        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.bell()
            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.bell()
            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()

    # 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))
Example #28
0
 def update_highlight_colors(self):
     if self.context is not None:
         colors = idleConf.GetHighlight(idleConf.CurrentTheme(), 'context')
         self.context['background'] = colors['background']
         self.context['foreground'] = colors['foreground']
Example #29
0
 def update_colors(self):
     """Update the sidebar text colors, usually after config changes."""
     colors = idleConf.GetHighlight(idleConf.CurrentTheme(), 'normal')
     self._update_colors(foreground=colors['foreground'],
                         background=colors['background'])
Example #30
0
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.bell = self.text.bell if self.BELL else lambda: None
        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.bell()
            return
        self.activate_restore()
        self.create_tag(indices)
        self.set_timeout_last()

    def paren_closed_event(self, event):
        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.bell()
            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

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

    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))