[Python-checkins] python/dist/src/Lib/idlelib CodeContext.py, NONE, 1.1 NEWS.txt, 1.33, 1.34 config-extensions.def, 1.12, 1.13

kbk at users.sourceforge.net kbk at users.sourceforge.net
Wed Apr 21 16:07:31 EDT 2004


Update of /cvsroot/python/python/dist/src/Lib/idlelib
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3845

Modified Files:
	NEWS.txt config-extensions.def 
Added Files:
	CodeContext.py 
Log Message:
- New Extension: CodeContext.  Provides block structuring hints for code
  which has scrolled above an edit window. Patch 936169 Noam Raphael.

A CodeContext.py
M NEWS.txt
M config-extensions.def


--- NEW FILE: CodeContext.py ---
"""CodeContext - Display the block context of code at top of edit window

Once code has scolled off the top of the screen, it can be difficult
to determine which block you are in.  This extension implements a pane
at the top of each IDLE edit window which provides block structure
hints.  These hints are the lines which contain the block opening
keywords, e.g. 'if', for the enclosing block.  The number of hint lines
is determined by the numlines variable in the CodeContext section of
config-extensions.def. Lines which do not open blocks are not shown in
the context hints pane.

"""
import Tkinter
from configHandler import idleConf
from PyShell import PyShell
from string import whitespace
import re

BLOCKOPENERS = dict([(x, None) for x in ("class", "def", "elif", "else",
                                         "except", "finally", "for", "if",
                                         "try", "while")])
INFINITY = 1 << 30
UPDATEINTERVAL = 100 #ms
FONTUPDATEINTERVAL = 1000 #ms

getspacesfirstword = lambda s, c=re.compile(r"^(\s*)(\w*)"): c.match(s).groups()

class CodeContext:
    menudefs = []
    numlines = idleConf.GetOption("extensions", "CodeContext",
                                  "numlines", type="int", default=3)
    bgcolor = idleConf.GetOption("extensions", "CodeContext",
                                 "bgcolor", type="str", default="LightGray")
    fgcolor = idleConf.GetOption("extensions", "CodeContext",
                                 "fgcolor", type="str", default="Black")
    def __init__(self, editwin):
        if isinstance(editwin, PyShell):
            return
        self.editwin = editwin
        self.text = editwin.text
        self.textfont = self.text["font"]
        self.label = Tkinter.Label(self.editwin.top,
                                   text="\n" * (self.numlines - 1),
                                   anchor="w", justify="left",
                                   font=self.textfont,
                                   bg=self.bgcolor, fg=self.fgcolor,
                                   relief="sunken",
                                   width=1, # Don't request more than we get
                                   )
        self.label.pack(side="top", fill="x", expand=0,
                        after=self.editwin.status_bar)
        # Dummy line, which starts the "block" of the whole document:
        self.info = list(self.interesting_lines(1))
        self.lastfirstline = 1
        # Start two update cycles, one for context lines, one for font changes.
        self.text.after(UPDATEINTERVAL, self.timer_event)
        self.text.after(FONTUPDATEINTERVAL, self.font_timer_event)

    def get_line_info(self, linenum):
        """Get the line indent value, text, and any block start keyword

        If the line does not start a block, the keyword value is False.
        The indentation of empty lines (or comment lines) is INFINITY.
        There is a dummy block start, with indentation -1 and text "".

        Return the indent level, text (including leading whitespace),
        and the block opening keyword.

        """
        if linenum == 0:
            return -1, "", True
        text = self.text.get("%d.0" % linenum, "%d.end" % linenum)
        spaces, firstword = getspacesfirstword(text)
        opener = firstword in BLOCKOPENERS and firstword
        if len(text) == len(spaces) or text[len(spaces)] == '#':
            indent = INFINITY
        else:
            indent = len(spaces)
        return indent, text, opener

    def interesting_lines(self, firstline):
        """Generator which yields context lines, starting at firstline."""
        # The indentation level we are currently in:
        lastindent = INFINITY
        # For a line to be interesting, it must begin with a block opening
        # keyword, and have less indentation than lastindent.
        for line_index in xrange(firstline, -1, -1):
            indent, text, opener = self.get_line_info(line_index)
            if indent < lastindent:
                lastindent = indent
                if opener == "else" or "elif":
                    # We also show the if statement
                    lastindent += 1
                if opener and line_index < firstline:
                    yield line_index, text

    def update_label(self):
        firstline = int(self.text.index("@0,0").split('.')[0])
        if self.lastfirstline == firstline:
            return
        self.lastfirstline = firstline
        tmpstack = []
        for line_index, text in self.interesting_lines(firstline):
            # Remove irrelevant self.info items, and when we reach a relevant
            # item (which must happen because of the dummy element), break.
            while self.info[-1][0] > line_index:
                del self.info[-1]
            if self.info[-1][0] == line_index:
                break
            # Add the block starting line info to tmpstack
            tmpstack.append((line_index, text))
        while tmpstack:
            self.info.append(tmpstack.pop())
        lines = [""] * max(0, self.numlines - len(self.info)) + \
                [x[1] for x in self.info[-self.numlines:]]
        self.label["text"] = '\n'.join(lines)

    def timer_event(self):
        self.update_label()
        self.text.after(UPDATEINTERVAL, self.timer_event)

    def font_timer_event(self):
        newtextfont = self.text["font"]
        if newtextfont != self.textfont:
            self.textfont = newtextfont
            self.label["font"] = self.textfont
        self.text.after(FONTUPDATEINTERVAL, self.font_timer_event)

Index: NEWS.txt
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/idlelib/NEWS.txt,v
retrieving revision 1.33
retrieving revision 1.34
diff -C2 -d -r1.33 -r1.34
*** NEWS.txt	11 Apr 2004 03:16:07 -0000	1.33
--- NEWS.txt	21 Apr 2004 20:06:22 -0000	1.34
***************
*** 4,7 ****
--- 4,10 ----
  *Release date: XX-XXX-2004*
  
+ - New Extension: CodeContext.  Provides block structuring hints for code
+   which has scrolled above an edit window. Patch 936169 Noam Raphael.
+ 
  - If nulls somehow got into the strings in recent-files.lst
    EditorWindow.update_recent_files_list() was failing.  Python Bug 931336.

Index: config-extensions.def
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/idlelib/config-extensions.def,v
retrieving revision 1.12
retrieving revision 1.13
diff -C2 -d -r1.12 -r1.13
*** config-extensions.def	16 Jul 2003 03:10:43 -0000	1.12
--- config-extensions.def	21 Apr 2004 20:06:26 -0000	1.13
***************
*** 4,8 ****
  # Each extension must have at least one section, named after the extension
  # module. This section must contain an 'enable' item (=1 to enable the
! # extension, =0 to disable it) and also contains any other general
  # configuration items for the extension. Each extension may also define up to
  # two optional sections named ExtensionName_bindings and
--- 4,8 ----
  # Each extension must have at least one section, named after the extension
  # module. This section must contain an 'enable' item (=1 to enable the
! # extension, =0 to disable it) and also contain any other general
  # configuration items for the extension. Each extension may also define up to
  # two optional sections named ExtensionName_bindings and
***************
*** 13,20 ****
  
  # Currently it is necessary to manually modify this file to change extension
! # key bindings.  Note: If a keybinding is already in use when the extension is
  # loaded, the extension's virtual event's keybinding will be set to ''.
  
! # See config-keys.def for notes on specifying keys.
  
  [FormatParagraph]
--- 13,25 ----
  
  # Currently it is necessary to manually modify this file to change extension
! # key bindings and default values. To customize, create
! # ~/.idlerc/config-extensions.cfg and append the appropriate customized
! # section(s).  Those sections will override the defaults in this file.
! 
! # Note: If a keybinding is already in use when the extension is
  # loaded, the extension's virtual event's keybinding will be set to ''.
  
! # See config-keys.def for notes on specifying keys and extend.txt for
! # information on creating IDLE extensions.
  
  [FormatParagraph]
***************
*** 57,58 ****
--- 62,69 ----
  flash-open-paren=<KeyRelease-parenright> <KeyRelease-bracketright> <KeyRelease-braceright>
  check-restore=<KeyPress>
+ 
+ [CodeContext]
+ enable=1
+ numlines=3
+ bgcolor=LightGray
+ fgcolor=Black




More information about the Python-checkins mailing list